views:

64

answers:

3

This would be easy with fork(), but I've got no MMU. I've heard that vfork() blocks the parent process until the child exits or executes exec(). How would I accomplish something like this?:

pid_t pid = vfork();

if (pid == -1) {
    // fail
    exit(-1);
}

if (pid == 0) {
    // child
    while(1) {
        // Do my daemon stuff
    }

    // Let's pretend it exits sometime
    exit();
} 

// Continue execution in parent without blocking.....
+3  A: 

It seems there is no way to do this exactly as you have it here. exec or _exit have to get called for the parent to continue execution. Either put the daemon code into another executable and exec it, or use the child to spawn the original task. The second approach is the sneaky way, and is described here.

zdav
The downvote was undeserved. zdav is right.
ninjalj
A twist is to use a multi-call binary, then you don't need put to the binary code into another executable proper.
Amigable Clark Kant
ninjalj
+3  A: 

daemon() function for uClinux systems without MMU and fork(), by Jamie Lokier, in patch format

You can't do daemon() with vfork(). To create something similar to a daemon on !MMU using vfork(), the parent process doesn't die (so there are extra processes), and you should call your daemon on the background (i.e. by appending & to the command line on the shell).

On the other hand, Linux provides clone(). Armed with that, knowledge and care, it's possible to implement daemon() for !MMU. Jamie Lokier has a function to do just that on ARM and i386, get it from here.

Edit: made the link to Jamie Lokier's daemon() for !MMU Linux more prominent.

ninjalj
A: 

I would have thought that this would be the type of problem that many others had run into before, but I've had a hard time finding anyone talking about the "kill the parent" problems.

I initially thought that you should be able to do this with a (not quite so, but sort of) simple call to clone, like this:

pid_t new_vfork(void) {
    return clone(child_func,        /* child function */
                 child_stack,          /* child stack    */
                 SIGCHLD | CLONE_VM,   /* flags */
                 NULL,                 /* argument to child */
                 NULL,                 /* pid of the child */
                 NULL,                 /* thread local storage for child */
                 NULL);                /* thread id of child in child's mem */
}

Except that determining the child_stack and the child_func to work the way that it does with vfork is pretty difficult since child_func would need to be the return address from the clone call and the child_stack would need to be the top of the stack at the point that the actual system call (sys_clone) is made.

You could probably try to call sys_clone directly with

pid_t new_vfork(void) {
    return sys_clone( SIGCHLD | CLONE_VM, NULL);
}

Which I think might get what you want. Passing NULL as the second argument, which is the child_stack pointer, causes the kernel to do the same thing as it does in vfork and fork, which is to use the same stack as the parent.

I've never used sys_clone directly and haven't tested this, but I think it should work. I believe that:

  sys_clone( SIGCHLD | CLONE_VM | CLONE_VFORK, NULL);

is equivalent to vfork.

If this doesn't work (and you can't figure out how to do something similar) then you may be able to use the regular clone call along with setjump and longjmp calls to emulate it, or you may be able to get around the need for the "return's twice" semantics of fork and vfork.

nategoose
I wonder if that would suffer from the problem described here: http://www.mail-archive.com/[email protected]/msg01290.html
ninjalj
Probably would. Plus I haven't been able to locate a `sys_clone` library function. It sure would be nice to have, though.
nategoose