Preventing killing of child processes?
TN2083 explains that launchd kills child processes when the parent exits, and suggests using setsid() as a workaround when a child needs to stay alive. I'm in that situation, (see http://lists.macosforge.org/pipermail/launchd-dev/2009-September/000664.html for details, I want to change the StartInterval of my job and use a helper tool to un/reload myself from launchd), but I can't get my helper tool into a state where it's not killed. Calling setsid() from either the daemon (before launching the helper) or from the helper tool itself returns -1 and it's killed off by launchd as soon as the job is unloaded. What's the right way to use setsid() (or another approach) here?
Calling setpgrp() from your child should prevent launchd from killing it.
That doesn't seem to be doing it. The child process still exits as soon as it unloads the parent job from launchd.
Hmm, I just did a controlled test, and it certainly does the trick for me on 10.5.8. Here's what I did: ===== parent_process.c #include <stdio.h> #include <unistd.h> int main(int argc, const char *argv[]) { if (!fork()) { execl("/child_process", "/child_process"); _exit(0); } sleep(10); return 0; } ===== child_process.c #include <stdio.h> #include <unistd.h> int main(int argc, const char *argv[]) { setpgrp(); sleep(60); return 0; } ===== com.parent.parent_process.plist <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.parent.parent_process</string> <key>ProgramArguments</key> <array> <string>/parent_process</string> </array> <key>RunAtLoad</key> <true/> </dict> </plist> ===== Compile parent_process.c and child_process.c, and put them and the plist in your drive's root directory. Then: launchctl load /com.parent.parent_process.plist You'll notice that the parent exits after 10 seconds, while the child stays alive for a full minute. Likewise, if you unload the parent early, the child still stays alive past the parent's death. Without setpgrp(), the child dies with the parent. Does that help?
That did help — and as it turns out, my problem wasn't launchd, but a missed SIGPIPE at the same time. I should have debugged it out more before posting to the list. Thanks, Dave. On Fri, Oct 9, 2009 at 7:50 PM, Dave Keck <davekeck@gmail.com> wrote:
That doesn't seem to be doing it. The child process still exits as soon as it unloads the parent job from launchd.
Hmm, I just did a controlled test, and it certainly does the trick for me on 10.5.8. Here's what I did:
===== parent_process.c
#include <stdio.h> #include <unistd.h>
int main(int argc, const char *argv[]) { if (!fork()) { execl("/child_process", "/child_process"); _exit(0); } sleep(10); return 0; }
===== child_process.c
#include <stdio.h> #include <unistd.h>
int main(int argc, const char *argv[]) { setpgrp(); sleep(60); return 0; }
===== com.parent.parent_process.plist
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.parent.parent_process</string> <key>ProgramArguments</key> <array> <string>/parent_process</string> </array> <key>RunAtLoad</key> <true/> </dict> </plist>
=====
Compile parent_process.c and child_process.c, and put them and the plist in your drive's root directory. Then:
launchctl load /com.parent.parent_process.plist
You'll notice that the parent exits after 10 seconds, while the child stays alive for a full minute. Likewise, if you unload the parent early, the child still stays alive past the parent's death. Without setpgrp(), the child dies with the parent. Does that help?
participants (2)
-
Dave Keck
-
Sidney San Martín