forken aus define

Begonnen von herrmannj, 06 Oktober 2014, 07:28:05

Vorheriges Thema - Nächstes Thema

herrmannj

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

rudolfkoenig

Wenn Du hier weitere Erkenntnisse hast, bitte mitteilen, es haengt evtl. mit der iOS8 Ladeproblematik auch zusammen.

herrmannj

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

Dr. Boris Neubert

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
Globaler Moderator, Developer, aktives Mitglied des FHEM e.V. (Marketing, Verwaltung)
Bitte keine unaufgeforderten privaten Nachrichten!

herrmannj

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

rudolfkoenig

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.

justme1968

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?
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

herrmannj

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.

rudolfkoenig

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.

herrmannj

_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

herrmannj


sub define
...
my $pid=fork();
return undef (if $pid );
  close STDOUT;
  close STDIN;
  close STDERR;
  setsid();
  sleep(10)
_exit(0);


herrmannj

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