Skip to content

Commit 9190155

Browse files
PeteLewisUnityjoncham
authored andcommitted
Only call waitpid for processes that Mono tracks, rather than all child processes owned by the calling process. (mono#6202)
waitpid(-1,...) reaps all zombie child processes of the calling process (see `man waitpid`). After a child process is reaped, it can no longer be queried. Because this reaping step is invoked via the `SIGCHLD` signal, all zombie children of the calling process are reaped every time any child process terminates, regardless of whether that child process was tracked by Mono. The impact of this bug is that apps using Mono that spawn their own child processes (outside of Mono's `w32process` API) cannot query the exit state of its children. For example, a call to `waitpid(my_child_pid,...)` will return `ECHILD` for "no such child" because Mono has already cleaned up the child the moment `SIGCHLD` was raised.
1 parent 6922252 commit 9190155

File tree

1 file changed

+22
-21
lines changed

1 file changed

+22
-21
lines changed

mono/metadata/w32process-unix.c

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,34 +1401,35 @@ process_add_sigchld_handler (void)
14011401
void
14021402
mono_w32process_signal_finished (void)
14031403
{
1404-
int status;
1405-
int pid;
1406-
Process *process;
1404+
mono_coop_mutex_lock (&processes_mutex);
1405+
1406+
for (Process* process = processes; process; process = process->next) {
1407+
int status = -1;
1408+
int pid;
14071409

1408-
do {
14091410
do {
1410-
pid = waitpid (-1, &status, WNOHANG);
1411+
pid = waitpid (process->pid, &status, WNOHANG);
14111412
} while (pid == -1 && errno == EINTR);
14121413

1413-
if (pid <= 0)
1414-
break;
1415-
1416-
mono_coop_mutex_lock (&processes_mutex);
1414+
// possible values of 'pid':
1415+
// process->pid : the status changed for this child
1416+
// 0 : status unchanged for this PID
1417+
// ECHILD : process has been reaped elsewhere (or never existed)
1418+
// EINVAL : invalid PID or other argument
14171419

1418-
for (process = processes; process; process = process->next) {
1419-
if (process->pid != pid)
1420-
continue;
1421-
if (process->signalled)
1422-
continue;
1420+
// Therefore, we ignore status unchanged (nothing to do) and error
1421+
// events (process is cleaned up later).
1422+
if (pid <= 0)
1423+
continue;
1424+
if (process->signalled)
1425+
continue;
14231426

1424-
process->signalled = TRUE;
1425-
process->status = status;
1426-
mono_coop_sem_post (&process->exit_sem);
1427-
break;
1428-
}
1427+
process->signalled = TRUE;
1428+
process->status = status;
1429+
mono_coop_sem_post (&process->exit_sem);
1430+
}
14291431

1430-
mono_coop_mutex_unlock (&processes_mutex);
1431-
} while (1);
1432+
mono_coop_mutex_unlock (&processes_mutex);
14321433
}
14331434

14341435
static gboolean

0 commit comments

Comments
 (0)