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

Edzard Egberts (03.02.2016, 10:48)
Ich habe ein Programm, das über Sockets TCP/IP-Verbindungen unterhält.
Wenn ich das Programm im Debugger laufen lasse, erhalte ich gelegentlich
(z.B. Herumbasteln an der Firewall) folgende Meldung:

Program received signal SIGPIPE, Broken pipe.
0xb805df8e in send () from /lib/libpthread.so.0

Der Debugger stoppt dann und läuft mit "Continue" weiter, was mir sagt,
dass ich dieses Signal behandeln sollte, nämlich mit signal(SIGPIPE,
SIG_IGN) abstellen. Im Release wird das Signal scheinbar per default
nicht bearbeitet? Ist das richtig, oder kann das im Release das Programm
beenden?

Ich habe dazu noch gelesen, dass man Signale nicht ignorieren, sondern
besser blocken sollte, das erscheint mir aber nicht so gut, weil die
dann im Zustand "pending" bleiben.

Eine Fehlerbehandlung habe ich auch noch durch die Socket-Meldungen,
SIGPIPE kommt zusätzlich zum "Socket closed" mit Fehlernummer und wird
von mir nicht gebraucht.

Meine eigentliche Frage ist jetzt, wie das mit der Bearbeitung dieses
Signals ursprünglich gedacht war und ob es eine bessere Strategie gibt,
als das einfach zu ignorieren. Es kommt mir darauf an, dass das Programm
möglichst ungestört weiter läuft, da eine unterbrochene Verbindung an
anderer Stelle behandelt wird.
Rainer Weikusat (03.02.2016, 17:22)
Edzard Egberts <ed_09> writes:
> Ich habe ein Programm, das über Sockets TCP/IP-Verbindungen unterhält.
> Wenn ich das Programm im Debugger laufen lasse, erhalte ich gelegentlich
> (z.B. Herumbasteln an der Firewall) folgende Meldung:
> Program received signal SIGPIPE, Broken pipe.
> 0xb805df8e in send () from /lib/libpthread.so.0
> Der Debugger stoppt dann und läuft mit "Continue" weiter, was mir sagt,
> dass ich dieses Signal behandeln sollte, nämlich mit signal(SIGPIPE,
> SIG_IGN) abstellen. Im Release wird das Signal scheinbar per default
> nicht bearbeitet? Ist das richtig, oder kann das im Release das Programm
> beenden?


Falls es nicht anderweitig abgestellt wurde, ja.

> Ich habe dazu noch gelesen, dass man Signale nicht ignorieren, sondern
> besser blocken sollte, das erscheint mir aber nicht so gut, weil die
> dann im Zustand "pending" bleiben.


Es ist auch Unsinn (Erklaerung folgt).

[...]

> Meine eigentliche Frage ist jetzt, wie das mit der Bearbeitung dieses
> Signals ursprünglich gedacht war und ob es eine bessere Strategie gibt,
> als das einfach zu ignorieren.


Es war/ ist dafuer gedacht, dass man die Ausgabe beliebiger Programme in
einen 'dynamisch verbundenen stream', zB eine pipe oder TCP-Verbindung,
umleiten kann, ohne dass diese besondere Fehlerbehandlung fuer
"Verbindung ploetzlich zusammengebrochen" implementieren: Versucht ein
Programm in einer solchen Situation Daten zu schreiben, sendet der
Kernel ein SIGPIPE das es beendet. Falls ein Programm 'weiss', dass es
mit dieser Situation zu rechnen hat, kann es SIGPIPE auf SIG_IGN setzen
und sich stattdessen um den EPIPE Fehler kuemmern.
Edzard Egberts (03.02.2016, 17:47)
Rainer Weikusat wrote:
> Edzard Egberts <ed_09> writes:
>> Ich habe ein Programm, das über Sockets TCP/IP-Verbindungen unterhält.
>> Wenn ich das Programm im Debugger laufen lasse, erhalte ich gelegentlich
>> (z.B. Herumbasteln an der Firewall) folgende Meldung:
>> Program received signal SIGPIPE, Broken pipe.
>> 0xb805df8e in send () from /lib/libpthread.so.0


>> Im Release wird das Signal scheinbar per default
>> nicht bearbeitet? Ist das richtig, oder kann das im Release das Programm
>> beenden?

> Falls es nicht anderweitig abgestellt wurde, ja.


Dazu muss ich anmerken, dass es wohl anderweitig abgestellt ist, denn
andernfalls wäre mir dieses Signal schon viel früher aufgefallen.
"Continue" würde nach einem Programmende auch nicht mehr funktionieren,
das war also eine dumme Frage.

>> Ich habe dazu noch gelesen, dass man Signale nicht ignorieren, sondern
>> besser blocken sollte, das erscheint mir aber nicht so gut, weil die
>> dann im Zustand "pending" bleiben.

> Es ist auch Unsinn (Erklaerung folgt).


Sicher? Kommt mir aber auch ohne Erklärung nicht überzeugend vor.

> Es war/ ist dafuer gedacht, dass man die Ausgabe beliebiger Programme in
> einen 'dynamisch verbundenen stream', zB eine pipe oder TCP-Verbindung,
> umleiten kann, ohne dass diese besondere Fehlerbehandlung fuer
> "Verbindung ploetzlich zusammengebrochen" implementieren: Versucht ein
> Programm in einer solchen Situation Daten zu schreiben, sendet der
> Kernel ein SIGPIPE das es beendet.


Aha, im Unix-Umfeld wäre das dann wahrscheinlich ein fork und nicht das
ganze Programm.

> Falls ein Programm 'weiss', dass es
> mit dieser Situation zu rechnen hat, kann es SIGPIPE auf SIG_IGN setzen
> und sich stattdessen um den EPIPE Fehler kuemmern.


Danke, das wollte ich bestätigt haben, mit ein bisschen
Hintergrundwissen ist mir da gleich wohler.
Rainer Weikusat (03.02.2016, 18:51)
Edzard Egberts <ed_09> writes:
> Rainer Weikusat wrote:
> Dazu muss ich anmerken, dass es wohl anderweitig abgestellt ist, denn
> andernfalls wäre mir dieses Signal schon viel früher aufgefallen.
> "Continue" würde nach einem Programmende auch nicht mehr funktionieren,
> das war also eine dumme Frage.


Unter Beruecksichtigung der Situation wuerde das wahrscheinlich
bedeuten, dass 'irgendwo' ein SIGPIPE handler definiert ist. In diesem
Fall bekaemest Du das Signal im Debugger zu sehen, weil der das Programm
fuer jedes an es gesendete Signal anhaelt bevor der Handler ausgefuehrt
wurde (falls nicht anders konfiguriert).
Matthias Andree (03.02.2016, 20:57)
Am 03.02.2016 um 16:47 schrieb Edzard Egberts:
> Rainer Weikusat wrote:
> Dazu muss ich anmerken, dass es wohl anderweitig abgestellt ist, denn
> andernfalls wäre mir dieses Signal schon viel früher aufgefallen.
> "Continue" würde nach einem Programmende auch nicht mehr funktionieren,
> das war also eine dumme Frage.


Manche Debugger verfolgen Konzepte wie first- und last-/2nd-chance
exceptions, und viele sind hinsichtlich des Signalhandlings auch
konfigurierbar...

>> Falls ein Programm 'weiss', dass es
>> mit dieser Situation zu rechnen hat, kann es SIGPIPE auf SIG_IGN setzen
>> und sich stattdessen um den EPIPE Fehler kuemmern.

> Danke, das wollte ich bestätigt haben, mit ein bisschen
> Hintergrundwissen ist mir da gleich wohler.


Auf den meisten Systemen sind die signal(3)-Manpages oder ggf.
sigaction() ganz ordentlich beschrieben...
Edzard Egberts (11.02.2016, 11:34)
Edzard Egberts wrote:
> Ich habe ein Programm, das über Sockets TCP/IP-Verbindungen unterhält.
> Wenn ich das Programm im Debugger laufen lasse, erhalte ich gelegentlich
> (z.B. Herumbasteln an der Firewall) folgende Meldung:
> Program received signal SIGPIPE, Broken pipe.
> 0xb805df8e in send () from /lib/libpthread.so.0
> Der Debugger stoppt dann und läuft mit "Continue" weiter, was mir sagt,
> dass ich dieses Signal behandeln sollte, nämlich mit signal(SIGPIPE,
> SIG_IGN) abstellen.


Eine weitere Debug-Sitzung, diesmal mit ignore SIGPIPE, hat ergeben,
dass ein Thread im select() hängt. Kann das zusammenhängen? Der Code
sieht so aus:

timeval tv; // Sockets überprüfen, maximal für Zeit MilliSek
warten:
tv.tv_sec= MilliSek / 1000L; // Anzahl der glatten Sekunden eintragen
tv.tv_usec= (MilliSek % 1000L)* 1000L; // Anzahl der verbleibenden
Millisekunden als Mikrosekunden eintragen

fd_set Temp_Rd= *sm_Mem.m_pRd; // Select ändert das Set entsprechend den
// gerade aktiven Sockets, deshalb muss
// das statische Set kopiert werden
fd_set Temp_Wr= *sm_Mem.m_pWr;
fd_set Temp_Er= *sm_Mem.m_pEr;
if (int Num= select(sm_FD_Max +1, &Temp_Rd, &Temp_Wr, &Temp_Er, &tv))

Aufgerufen wird das mit MilliSek= 50 und IMHO darf select() gar nicht
hängen bleiben. Was mache ich denn nun, reboot auf SIGPIPE? Ich hätte
nie erwartet, dass ein select() mit Timeout hängen bleiben kann.
Edzard Egberts (11.02.2016, 12:01)
Edzard Egberts wrote:
> Eine weitere Debug-Sitzung, diesmal mit ignore SIGPIPE, hat ergeben,
> dass ein Thread im select() hängt.


Nachtrag: Genauer gesagt die Funktion _ZN8t_socket5TimerEj
Stefan Reuther (11.02.2016, 18:49)
Am 11.02.2016 um 10:34 schrieb Edzard Egberts:
> Edzard Egberts wrote:
> Eine weitere Debug-Sitzung, diesmal mit ignore SIGPIPE, hat ergeben,
> dass ein Thread im select() hängt. Kann das zusammenhängen? Der Code
> sieht so aus:


Hängt der im select() oder loopt der fleißig?

Mein erster Verdacht wäre ja, dass einer der Filedescriptoren (genau
der, der das SIGPIPE geworfen hätte) in einen Fehlerzustand geht, den du
nicht korrekt auflöst.

Stefan
Edzard Egberts (12.02.2016, 09:38)
Stefan Reuther wrote:
> Am 11.02.2016 um 10:34 schrieb Edzard Egberts:
>> Edzard Egberts wrote:
>> Eine weitere Debug-Sitzung, diesmal mit ignore SIGPIPE, hat ergeben,
>> dass ein Thread im select() hängt. Kann das zusammenhängen? Der Code
>> sieht so aus:

> Hängt der im select() oder loopt der fleißig?


Der hängt wirklich, der Debugger macht nichts anderes, als in den
zweiten Thread zu wechseln, step, next oder ein breakpoint im Loop
brachte alles nichts.

> Mein erster Verdacht wäre ja, dass einer der Filedescriptoren (genau
> der, der das SIGPIPE geworfen hätte) in einen Fehlerzustand geht, den du
> nicht korrekt auflöst.


Ähm, ja, *hüstel*! Das Problem fand sich gerade in der anderen Ecke beim
send(). Dort sollte eigentlich jeder Fehler außer EWOULDBLOCK den
Descriptor abschalten und genau dieser Block war auskommentiert. Der
enthielt natürlich auch noch die Fehlermeldung. ;o(
Ähnliche Themen