How to assure NSTask termination when parent dies

  • My app generates a task using NSTask().

    If my app is killed or calls abort() - which equates to raise(SIGABRT) - then it would be desirable that the child die too.

    If I have the code for the launched task then a kqueue comes to the rescue:
    http://old.nabble.com/Ensure-NSTask-terminates-when-parent-application-does
    -td22510014.html


    However, if I launch a shell this option isn't available.
    So process groups come to mind.

    However calling setpgid (see code below) seems to fail however with RPERM - operation not allowed.
    Is this an OS X POSIX process implementation detail or a consequence of the interior NSTask fork() implementation?

    I know that there are some OS NSTask substitutes available but I am not certain that that is the answer.

    My only thought is to install a Cocoa friendly signal handler and explicitly terminate the child.
    But there is no guarantee that this sort of post trauma cleanup will always succeed.

    Process group code:

    // launch the task
        [task launch];

    pid_t group = setsid();
    if (group == -1) {
            NSLog(@"setsid() == -1");
              group = getpgrp();
    }
    if (setpgid([task processIdentifier], group) == -1) {
              NSLog(@"unable to put task into same group as self: errno = %i", errno);
    }
    NSLog(@"new task process id = %i", [task processIdentifier]);
    NSLog(@"pgid = %i", group);

    Regards

    Jonathan Mitchell

    Developer
    Mugginsoft LLP
    http://www.mugginsoft.com
  • On Fri, Aug 13, 2010 at 9:13 AM, <jonathan...>
    <jonathan...> wrote:
    > My app generates a task using NSTask().
    >
    > If my app is killed or calls abort() - which equates to raise(SIGABRT) - then it would be desirable that the child die too.
    >
    > If I have the code for the launched task then a kqueue comes to the rescue:
    > http://old.nabble.com/Ensure-NSTask-terminates-when-parent-application-does
    -td22510014.html

    >
    > However, if I launch a shell this option isn't available.
    > So process groups come to mind.
    >
    > However calling setpgid (see code below) seems to fail however with RPERM - operation not allowed.
    > Is this an OS X POSIX process implementation detail or a consequence of the interior NSTask fork() implementation?
    >
    > I know that there are some OS NSTask substitutes available but I am not certain that that is the answer.
    >
    > My only thought is to install a Cocoa friendly signal handler and explicitly terminate the child.
    > But there is no guarantee that this sort of post trauma cleanup will always succeed.

    I'm not sure why your setpgid doesn't work. You might try a more
    UNIX-oriented mailing list, such as darwin-dev. Your problem isn't
    really related to Cocoa except for the part where you're using an
    NSTask wrapper, and that *shouldn't* affect things....

    There are a couple of other things you could try.

    If your subprocess reads from standard input and exits on EOF, set its
    standard input to a pipe. When your process exits, it will close its
    end of the pipe. That will cause an EOF to be generated on the other
    side, and it will exit.

    If your subprocess regularly writes to standard output, set its
    standard output to a pipe. When your process exits, it will close its
    end, which causes a SIGPIPE to be generated on the other side the next
    time it tries to write to it. SIGPIPE kills the process by default.

    Finally, if neither of these apply to your particular subprocess, you
    could make your own subprocess that DOES do these, and it could then
    kill the other subprocesses when it sees your process exit.

    Mike
  • On 13 Aug 2010, at 19:29, Michael Ash wrote:
    >
    > I'm not sure why your setpgid doesn't work. You might try a more
    > UNIX-oriented mailing list, such as darwin-dev.
    >
    > There are a couple of other things you could try.
    >
    > If your subprocess reads from standard input and exits on EOF, set its
    > standard input to a pipe. When your process exits, it will close its
    > end of the pipe. That will cause an EOF to be generated on the other
    > side, and it will exit.
    >
    > If your subprocess regularly writes to standard output, set its
    > standard output to a pipe. When your process exits, it will close its
    > end, which causes a SIGPIPE to be generated on the other side the next
    > time it tries to write to it. SIGPIPE kills the process by default.
    >

    Thanks for the suggestions Mike.
    I have the tasks piped up already but I am still able to get unruly child processes.
    I will take a close look at just how the pipes are being utilised.

    Regards

    Jonathan
  • > Process group code:
    >
    > // launch the task
    > [task launch];
    >
    > pid_t group = setsid();
    > if (group == -1) {
    > NSLog(@"setsid() == -1");
    > group = getpgrp();
    > }
    > if (setpgid([task processIdentifier], group) == -1) {
    > NSLog(@"unable to put task into same group as self:
    > errno = %i", errno);
    > }

    The current process-group id is inherited across fork() and execve()
    -  see their respective man pages.  So if you reorder the operations
    so setsid() occurs before [task launch], then the child inherits
    automatically.

    This doesn't mean the child can't change its own pgid/sid.  And since
    you mention a shell, it's not unusual for shells to do exactly that.

      -- GG
  • On 13 Aug 2010, at 22:32, Greg Guerin wrote:

    >> Process group code:
    >>
    >> // launch the task
    >> [task launch];
    >>
    >> pid_t group = setsid();
    >> if (group == -1) {
    >> NSLog(@"setsid() == -1");
    >> group = getpgrp();
    >> }
    >> if (setpgid([task processIdentifier], group) == -1) {
    >> NSLog(@"unable to put task into same group as self: errno = %i", errno);
    >> }
    >
    > The current process-group id is inherited across fork() and execve() -  see their respective man pages.  So if you reorder the operations so setsid() occurs before [task launch], then the child inherits automatically.
    >
    Hah! That does seem to have the desired effect.

    > This doesn't mean the child can't change its own pgid/sid.  And since you mention a shell, it's not unusual for shells to do exactly that.
    >
    In my simple test (one task forks/execs to bash which forks/execs 10 background sleeps) killing the process leader has the desired cascade of terminations.

    Thanks and regards

    Jonathan Mitchell

    Developer
    Mugginsoft LLP
    previous month august 2010 next month
    MTWTFSS
                1
    2 3 4 5 6 7 8
    9 10 11 12 13 14 15
    16 17 18 19 20 21 22
    23 24 25 26 27 28 29
    30 31          
    Go to today