@@ -95,6 +95,13 @@ static gchar** _add_shadow_pid_to_env(gchar** envp) {
9595
9696static pid_t _threadpreload_fork_exec (ThreadPreload * thread , const char * file , char * const argv [],
9797 char * const envp [], const char * workingDir ) {
98+ // For childpidwatcher. We must create them O_CLOEXEC to prevent them from
99+ // "leaking" into a concurrently forked child.
100+ int pipefd [2 ];
101+ if (pipe2 (pipefd , O_CLOEXEC )) {
102+ utility_panic ("pipe2: %s" , g_strerror (errno ));
103+ }
104+
98105 // vfork has superior performance to fork with large workloads.
99106 pid_t pid = vfork ();
100107
@@ -111,6 +118,11 @@ static pid_t _threadpreload_fork_exec(ThreadPreload* thread, const char* file, c
111118 case 0 : {
112119 // child
113120
121+ // *Don't* close the write end of the pipe on exec.
122+ if (fcntl (pipefd [1 ], F_SETFD , 0 )) {
123+ die_after_vfork ();
124+ }
125+
114126 // Set the working directory
115127 if (chdir (workingDir ) < 0 ) {
116128 die_after_vfork ();
@@ -124,10 +136,20 @@ static pid_t _threadpreload_fork_exec(ThreadPreload* thread, const char* file, c
124136 die_after_vfork ();
125137 }
126138 default : // parent
127- debug ("started process %s with PID %d" , file , pid );
128- return pid ;
129139 break ;
130140 }
141+
142+ // *Must* close the write-end of the pipe, so that the child's copy is the
143+ // last remaining one, allowing the read-end to be notified when the child
144+ // exits.
145+ if (close (pipefd [1 ])) {
146+ utility_panic ("close: %s" , g_strerror (errno ));
147+ }
148+
149+ childpidwatcher_registerPid (worker_getChildPidWatcher (), pid , pipefd [0 ]);
150+
151+ debug ("started process %s with PID %d" , file , pid );
152+ return pid ;
131153}
132154
133155static void _threadpreload_cleanup (ThreadPreload * thread ) {
@@ -314,6 +336,8 @@ void threadpreload_handleProcessExit(Thread* base) {
314336 ThreadPreload * thread = _threadToThreadPreload (base );
315337 // TODO [rwails]: come back and make this logic more solid
316338
339+ childpidwatcher_unregisterPid (worker_getChildPidWatcher (), base -> nativePid );
340+
317341 /* make sure we cleanup circular refs */
318342 if (thread -> base .sys ) {
319343 syscallhandler_unref (thread -> base .sys );
0 commit comments