Messages in this thread | | | From | Bryan Donlan <> | Date | Fri, 8 Apr 2011 16:52:05 -0400 | Subject | Re: [path][rfc] add PR_DETACH prctl command |
| |
2011/4/8 Stas Sergeev <stsp@aknet.ru>: > 08.04.2011 22:13, Bryan Donlan wrote: >> >> I can't comment on the patch itself, but, if your application knows it >> might have to daemonize after spinning up threads, why not simply >> fork() immediately on startup, and have the parent simply wait forever >> for either the child to die or for a daemonize signal from the child? >> If done early enough it shouldn't tie up too much memory, and it >> wouldn't require any of these invasive kernel changes. As an added >> bonus, it's portable to all unixen :) > > Yes, thats almost always true. Except when you deal with > the vendor-provided poorly-coded drivers and libs, where > you get the drivers initialized only via the lib. And the > initialization process must be finished before the boot-up > can continue, but that's not the whole story: only the > process that initialized that lib, can then work with it. > And of course that lib creates a dozen of threads... > OK, you've got the idea. :)
Still, you can workaround this by either: a) Load the vendor library via dlopen() b) Use a separate launcher executable to handle the fork-and-wait
Either of these approaches are far simpler than patching the kernel, more portable, and much, much easier to get right. In fact, here's a quick and dirty implementation of the latter:
#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h>
void sigusr1_handler(int unused) { (void)unused;
_exit(0); }
int main(int argc, char **argv) { int waitstatus; pid_t child, parent = getpid();
(void)argc;
signal(SIGUSR1, sigusr1_handler);
child = fork(); if (child < 0) { perror("Fork failed"); return EXIT_FAILURE; } if (child == 0) { char envbuf[20]; sprintf(envbuf, "%d", (int)parent); setenv("LAUNCHER_PID", envbuf, 1);
execvp(argv[1], &argv[1]); perror("Launching child failed"); _exit(EXIT_FAILURE); }
wait(&waitstatus);
if (WIFEXITED(waitstatus)) _exit(WEXITSTATUS(waitstatus));
_exit(256); }
Just kill(atoi(getenv("LAUNCHER_PID")), SIGUSR1) to detach. Much easier than doing some very racy things in the kernel, no? It's certainly more obvious that this ought to be correct in the face of races with its parent :)
| |