[WEKA] Calling fork() and D runtime

via Digitalmars-d digitalmars-d at puremagic.com
Sun May 21 15:50:49 PDT 2017


On Monday, 15 May 2017 at 11:33:29 UTC, Jonathan Shamir wrote:
> 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?

Some links to related discussions:
https://issues.dlang.org/show_bug.cgi?id=14205
http://forum.dlang.org/thread/ksqubftqniwznqbmurrk@forum.dlang.org
https://issues.dlang.org/show_bug.cgi?id=14770
https://issues.dlang.org/show_bug.cgi?id=16006
https://github.com/dlang/phobos/pull/4294
https://github.com/dlang/druntime/pull/1569


More information about the Digitalmars-d mailing list