Das Problem ist, dass das Programm auf zwei Dinge gleichzeitig warten will: Signale und Daten aus dem Socket. Zur Lösung sind drei Wege denkbar:
select
«
, siehe
[8]
.Alle drei Arten sind unter Linux implementiert und dank zusätzlicher Module vom CPAN auch unter Perl nutzbar. Ich werde mich im Folgenden auf den zweiten Weg konzentrieren.
Eine unter Unix-ähnlichen Systemen recht kompatible Methode das zu implementieren, ist unter dem Namen "Self-Pipe Trick" [7] bekannt. Dazu erzeugt man für jedes zu erwartende Signal eine Pipe. Beide Enden der Pipe werden in den nicht-blockierenden Modus geschaltet. Der zu diesem Zweck in C zu implementierende Signal-Handler schreibt dann ein beliebiges Byte in die Pipe. Das kann schiefgehen, wenn die Pipe voll ist. Aber es wird den Prozess nicht blockieren, da der Dateideskriptor nicht-blockierend ist. Nun kann das Leseende der Pipe gemeinsam mit anderen Dateideskriptoren mit einem gewöhnlichen Select-, Poll- oder Epoll-Aufruf überwacht werden.
Die Methode ist jedoch sehr verschwenderisch, denn um ein Bit an Information zu verwalten, wird ein mehrere KByte großer Puffer im Kernel angelegt. Die Linux-Entwickler haben als Gegenmittel die Systemaufrufe
»signalfd
«
und
»eventfd
«
implementiert, um der Verschwendung Einhalt zu gebieten. Das CPAN-Modul
»Linux::FD
«
[4]
liefert Unterstützung für beide.
Für Perl-Programmierer bequemer ist allerdings das Modul
»AnyEvent
«
[5]
mit
»libev
«
[6]
als Backend. Damit wird
»eventfd
«
benutzt, wenn der Aufruf verfügbar ist. Sonst wird eine Self-Pipe gebastelt.
Listing 5
zeigt das Programm. Der interessante Teil spielt sich in der Funktion
»query
«
ab. Mit AnyEvent nicht vertraute Leser sollten einen Abstecher zum
Kasten "AnyEvent – eine Kurzübersicht"
machen.
Listing 5
burn3.pl