forkfd: dynamically detect whether the Darwin waitid is broken
The Darwin kernel that came with Mac OS X 10.7 has a broken implementation of waitid when passed a P_ALL first argument. It does tell us that there is a process that can be wait()ed, but does not fill in the siginfo_t structure. See commit 9931fa9df4cb96a4006a3390db64f87e3b5bc1a0 for more information. Change-Id: Iee8cbc07c4434ce9b560ffff13cafa4c88cdabd6 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
This commit is contained in:
parent
bb5d287cc3
commit
4da46bbb9a
35
src/3rdparty/forkfd/forkfd.c
vendored
35
src/3rdparty/forkfd/forkfd.c
vendored
@ -58,6 +58,10 @@
|
|||||||
# include <sys/eventfd.h>
|
# include <sys/eventfd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if _POSIX_VERSION-0 >= 200809L || _XOPEN_VERSION-0 >= 500
|
||||||
|
# define HAVE_WAITID 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
/* Up until OS X 10.7, waitid(P_ALL, ...) will return success, but will not
|
/* Up until OS X 10.7, waitid(P_ALL, ...) will return success, but will not
|
||||||
* fill in the details of the dead child. That means waitid is not useful to us.
|
* fill in the details of the dead child. That means waitid is not useful to us.
|
||||||
@ -66,11 +70,9 @@
|
|||||||
*/
|
*/
|
||||||
# include <Availability.h>
|
# include <Availability.h>
|
||||||
# include <AvailabilityMacros.h>
|
# include <AvailabilityMacros.h>
|
||||||
# if MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
|
# if MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
|
||||||
# define HAVE_WAITID 1
|
# define HAVE_BROKEN_WAITID_ALL 1
|
||||||
# endif
|
# endif
|
||||||
#elif _POSIX_VERSION-0 >= 200809L || _XOPEN_VERSION-0 >= 500
|
|
||||||
# define HAVE_WAITID 1
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef FFD_ATOMIC_RELAXED
|
#ifndef FFD_ATOMIC_RELAXED
|
||||||
@ -115,6 +117,12 @@ static struct sigaction old_sigaction;
|
|||||||
static pthread_once_t forkfd_initialization = PTHREAD_ONCE_INIT;
|
static pthread_once_t forkfd_initialization = PTHREAD_ONCE_INIT;
|
||||||
static ffd_atomic_int forkfd_status = FFD_ATOMIC_INIT(0);
|
static ffd_atomic_int forkfd_status = FFD_ATOMIC_INIT(0);
|
||||||
|
|
||||||
|
#ifdef HAVE_BROKEN_WAITID_ALL
|
||||||
|
static int waitid_p_all_works = 0;
|
||||||
|
#else
|
||||||
|
static const int waitid_p_all_works = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
static ProcessInfo *tryAllocateInSection(Header *header, ProcessInfo entries[], int maxCount)
|
static ProcessInfo *tryAllocateInSection(Header *header, ProcessInfo entries[], int maxCount)
|
||||||
{
|
{
|
||||||
/* we use ACQUIRE here because the signal handler might have released the PID */
|
/* we use ACQUIRE here because the signal handler might have released the PID */
|
||||||
@ -246,6 +254,9 @@ static void sigchld_handler(int signum)
|
|||||||
memset(&info, 0, sizeof info);
|
memset(&info, 0, sizeof info);
|
||||||
|
|
||||||
#ifdef HAVE_WAITID
|
#ifdef HAVE_WAITID
|
||||||
|
if (!waitid_p_all_works)
|
||||||
|
goto search_arrays;
|
||||||
|
|
||||||
/* be optimistic: try to see if we can get the child that exited */
|
/* be optimistic: try to see if we can get the child that exited */
|
||||||
search_next_child:
|
search_next_child:
|
||||||
/* waitid returns -1 ECHILD if there are no further children at all;
|
/* waitid returns -1 ECHILD if there are no further children at all;
|
||||||
@ -298,6 +309,8 @@ search_next_child:
|
|||||||
* belongs to one of the chained SIGCHLD handlers. However, there might be another
|
* belongs to one of the chained SIGCHLD handlers. However, there might be another
|
||||||
* child that exited and does belong to us, so we need to check each one individually.
|
* child that exited and does belong to us, so we need to check each one individually.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
search_arrays:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (i = 0; i < (int)sizeofarray(children.entries); ++i) {
|
for (i = 0; i < (int)sizeofarray(children.entries); ++i) {
|
||||||
@ -352,6 +365,20 @@ chain_handler:
|
|||||||
|
|
||||||
static void forkfd_initialize()
|
static void forkfd_initialize()
|
||||||
{
|
{
|
||||||
|
#if defined(HAVE_BROKEN_WAITID_ALL)
|
||||||
|
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);
|
||||||
|
|
||||||
|
// now really reap the child
|
||||||
|
waitid(P_PID, pid, &info, WEXITED);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* install our signal handler */
|
/* install our signal handler */
|
||||||
struct sigaction action;
|
struct sigaction action;
|
||||||
memset(&action, 0, sizeof action);
|
memset(&action, 0, sizeof action);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user