NSTask terminates when NSApplication exits
-
I am trying to write a program that maintains different installs of
another program including launching the program. To do so, I am using
NSTask. Now when I quit my cocoa app. the NSTask app dies. The task
that the NSTask is running is a Java program, not sure if that makes a
difference. According to what I have read, the application should keep
running even when the parent task exits. I am running my cocoa app
from in XCode4, not sure if that has any effect on it. Could it be
that I am not specifying standard* streams so when the parent app
quits, those streams are closed and thus the process?
I can probably find out the answer by trying different things, but I'd
like to get a better insight for what is going on and why the child
task is terminating. -
On Jan 18, 2012, at 11:59 AM, Andrew wrote:
> I can probably find out the answer by trying different things, but I'd
> like to get a better insight for what is going on and why the child
> task is terminating.
You may want to try LSxxxx (Launch Services) routines.
--
Scott Ribe
<scott_ribe...>
http://www.elevated-dev.com/
(303) 722-0567 voice -
On Jan 18, 2012, at 10:59 AM, Andrew wrote:
> I am trying to write a program that maintains different installs of
> another program including launching the program. To do so, I am using
> NSTask. Now when I quit my cocoa app. the NSTask app dies. …
> According to what I have read, the application should keep
> running even when the parent task exits.
Nope. In Unix, a process is killed when its parent process exits. This is one reason why you shouldn't launch application processes directly :) Instead, use NSWorkspace to launch the app (or call LaunchServices directly if you prefer a C API.) This starts it up in the normal way, as a subprocess of your login session’s main launchd process.
—Jens -
On Jan 18, 2012, at 11:59 AM, Andrew wrote:
> I am trying to write a program that maintains different installs of
> another program including launching the program. To do so, I am using
> NSTask. Now when I quit my cocoa app. the NSTask app dies. The task
> that the NSTask is running is a Java program, not sure if that makes a
> difference. According to what I have read, the application should keep
> running even when the parent task exits. I am running my cocoa app
> from in XCode4, not sure if that has any effect on it. Could it be
> that I am not specifying standard* streams so when the parent app
> quits, those streams are closed and thus the process?
>
> I can probably find out the answer by trying different things, but I'd
> like to get a better insight for what is going on and why the child
> task is terminating.
Any special handling of NSTask aside, Mac OS X uses Unix-based process control which closes all child processes when the parent is closed. Since your sub-program is Java you may be able to detach the child process. This is usually accomplished by the sub-program by executing a low-level fork(). It may need to be followed by an exec() to fully detach the process. Note that you can't do this with Cocoa/Objective-C (at least Apple says you shouldn't…)
Alternatively (and probably preferably) you could use launchd/Launch Services as recommended. Useful reading: http://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPS
ystemStartup/Chapters/Introduction.html
HTH,
Keary Suska
Esoteritech, Inc.
"Demystifying technology for your home or business" -
On Jan 18, 2012, at 3:13 PM, Keary Suska wrote:
> Any special handling of NSTask aside, Mac OS X uses Unix-based process control which closes all child processes when the parent is closed.
No, that's not true. Where did you get that?
Processes with a controlling terminal get a SIGHUP when that terminal is closed, and that will kill a naive process, but that wouldn't apply to subprocesses of GUI apps. Other than that, child processes are independent of their parent process.
> Since your sub-program is Java you may be able to detach the child process.
This doesn't make sense to me. What does being Java have to do with anything?
> This is usually accomplished by the sub-program by executing a low-level fork(). It may need to be followed by an exec() to fully detach the process.
Fork() creates the child subprocess as a near duplicate of the parent. Exec() replaces the process's image with a new one. This is the standard means of creating a subprocess running a new program, but doesn't particularly "detach" an already-existing subprocess from its parent (whatever that might mean).
> Note that you can't do this with Cocoa/Objective-C (at least Apple says you shouldn't…)
You can fork() and exec() just fine. What you can't do is fork(), _not_ call exec(), and then do anything other than call POSIX async-cancel-safe APIs. That includes using high-level frameworks like Cocoa, Core Foundation, or the like.
Regards,
Ken -
Thanks, I'll have a look.
BTW, I was able to confirm it is a result of streams. My Java
processes do not quit if I pipe their output to null:
NSTask *task = [NSTask new];
[task setLaunchPath:execPath];
[task setCurrentDirectoryPath:_directory];
[task setArguments:arguments];
[task setStandardError:[NSFileHandle fileHandleWithNullDevice]];
[task setStandardOutput:[NSFileHandle fileHandleWithNullDevice]];
[task launch];
So if I want to capture the output I can simply use a file handle to a
real file and it looks like the NSTask process no longer quits.
On Wed, Jan 18, 2012 at 12:55 PM, Scott Ribe
<scott_ribe...> wrote:
> On Jan 18, 2012, at 11:59 AM, Andrew wrote:
>
>> I can probably find out the answer by trying different things, but I'd
>> like to get a better insight for what is going on and why the child
>> task is terminating.
>
> You may want to try LSxxxx (Launch Services) routines.
>
> --
> Scott Ribe
> <scott_ribe...>
> http://www.elevated-dev.com/
> (303) 722-0567 voice
>
>
>
>
-
On Jan 18, 2012, at 2:27 PM, Ken Thomases wrote:
>> Note that you can't do this with Cocoa/Objective-C (at least Apple says you shouldn't…)
>
> You can fork() and exec() just fine. What you can't do is fork(), _not_ call exec(), and then do anything other than call POSIX async-cancel-safe APIs. That includes using high-level frameworks like Cocoa, Core Foundation, or the like.
I think it's recommended that you not launch a GUI app via fork/exec. Calling fork/exec *from* GUI apps is fine all day long.
--
Scott Ribe
<scott_ribe...>
http://www.elevated-dev.com/
(303) 722-0567 voice -
On Wed, Jan 18, 2012 at 12:38 PM, Jens Alfke <jens...> wrote:
> Nope. In Unix, a process is killed when its parent process exits.
No it's not.
/tmp% cat processes.c
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
printf("Parent pid is %lu\n", (unsigned long)getpid());
pid_t child = fork();
if (child == -1) {
fprintf(stderr, "Fork failed\n");
return 1;
} else if (child == 0) {
sleep(10000);
return 0;
} else {
printf("Child pid is %lu, parent exiting\n", (unsigned long)child);
return 0;
}
}
/tmp% clang -o processes processes.c
/tmp% ./processes
Parent pid is 47549
Child pid is 47550, parent exiting
/tmp% ps aux 47549
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
/tmp% ps aux 47550
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
kyle 47550 0.0 0.0 2434784 160 s000 S 9:34AM 0:00.00 ./processes
--Kyle Sluder -
On Jan 18, 2012, at 2:27 PM, Ken Thomases wrote:
> On Jan 18, 2012, at 3:13 PM, Keary Suska wrote:
>
>> Any special handling of NSTask aside, Mac OS X uses Unix-based process control which closes all child processes when the parent is closed.
>
> No, that's not true. Where did you get that?
It has likely, as you point out, come from the entirely wrong orifice. I suspect I am confusing tis with system() and popen() calls, which I think have a dependency on the parent process' life, but I could be wrong about that too.
> Processes with a controlling terminal get a SIGHUP when that terminal is closed, and that will kill a naive process, but that wouldn't apply to subprocesses of GUI apps. Other than that, child processes are independent of their parent process.
>
>> Since your sub-program is Java you may be able to detach the child process.
>
> This doesn't make sense to me. What does being Java have to do with anything?
I meant as opposed to a Cocoa-based app. The Java runtime, AFAIK, does not have the same restrictions.
>> This is usually accomplished by the sub-program by executing a low-level fork(). It may need to be followed by an exec() to fully detach the process.
>
> Fork() creates the child subprocess as a near duplicate of the parent. Exec() replaces the process's image with a new one. This is the standard means of creating a subprocess running a new program, but doesn't particularly "detach" an already-existing subprocess from its parent (whatever that might mean).
Again, this might be my mistaking daemonizing pipe-to-subprocess, but I could be wrong about that too.
>> Note that you can't do this with Cocoa/Objective-C (at least Apple says you shouldn't…)
>
> You can fork() and exec() just fine. What you can't do is fork(), _not_ call exec(), and then do anything other than call POSIX async-cancel-safe APIs. That includes using high-level frameworks like Cocoa, Core Foundation, or the like.
This might also be where I recalled the necessity of fork-exec, but it has been some time since I wandered down that rabbit hole..
Sorry for the noise...
Keary Suska
Esoteritech, Inc.
"Demystifying technology for your home or business" -
On Jan 18, 2012, at 1:38 PM, Jens Alfke wrote:
>
> Nope. In Unix, a process is killed when its parent process exits.
Not true. It looks like the case at a cursory level because session management does this when you're in the terminal. There are various ways to arrange for a process to exit when its parent exits. But it is *not* the case that a process is automatically killed when its parent exits.
--
Scott Ribe
<scott_ribe...>
http://www.elevated-dev.com/
(303) 722-0567 voice -
On Jan 19, 2012, at 10:10 AM, Scott Ribe wrote:
> Not true. It looks like the case at a cursory level because session management does this when you're in the terminal. There are various ways to arrange for a process to exit when its parent exits. But it is *not* the case that a process is automatically killed when its parent exits.
Huh; you learn something new every day!
In addition to shell behavior you mention, I also see this when Xcode crashes and takes down the app I’m debugging. But I suppose Xcode configures the process it launches to work that way?
—Jens -
On Jan 19, 2012, at 12:49 PM, Jens Alfke wrote:
> On Jan 19, 2012, at 10:10 AM, Scott Ribe wrote:
>
>> Not true. It looks like the case at a cursory level because session management does this when you're in the terminal. There are various ways to arrange for a process to exit when its parent exits. But it is *not* the case that a process is automatically killed when its parent exits.
>
> Huh; you learn something new every day!
>
> In addition to shell behavior you mention, I also see this when Xcode crashes and takes down the app I’m debugging. But I suppose Xcode configures the process it launches to work that way?
This is probably because Xcode is using a pseudo-terminal device as the subprocess's output, so it can capture it and show it in the console window, and thus the subprocess has a controlling terminal, which is closed when Xcode crashes, which delivers SIGHUP to the subprocess. If a process hasn't specifically arranged otherwise, it will be killed by the SIGHUP.
Regards,
Ken -
On Jan 19, 2012, at 11:49 AM, Jens Alfke wrote:
> Huh; you learn something new every day!
Yeah, specifically I learned this about 6 months ago ;-)
> In addition to shell behavior you mention, I also see this when Xcode crashes and takes down the app I’m debugging. But I suppose Xcode configures the process it launches to work that way?
Yeah, probably what Ken said ;-) In my case, I spent a lot of effort trying to figure out how to get a child process to *not* exit when the parent crashed, then suddenly it just started working that way ;-)
--
Scott Ribe
<scott_ribe...>
http://www.elevated-dev.com/
(303) 722-0567 voice


