Hey,

This is my first time writing in the D forums!

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). 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.

So, normally, implementing such an application would look something like: 1. Main "agent" process runs fork() to create a child process (child_1). All memory is copy-on-write. 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. 3. Child_2 initializes the container (mounts, unshare, chroot, etc) then eventually exec()s into the container init process.
4. child_1 exit()s, which causes child_2 to become a daemon.
5. The agent main process should wait() on the forked pid since it's impolite to leave zombies (I do this in a thread).

The problem I encounter is with the forked process (child_1).

Here is the code I wrote handling the fork() (Note: this functionality should really be provided by core.threads or something, for unix environments).

```private void deferToForkProcess(int delegate() entryPoint, Timeout timeout = Timeout.infinite) {
    import core.runtime : Runtime;
    import core.sys.posix.unistd : fork, pid_t;
    import core.sys.posix.sys.wait;
    import core.stdc.stdlib : exit;

    int rc = theReactor.deferToThread({
        pid_t pid = fork();
        errnoEnforce(pid >= 0, "Fork failed");

        // child process
        if (pid == 0) {
            try {
                int rc = entryPoint();
                exit(rc);
            } catch (Throwable ex) {
                try {
                    LOG_ERROR(ex.toString);
                } catch (Throwable) {}
                exit(1);
            }
            //assert(false);
        }

        // parent - wait for child to exit

        int status = 0;
        do {
errnoEnforce(waitpid(pid, &status, 0) != -1, "Waitpid failed");
        } while (!WIFEXITED(status));

        int rc = WEXITSTATUS(status);
        return rc;
    }, timeout);

    enforce(rc == 0, "Child process failed (rc = %d)".format(rc));
}
```

entryPoint() returns 0, but the exit(0) raises an OutOfMemoryError:
```0x4e6472
exit
??:0
0x4e6428
__run_exit_handlers
??:0
0x4df976
__libc_csu_fini
??:0
0x40327e
ldc.register_dso
crtstuff.c:0
0x4caee4
_d_dso_registry
??:0
0x4ccdba
_D2rt4util9container6common8xreallocFNbNiPvmZPv
??:0
0x4b873d
onOutOfMemoryError
??:0```

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).

What is the correct way to handle fork() with the D runtime?

Reply via email to