<div dir="ltr">This is how I use fork on one of my project<div><a href="http://gitlab.eurosat.cz/ekj/esatd/raw/master/source/app.d">http://gitlab.eurosat.cz/ekj/esatd/raw/master/source/app.d</a><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, May 15, 2017 at 1:33 PM, Jonathan Shamir via Digitalmars-d <span dir="ltr"><<a href="mailto:digitalmars-d@puremagic.com" target="_blank">digitalmars-d@puremagic.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hey,<br>
<br>
This is my first time writing in the D forums!<br>
<br>
I have an application written in D that runs as a linux daemon (some python service script is in charge of running and daemonizing it).<br>
This "agent" works similar to docker - a service that accepts commands and runs in the background, and starts our application container. The container is itself a daemon (ppid = 1) with unshared namespaces etc.<br>
<br>
So, normally, implementing such an application would look something like:<br>
1. Main "agent" process runs fork() to create a child process (child_1). All memory is copy-on-write.<br>
2. Child_1 malloc()s a stack, and calls clone() to create yet another child (child_2), which will eventually become the container pid 1.<br>
3. Child_2 initializes the container (mounts, unshare, chroot, etc) then eventually exec()s into the container init process.<br>
4. child_1 exit()s, which causes child_2 to become a daemon.<br>
5. The agent main process should wait() on the forked pid since it's impolite to leave zombies (I do this in a thread).<br>
<br>
The problem I encounter is with the forked process (child_1).<br>
<br>
Here is the code I wrote handling the fork() (Note: this functionality should really be provided by core.threads or something, for unix environments).<br>
<br>
```private void deferToForkProcess(int delegate() entryPoint, Timeout timeout = Timeout.infinite) {<br>
    import core.runtime : Runtime;<br>
    import core.sys.posix.unistd : fork, pid_t;<br>
    import core.sys.posix.sys.wait;<br>
    import core.stdc.stdlib : exit;<br>
<br>
    int rc = theReactor.deferToThread({<br>
        pid_t pid = fork();<br>
        errnoEnforce(pid >= 0, "Fork failed");<br>
<br>
        // child process<br>
        if (pid == 0) {<br>
            try {<br>
                int rc = entryPoint();<br>
                exit(rc);<br>
            } catch (Throwable ex) {<br>
                try {<br>
                    LOG_ERROR(ex.toString);<br>
                } catch (Throwable) {}<br>
                exit(1);<br>
            }<br>
            //assert(false);<br>
        }<br>
<br>
        // parent - wait for child to exit<br>
<br>
        int status = 0;<br>
        do {<br>
            errnoEnforce(waitpid(pid, &status, 0) != -1, "Waitpid failed");<br>
        } while (!WIFEXITED(status));<br>
<br>
        int rc = WEXITSTATUS(status);<br>
        return rc;<br>
    }, timeout);<br>
<br>
    enforce(rc == 0, "Child process failed (rc = %d)".format(rc));<br>
}<br>
```<br>
<br>
entryPoint() returns 0, but the exit(0) raises an OutOfMemoryError:<br>
```0x4e6472<br>
exit<br>
??:0<br>
0x4e6428<br>
__run_exit_handlers<br>
??:0<br>
0x4df976<br>
__libc_csu_fini<br>
??:0<br>
0x40327e<br>
ldc.register_dso<br>
crtstuff.c:0<br>
0x4caee4<br>
_d_dso_registry<br>
??:0<br>
0x4ccdba<br>
_D2rt4util9container6common8xr<wbr>eallocFNbNiPvmZPv<br>
??:0<br>
0x4b873d<br>
onOutOfMemoryError<br>
??:0```<br>
<br>
I tried to call Runtime.initialize() and Runtime.terminate() surrounding the call to entryPoint(), but this didn't help. I suspect calling initialize() was a no-op since the forked process shares (copy-on-write) the VM space with it's parent, that already initialized the runtime. (Note: confirmed, initialize() returns true indicating it was already inited).<br>
<br>
What is the correct way to handle fork() with the D runtime?<br>
</blockquote></div><br></div>