Guten morgen,
für ein device würde ich gern im define (des device) forken.
pseudocode:
sub define
...
my $pid=fork();
return undef (if $pid );
sleep(10)
_exit(0);
Das funktioniert über telnet, nicht jedoch über das webif. Im webif wird das return des parent ausgeführt (zB wird set ? danach aufgerufen). Die Seite wird jeoch erst weiter geladen wenn das child beendet ist.
Im "child-Teil" des define habe ich ebenfalls versucht alle filehandels (mit dem code aus blockingcall) zu löschen, keine Änderung.
Ich hab das jetzt soweit gelöst das ich im define einen internalTimer (+1) setze der (mit dem gleichen code) danach forked, aber so richtig wohl fühle ich mich nicht da ich nicht verstehe warum das fork im define blockt.
vg
jörg
Wenn Du hier weitere Erkenntnisse hast, bitte mitteilen, es haengt evtl. mit der iOS8 Ladeproblematik auch zusammen.
ja eben.
Verstehe ich grundsätzlich richtig?:
Während des fork werden alle offenen Verbindungen (TCP) dupliziert, nach dem (parent-) return des define "müsste" die mainloop die offenen Verbindungen beantworten.
Ich hab eine Weile gebraucht um zu verstehen das der "Hänger" im webif entsteht, hab lange gedacht mein fork würde nicht ausgeführt. Ich stell mal ein device hier rein um das Verhalten zu demonstrieren. Bin darüber hinaus etwas ratlos, die offenen filehandles hab ich ja testweise schon gelöscht.
vg
jörg
Auf die Gefahr hin, Eulen nach Athen zu tragen: in perlfork stehen kilometerweise Warnhinweise, worauf man beim Fork achten muss und welche Filehandles unbedingt vom Parent und vom Child geschlossen werden sollen. Ich habe das selbst nie umgesetzt, aber mir fiel ein, dass ich das neulich geĺesen habe, und ich dachte mir, ich schreib's hier mal.
Grüße
Boris
ZitatAuf die Gefahr hin, Eulen nach Athen zu tragen
alles gut, danke :)
Schließlich habe ich ja ge-posted weil ich alleine keine Lösung gefunden habe (und das Problem elegant aus sitze -> internalTimer ... ;) ) Eigene Fehler kann man jedoch per Definition nicht selber finden wenn sie auf Missverständnissen beruhen: Deine Antwort ist hochwillkommen.
Ich habe diesen Teil: (perldoc)
ZitatOpen filehandles
Any filehandles open at the time of the fork() will be dup()-ed. Thus, the files can be closed independently in the parent and child, but beware that the dup()-ed handles will still share the same seek pointer. Changing the seek position in the parent will change it in the child and vice-versa. One can avoid this by opening files that need distinct seek pointers separately in the child.
so interpretiert das der fork jeweils eine Kopie aller offenen Filehandle erhält.
Damit könnten jetzt sowohl parent als auch child weiterarbeiten.
Wenn der Child jetzt in einen blockenden mode geht (simuliert mit sleep) wird der "geerbte" Teil der select loop aus fhem.pl nie aufgerufen, ergo "sollte" der child sich auch nicht in die offenen IP (webif) Verbindungen, wie auch immer, einmischen.
Der parent sollte über die select loop die offenen Verbindungen bedienen, ergo sollte das webif weiter "durchladen". Machts aber nicht. Was ich finden konnte war der Versuch das zu tun (ich sehe das fhemweb das "set" des moduls im parent aufruft um die set Befehle zu ermitteln).
Weshalb das also
über telnet funktioniert und
webif nicht ist mir weiterhin unklar. Erstmal wollte ich aber eben "Denkfehler" für mich ausschließen.
vg
jörg
Soweit ich es verstehe, betrifft das ganze Geschwafel in "perldoc perlfork" die Emulation, d.h. Windows.
Und ich meine, damit haben wir in diesem Beitrag nicht zu tun.
auch auf die gefahr hin mich zu wiederholen :)
alles was dort zu filedescriptoren und schiessen, dup und buffern bzw filepointern gesagt wird gilt auch für unix/linux.
siehe explizite hinweise auf solaris und unixware. wenn das nur für windows gelten würde bräuchte es die ganzen close im blocking call nicht, die cul devices wären z.b. nicht bloickiert nach einem fork und restart, es wäre nicht nötig eine neue sqlite verbindung auf zu machen für plotfork und und und
das erklärt aber leider alles nicht das problem aus dem ersten post.
ich vermute aber das es auch mit den sockets zu tun hat.
@herrmannj: hast du mal versucht mit strace zu schauen was der hängende parent prozess genau macht?
Zitat@herrmannj: hast du mal versucht mit strace zu schauen was der hängende parent prozess genau macht?
ne, noch nich ..... Ich bin a auch drauf gestoßen im Rahmen eines device darauf gestossen und nachdem ich das "umschifft" hatte war die prio für das device erst mal höher ....
Aber Rudolf könnte schon irgendwie den Punkt haben:
http://perldoc.perl.org/functions/fork.html:
Dieser Teil:
ZitatPerl attempts to flush all files opened for output before forking the child process, but this may not be supported on some platforms (see perlport). To be safe, you may need to set $| ($AUTOFLUSH in English) or call the autoflush() method of IO::Handle on any open handles to avoid duplicate output.
könnte da irgendwie reinlaufen, ganz blicke ich das aber nicht.
Zitatsiehe explizite hinweise auf solaris und unixware.
Akzeptiert, aber aber alles andere meint klar die fork()-Emulation (aka Windows).
Ich finde die Idee mit _exit() gut, und wuerde es in BlockingCall und FHEMWEB/plotfork einbauen, falls kein Veto kommt.
Weiss noch jemand, wozu wir das FD-Schliessen in BlockingCall praktizieren? Ich habe es inzwischen verdraengt, und wuerde es gerne dokumentieren.
_exit meint POSIX _exit
Das schliessen der FD wird als best practice beschrieben, andre hatte ja aber auch ganz praktische auswirkungen (sagt er bestimmt)
Wenn die fd im child offen bleiben und der parent stirbt sind die dazugehörigen ressourcen geblockt (das ist wohl zb das cul thema). Das komische verhalten im define via webif zu untersuchen bin ich noch nicht zu gekommen.
vg
jörg
sub define
...
my $pid=fork();
return undef (if $pid );
close STDOUT;
close STDIN;
close STDERR;
setsid();
sleep(10)
_exit(0);
schon betagter, vielleicht noch von Interesse. Die komplette, funktionierende (Linux) Litanei lautet:
# child ahead
setsid();
# close open handles
close STDOUT;
open STDOUT, '>/dev/null';
close STDIN;
close STDERR;
open STDERR, '>/dev/null';
foreach my $key (keys %defs) { TcpServer_Close($defs{$key}) if ($defs{$key}->{SERVERSOCKET}); }
foreach my $key (keys %selectlist) { POSIX::close ($selectlist{$key}->{FD}) if (defined($selectlist{$key}->{FD})); }
vg
jörg