From 970241a11ad03f33fd2f8c3dcc8bf7e54a7d274f Mon Sep 17 00:00:00 2001 From: Dyami Caliri Date: Sun, 24 May 2015 09:04:24 -0700 Subject: Fix forkfd on OS X 10.7 and earlier by avoiding waitid altogether On OS X 10.7 and earlier, waitid() never sets si_pid, even when using P_PID. So on OS X, check if waitid() works, and if not, use the same codepath as if HAVE_WAITID were not defined. Change-Id: I64331a090f9358bb01f435954d3dfd3ab430a96c Reviewed-by: Thiago Macieira --- src/3rdparty/forkfd/forkfd.c | 56 +++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c index 017ae0741e..8d08f403ec 100644 --- a/src/3rdparty/forkfd/forkfd.c +++ b/src/3rdparty/forkfd/forkfd.c @@ -63,7 +63,7 @@ # include # include # if MAC_OS_X_VERSION_MIN_REQUIRED <= 1070 -# define HAVE_BROKEN_WAITID_ALL 1 +# define HAVE_BROKEN_WAITID 1 # endif #endif @@ -109,10 +109,10 @@ static struct sigaction old_sigaction; static pthread_once_t forkfd_initialization = PTHREAD_ONCE_INIT; static ffd_atomic_int forkfd_status = FFD_ATOMIC_INIT(0); -#ifdef HAVE_BROKEN_WAITID_ALL -static int waitid_p_all_works = 0; +#ifdef HAVE_BROKEN_WAITID +static int waitid_works = 0; #else -static const int waitid_p_all_works = 1; +static const int waitid_works = 1; #endif static ProcessInfo *tryAllocateInSection(Header *header, ProcessInfo entries[], int maxCount) @@ -183,10 +183,13 @@ static int tryReaping(pid_t pid, siginfo_t *info) { /* reap the child */ #ifdef HAVE_WAITID - // we have waitid(2), which fills in siginfo_t for us - info->si_pid = 0; - return waitid(P_PID, pid, info, WEXITED | WNOHANG) == 0 && info->si_pid == pid; -#else + if (waitid_works) { + // we have waitid(2), which fills in siginfo_t for us + info->si_pid = 0; + return waitid(P_PID, pid, info, WEXITED | WNOHANG) == 0 && info->si_pid == pid; + } +#endif + int status; if (waitpid(pid, &status, WNOHANG) <= 0) return 0; // child did not change state @@ -206,7 +209,6 @@ static int tryReaping(pid_t pid, siginfo_t *info) } return 1; -#endif } static void freeInfo(Header *header, ProcessInfo *entry) @@ -246,7 +248,7 @@ static void sigchld_handler(int signum) memset(&info, 0, sizeof info); #ifdef HAVE_WAITID - if (!waitid_p_all_works) + if (!waitid_works) goto search_arrays; /* be optimistic: try to see if we can get the child that exited */ @@ -310,12 +312,14 @@ search_arrays: if (pid <= 0) continue; #ifdef HAVE_WAITID - /* The child might have been reaped by the block above in another thread, - * so first check if it's ready and, if it is, lock it */ - if (!isChildReady(pid, &info) || - !ffd_atomic_compare_exchange(&children.entries[i].pid, &pid, -1, - FFD_ATOMIC_RELAXED, FFD_ATOMIC_RELAXED)) - continue; + if (waitid_works) { + /* The child might have been reaped by the block above in another thread, + * so first check if it's ready and, if it is, lock it */ + if (!isChildReady(pid, &info) || + !ffd_atomic_compare_exchange(&children.entries[i].pid, &pid, -1, + FFD_ATOMIC_RELAXED, FFD_ATOMIC_RELAXED)) + continue; + } #endif if (tryReaping(pid, &info)) { /* this is our child, send notification and free up this entry */ @@ -331,12 +335,14 @@ search_arrays: if (pid <= 0) continue; #ifdef HAVE_WAITID - /* The child might have been reaped by the block above in another thread, - * so first check if it's ready and, if it is, lock it */ - if (!isChildReady(pid, &info) || - !ffd_atomic_compare_exchange(&array->entries[i].pid, &pid, -1, - FFD_ATOMIC_RELAXED, FFD_ATOMIC_RELAXED)) - continue; + if (waitid_works) { + /* The child might have been reaped by the block above in another thread, + * so first check if it's ready and, if it is, lock it */ + if (!isChildReady(pid, &info) || + !ffd_atomic_compare_exchange(&array->entries[i].pid, &pid, -1, + FFD_ATOMIC_RELAXED, FFD_ATOMIC_RELAXED)) + continue; + } #endif if (tryReaping(pid, &info)) { /* this is our child, send notification and free up this entry */ @@ -357,17 +363,19 @@ chain_handler: static void forkfd_initialize() { -#if defined(HAVE_BROKEN_WAITID_ALL) +#if defined(HAVE_BROKEN_WAITID) pid_t pid = fork(); if (pid == 0) { _exit(0); } else if (pid > 0) { siginfo_t info; waitid(P_ALL, 0, &info, WNOWAIT | WEXITED); - waitid_p_all_works = (info.si_pid != 0); + waitid_works = (info.si_pid != 0); + info.si_pid = 0; // now really reap the child waitid(P_PID, pid, &info, WEXITED); + waitid_works = waitid_works && (info.si_pid != 0); } #endif -- cgit v1.2.3