schönen Freitag miteinander!
Programm1 redet normalerweise per /dev/ttyUSBx mit einer Hardware. Jetzt
soll Programm2 diese Hardware simulieren. Prog1 kann einen symlink (z.B.
"/tmp/hardware") für die Schnittstelle benutzen, dann sieht es sehr
einfach aus:
1
pts=open("/dev/ptmx",O_RDONLY);
2
path=ptsname(pts);
3
grantpt(pts);
4
unlockpt(pts);
5
symlink(path,"/tmp/hardware");
so kann Prog1 sein normales open("/tmp/hardware") machen.
Jetzt muss man "nur noch" dafür sorgen, dass der Link entfernt wird,
wenn Prog2 beendet wird. atexit() funktioniert dafür nur meistens. Ja,
Prog1 könnte das pty in /proc/$(pidof Prog2)/fd/ suchen, aber wie macht
man das normalerweise?
Den Symlink könnte man früher löschen - der kann weg sobald Prog1 sein
open() call ausgeführt hat.
Ob das in der Praxis funktioniert ist zweifelhaft.
TTYUSB kennt noch die für UART/RS232 typischen Schnittstellenparameter
und deren Syscalls. Die funktionieren auf Dateien oder named Pipes
nicht.
Jim M. schrieb:> Den Symlink könnte man früher löschen - der kann weg sobald Prog1 sein> open() call ausgeführt hat.
Gute Idee, danke!
> Ob das in der Praxis funktioniert ist zweifelhaft.
Meinst du das Link-löschen oder die Schnittstellenparameter? Es bleibt
ein kleines Restrisiko: Prog2 startet, Prog1 aber nicht, Prog2 erwischt
einen Segfault, Prog1 startet und findet den kaputten Link. Irgendwas
ist immer; hauptsächlich wundert mich, dass es dafür scheinbar keinen
Mechanismus gibt. So in der Art, wie z.B. Speicher garantiert
freigegeben wird, egal, wie das Programm beendet wird.
Die ioctl() Syscalls funktionieren, praktisch als NOP. Nur das Timing
ist natürlich völlig anders, dagegen reicht mir in diesem speziellen
Fall ein usleep().
Jim M. schrieb:> Den Symlink könnte man früher löschen - der kann weg sobald Prog1 sein> open() call ausgeführt hat.>> Ob das in der Praxis funktioniert ist zweifelhaft.
Das gilt eigentlich für alle was über Filedescriptoren angesprochen
wird. Mann kann das Objekt (File, (Sym)Link, Gerät, ...) auf
Filesystem-Ebene hinterrücks löschen. Das Objekt bleibt trotzdem so
lange erhalten bis der letzte Filedescriptor drauf zu gemacht wird.
Eine uralte, schon zu UNIX-Zeiten beliebte Technik um zum Beispiel
temporäre Dateien automatisch zu löschen wenn der Prozess endet. Datei
öffnen, Filedescriptor brav behalte, Datei im Filesystem löschen, frisch
und fröhlich mit der nun unsichtbaren Datei über den Filedescriptor
arbeiten. Der Prozess endet und Linux räumt erst dann die Datei ab.
Hannes J. schrieb:> Eine uralte, schon zu UNIX-Zeiten beliebte Technik um zum Beispiel> temporäre Dateien automatisch zu löschen wenn der Prozess endet. Datei> öffnen, Filedescriptor brav behalte, Datei im Filesystem löschen, frisch> und fröhlich mit der nun unsichtbaren Datei über den Filedescriptor> arbeiten. Der Prozess endet und Linux räumt erst dann die Datei ab.
Oder, wenn der Prozess weiter und weiter auf /tmp schreibt, gibt es eine
panic und der Systemverwalter steht in Deinem Buero... Der schoene neue
Convex-Supercomputer sollte fuer etwas gut sein...
> Ja, Prog1 könnte das pty in /proc/$(pidof Prog2)/fd/ suchen, aber wie macht> man das normalerweise?
Da würde es aber doch nur das ptm, nicht das pts, finden.
Falls Programm 2 von Program 1 gestartet wird, könnte man Program 2 ein
FD von Program 1 übergeben. Man könnte das pts öffnen und als FD 0,1,2
(stdin, stdout, stderr) setzen. Oder man könnte eine environment
Variable oder einen Parameter setzen, und ihm so mitteilen, wo das pts
zu finden ist.
(Mit /proc/self/fd/N kann man für FDs auch einen Dateipfad angeben. Aber
ein open da drauf gibt eine neue File Description (nicht nur einen neuen
File Descriptor). Beim pts kein Problem, bei (gelöschten) Dateien auch
nicht. Aber z.B. bei einem fd auf ein ptm von /dev/ptmx bekäme man ein
neues pts).
Daniel A. schrieb:>> Ja, Prog1 könnte das pty in /proc/$(pidof Prog2)/fd/ suchen, aber wie macht>> man das normalerweise?>> Da würde es aber doch nur das ptm, nicht das pts, finden.
Stimmt auch wieder. Wenn man einem vorhandenen Programm eine Hardware
vortäuschen will, kommt sowas ja sowieso nicht in Frage, da ist ein
symlink vernünftig. Und im Normalfall, wenn beide Programme
zusammenarbeiten, funktioniert ja alles automatisch richtig. Dankeschön!
Thomas W. schrieb:> Oder, wenn der Prozess weiter und weiter auf /tmp schreibt, gibt es eine> panic und der Systemverwalter steht in Deinem Buero...
Systemverwalter lernt was über Quotas.
Im Prinzip sollte kein Programm in einen segfault laufen, das wäre
eigentlich das Maß der Dinge.
Man kann ansonsten alle anderen Sigs abfangen und abhandeln, dann wäre
jede andere Möglichkeit den Symlink doch zu löschen abgedeckt.
Einen kritischen Segfault kann man verhindern indem man es richtig
programmiert. man könnte auch bei jedem start des "Programm2" einen
vorhandenen symlink löschen. Somit gäbe es keinen unlösbaren Worst case.
Philipp K. schrieb:> Man kann ansonsten alle anderen Sigs abfangen und abhandeln, dann wäre> jede andere Möglichkeit den Symlink doch zu löschen abgedeckt.
SIGSEGV kann man abfangen, zumindest auf linux. Aber es gibt andere
Signale, die man nicht abfangen kann. z.B. SIGKILL.
Wenn du auf beide Codes (Anwendung und Simulator) vollen Zugriff hast,
könnte man auch auf unterster Ebene eine alternative Kommunikation
einbauen, speziell für den Simu-Fall, z.B. per IP oder IPC oder schlicht
ein File ...
Frank E. schrieb:> Wenn du auf beide Codes (Anwendung und Simulator) vollen Zugriff hast,> könnte man auch auf unterster Ebene eine alternative Kommunikation...
hätte ich sogar, aber das geht in die falsche Richtung. So richtig
"minimal-invasiv" ist nur ein Kabel und eine echte serielle
Schnittstelle; dann stimmt auch das Timing ganz von alleine.
Kann man als Pfad, über fixe FDs (z.B. stdin/stdout), oder per erstem
freien FD + ne env variable, übergeben.
So braucht man keine Symlinks, und es bleibt nachher auch nichts zurück.