2014-03-05 9 views
5

Ich schreibe eine debugging utility, und ich möchte fork ein Kind, während verhindert, dass die Kündigung des Kindes eine SIGCHLD zu seinem Elternteil auslösen. Ich möchte immer noch, dass andere Kinder nach der Beendigung normalerweise SIGCHLD verursachen.Gibt es eine Möglichkeit zu verhindern, dass nur ein bestimmtes Kind eine SIGCHLD auslöst?

Ich möchte dies tun, weil ich nicht wollen fork einen vorhandenen $SIG{CHLD} Handler auslösen, aber ich möchte immer noch andere Kinder, um es auszulösen. Das heißt, ich möchte mein neues Kind isolieren und ich möchte nicht, dass es die Verwaltung bestehender Kinder beeinträchtigt.

Ich bin vorsichtig bei der lokalen Installation eines benutzerdefinierten $SIG{CHLD} Handler, da ich glaube nicht, kann ich richtig erkennen, wenn ich den ursprünglichen Handler aufrufen sollte. Zum Beispiel, wenn ich einen lokalen $SIG{CHLD} Handler installiere, dann bin ich garantiert, ein SIGCHLD Signal zu erhalten, sobald ich ein Kind spawne und das Elternteil waitpid dafür habe, es zu beenden. Das SIGCHLD wird jedoch nicht anzeigen, ob andere Kinder ebenfalls beendet wurden oder nicht, so dass ich nicht sicher sein kann, ob der ursprüngliche Handler aufgerufen werden soll.

Ich recherchierte, dass ein Prozess seine Eltern-PID nicht ändern kann. Ich bin mir nicht sicher, ob das Ändern der Prozessgruppen-ID oder der Sitzungs-ID des Kindes nützlich wäre.

Ist es sogar möglich zu verhindern, dass ein bestimmtes Kind die SIGCHLD auf dem Elternteil auslöst? Muss ich mich auf den vorhandenen $SIG{CHLD}-Handler verlassen, um das Richtige zu tun, wenn er das SIGCHLD-Signal für ein Kind empfängt, das er nicht erwartet hat?

Obwohl es möglicherweise eine bessere Möglichkeit gibt, dieses Debugging-Dienstprogramm zu implementieren (lassen Sie mich wissen, wenn es gibt), frage ich mich immer noch, ob POSIX bietet so eine feinkörnige Kontrolle über Kinder, und bin auf der Suche nach einer Perl-Lösung für meine Dilemma.

Antwort

2

Sie können nicht portably verhindern die SIGCHLD vollständig, aber wenn der Signal-Handler geschrieben ist richtig können Sie die waitpid von der Rückkehr Ihre Debugging-Tool pid es durch Verwaisung verhindern.

use Signal::Mask; 
sub start_background_child { 
    local $Signal::Mask{CHLD} = 1; 
    my $first = fork; 
    croak "fork failed: $!" if not defined $first; 
    if ($first) { 
    waitpid $first, 0; 
    return; 
    } 

    my $second = fork; 
    croak "fork failed: $!" if not defined $second; 
    exit if $second; 

    your_stuff_here(); 
} 
+0

Dieser Ansatz kann oder kann nicht verhindern, dass die ursprüngliche SIGCHLD (Portabilitätsproblem), aber wenn es nicht wartet, wird nie den Debugprozess zurückgeben. –

+0

So perfekt wie es nur geht! Auf meinem Macbook (OS X 10.8.2) funktioniert das wie gewünscht.Außerdem liebe ich Ihre 'Signal :: Mask' und' Signal :: Pending' Module; Sie haben es sehr einfach gemacht, das Verhalten auf meinem System zu erforschen. :) – Mohith

1

Ich denke, du könntest das spezielle Kind - Gabel zweimal dämonisieren - um die Eltern-Kind-Beziehung zu trennen. Sie erhalten immer noch eine SIGCHLD, wenn der Prozess erstellt wurde - ich weiß nicht, ob das für Sie akzeptabel ist.

sub start_special_child { 
    return if fork;  # run rest of this routine in child process 
    fork && exit;  # run rest of this routine in grandchild process 
         # the exit here triggers SIGCHLD in the parent 
    ...     # now run your special process 
    exit;    # exit here does not trigger SIGCHLD 
} 

Der andere Ansatz ist die Übersicht über den Prozess-IDs Ihres Kind Prozesse zu halten, und waitpid verwenden, um herauszufinden, welche (s) Verfahren die SIGCHLD Handler ausgelöst.

$SIG{CHLD} = \&sigchld_handler; 
$pid1 = start_child_process(); 
$pid2 = start_child_process(); 
$pid3 = start_child_process(); 
$pidS = start_special_child_process(); 

sub sigchld_handler { 
    $pid = waitpid -1, WNOHANG;  # use POSIX ':sys_wait_h' 
    return if $pid == $pidS; 
} 
+0

Ich möchte, dass die anfängliche 'SIGCHLD' zu vermeiden, so dass der erste Ansatz leider nicht akzeptabel für mich ist (da es immer noch die vorhandene' $ SIG {CHLD} 'Handler auslösen würde). Der zweite Ansatz wäre ideal, wenn ich den ursprünglichen '$ SIG {CHLD}' - Handler sowie die anderen Kinder kontrollieren könnte. Ich suche jedoch nach einer generischen Lösung, die unabhängig vom ursprünglichen '$ SIG {CHLD}' und ohne Kenntnis anderer Kinder funktioniert. Ich möchte auch vermeiden, die anderen Kinder zu ernten (aber es macht mir nichts aus, wenn das spezielle Kind geerntet wird). – Mohith

+0

Normalerweise mag ich Perls Threads nicht, aber vielleicht ist hier ein Thread besser geeignet als ein Fork. – mob