expertenaustausch > comp.os.* > comp.os.unix.programming

Jan Kandziora (12.01.2009, 15:33)
Hallo,

ich steh' vermutlich einfach auf dem Schlauch. Folgende Umstände:

Für einen Touchscreen existiert ein selbstgemachtes XInput-Treibermodul. Zur
Kalibrierung dient ein selbstgemachtes Programm, das genau wie der Treiber
die Rohdaten vom per RS232 angebundenen Controller lesen muss.

Soweit, so gut. Nun kann aber natürlich immer nur ein Prozess die serielle
Schnittstelle kontrollieren. Das ist während der ganzen Zeit der Treiber.
Für das Kalibrierprogramm würde es jedoch auch ausreichen, nur "mitlesen"
zu können. Daher will ich eine Named Pipe einrichten, in die der Treiber
die vom Controller gelesenen Daten einfach nur abkippt. Das
Kalibrierprogramm soll sie dort abholen.

Nun das Problem: Wie erreiche ich zuverlässig, dass beim Schließen der Named
Pipe durch das Kalibrierprogramm der Treiber *kein SIGPIPE* erhält? Ich
möchte das Signal ungern einfach ignorieren, da der Treiber ja nur ein
einzelnes Modul von X ist und ich nicht weiß, wie die anderen Programmteile
auf das SIGPIPE bzw. auf das Fehlen von SIGPIPE reagieren.

Ich habe schon versucht, mittels select() herauszufinden, ob der
Dateideskriptor geschrieben werden kann. select() liefert jedoch
grundsätzlich 0 zurück, wenn ich es auf die zuvor erfolgreich geöffnete
Named Pipe anwende, egal ob ein anderer Prozess daran horcht oder nicht.

Funktionierende Testcode mit signal():

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>

const char *buf = "BLA";

#define FD_INVALID -1

int main(void)
{
int fd=FD_INVALID;
ssize_t count;

signal(SIGPIPE, SIG_IGN);

while (1)
{
if (fd == FD_INVALID)
{
if ((fd=open("xfifo", O_WRONLY|O_NONBLOCK)) < 0)
{
if (errno == ENXIO) goto end;

perror("open");
exit(EXIT_FAILURE);
}
}

if ((count=write(fd, buf, sizeof(buf)-1)) < 0)
{
if (errno == EPIPE)
{
close(fd);
fd=FD_INVALID;
}
else
{
perror("write");
exit(EXIT_FAILURE);
}
}

end:
fprintf(stderr,".");
usleep(100000);
}

return 0;
}

Die Gegenseite ist einfach "cat xfifo"

Vielleicht hat ja jemand von euch eine Idee.

Mit freundlichem Gruß

Jan
Rainer Weikusat (12.01.2009, 15:46)
Jan Kandziora <jjj> writes:

[...]

> Daher will ich eine Named Pipe einrichten, in die der Treiber
> die vom Controller gelesenen Daten einfach nur abkippt. Das
> Kalibrierprogramm soll sie dort abholen.
> Nun das Problem: Wie erreiche ich zuverlässig, dass beim Schließen der Named
> Pipe durch das Kalibrierprogramm der Treiber *kein SIGPIPE* erhält? Ich
> möchte das Signal ungern einfach ignorieren, da der Treiber ja nur ein
> einzelnes Modul von X ist und ich nicht weiß, wie die anderen Programmteile
> auf das SIGPIPE bzw. auf das Fehlen von SIGPIPE reagieren.


Eine (Linux-)Alternativmogelichkeit waere, eine PF_UNIX stream socket zu
benutzen und Daten mit 'send' und MSG_NOSIGNAL als flag zu
schreiben. Man koennte wohl auch einen Hilfs-Prozess benutzen, dem der
Treiber die Daten via pipe uebertraegt, und der selber die 'named
pipe' fuettert, wobei er SIGPIPE so behandeln koennte, wie es ihm
passen wuerde. Allerdings gibt es (meines Wissens nach) keine
zuverlaessige Moeglichkeit, ein unzeitiges Ableben dieses
Hilfsprozesses vor einem SIGPIPE zu erkennen. Schliesslich koennte man
die Daten auch noch einfach an eine PF_UNIX datagram socket mit einer
'bekannten' Addresse schicken (sendto). Sollte die im Moment niemand haben
wollen, gaebe es 'nur' einen Fehler, den man vollstaendig ignorieren
kann.
Jan Kandziora (12.01.2009, 16:06)
Rainer Weikusat schrieb:
> Eine (Linux-)Alternativmogelichkeit waere, eine PF_UNIX stream socket zu
> benutzen und Daten mit 'send' und MSG_NOSIGNAL als flag zu
> schreiben.
> Schliesslich koennte man
> die Daten auch noch einfach an eine PF_UNIX datagram socket mit einer
> 'bekannten' Addresse schicken (sendto). Sollte die im Moment niemand haben
> wollen, gaebe es 'nur' einen Fehler, den man vollstaendig ignorieren
> kann.

Daran hatte ich auch schon gedacht, nur ist das Kalibrierprogramm ein
Tcl-Skript, und Tcl kann wohl leider nur PF_INET-Sockets. Hmm, vielleicht
mache ich das einfach via PF_INET, aber das ist viel häßlicher als ich es
wollte...

Oder, Moment:

> Man koennte wohl auch einen Hilfs-Prozess benutzen, dem der
> Treiber die Daten via pipe uebertraegt, und der selber die 'named
> pipe' fuettert, wobei er SIGPIPE so behandeln koennte, wie es ihm
> passen wuerde. Allerdings gibt es (meines Wissens nach) keine
> zuverlaessige Moeglichkeit, ein unzeitiges Ableben dieses
> Hilfsprozesses vor einem SIGPIPE zu erkennen.

Hmm, in dem Fall würde ich wohl lieber das Kalibierprogramm weiterlaufen
lassen und einfach dessen Kalibrierfenster (Fullscreen) nicht anzeigen. Das
geht natürlich auch. Der Tcl-Interpreter ist ohnehin noch von anderen
Teilen des Systems geladen, das frisst also nur ein paar kB für das Skript.
Ist natürlich doof, wenn man es später mal in einer anderen Umgebung
betreiben will.

Gibt es sonst noch Möglichkeiten?

Mit freundlichem Gruß

Jan
Jan Kandziora (12.01.2009, 16:52)
Jan Kandziora schrieb:
> Gibt es sonst noch Möglichkeiten?

Ich habe die Named Pipe jetzt mal spaßeshalber mit O_RDWR statt O_WRONLY
eröffnet, weil SIGPIPE ja angeblich nur dann kommt, wenn es keine lesenden
Prozesse gibt. So klappt es nun auch *ohne* SIGPIPE abzufangen.

Ist das ein Schmutzeffekt oder kann man sich darauf verlassen, dass das
funktioniert?

Mit freundlichem Gruß

Jan
Rainer Weikusat (12.01.2009, 16:57)
Jan Kandziora <jjj> writes:
> Jan Kandziora schrieb:
> Ich habe die Named Pipe jetzt mal spaßeshalber mit O_RDWR statt O_WRONLY
> eröffnet, weil SIGPIPE ja angeblich nur dann kommt, wenn es keine lesenden
> Prozesse gibt. So klappt es nun auch *ohne* SIGPIPE abzufangen.
> Ist das ein Schmutzeffekt oder kann man sich darauf verlassen, dass das
> funktioniert?


Das kommt darauf an, was man unter 'sich darauf verlassen'
versteht. Lt. UNIX(*)-Standard ist das Verhalten fuer einen solchen
Fall undefiniert. Linux hat es (soweit mir bekannt) 'schon immer' als
dokumentiertes feature (=> fifo(4)).
Jan Kandziora (12.01.2009, 18:00)
Rainer Weikusat schrieb:
>> Ist das ein Schmutzeffekt oder kann man sich darauf verlassen, dass das
>> funktioniert?

> Das kommt darauf an, was man unter 'sich darauf verlassen'
> versteht. Lt. UNIX(*)-Standard ist das Verhalten fuer einen solchen
> Fall undefiniert. Linux hat es (soweit mir bekannt) 'schon immer' als
> dokumentiertes feature (=> fifo(4)).

Guter Hinweis, hatte ich doch glatt überlesen. Dann mache ich das erstmal
so.

Also im Hinterkopf behalten (==aufschreiben), falls das ganze später mal
portiert werden muss. Und Danke für deine alternativen Ideen.

Mit freundlichem Gruß

Jan
Markus Raab (12.01.2009, 20:17)
Jan Kandziora wrote:
> Gibt es sonst noch Möglichkeiten?


Du könntest genau an der Stelle wo du das Signal abdrehen willst ein
atomic_t setzen und im sighandler dieses abfragen, siehe z.b.:


Damit könntest du beim schreiben das SIGPIPE unterdrücken ohne das restliche
Programm zu beeinflussen.

Wahrscheinlich ist die Idee zu trivial und löst das Problem nicht ganz,
konnte mir den ganzen Thread leider nicht durchlesen.

mfg Markus
Rainer Weikusat (13.01.2009, 10:29)
Markus Raab <usenet> writes:
> Jan Kandziora wrote:
>> Gibt es sonst noch Möglichkeiten?

> Du könntest genau an der Stelle wo du das Signal abdrehen willst ein
> atomic_t setzen und im sighandler dieses abfragen, siehe z.b.:
>


Der Typ heisst 'sig_atomic_t'.
Ähnliche Themen