diff --git a/src/modules/system/System.cpp b/src/modules/system/System.cpp index 61e2ef742..cd71bdbde 100755 --- a/src/modules/system/System.cpp +++ b/src/modules/system/System.cpp @@ -41,6 +41,20 @@ #pragma comment(lib, "shell32.lib") #endif +#if defined(LOVE_LINUX) +static void sigchld_handler(int sig) +{ + // Because waitpid can set errno, we need to save it. + auto old = errno; + + // Reap whilst there are children waiting to be reaped. + while (waitpid(-1, nullptr, WNOHANG) > 0) + ; + + errno = old; +} +#endif + namespace love { namespace system @@ -50,12 +64,14 @@ System::System() { #if defined(LOVE_LINUX) // Enable automatic cleanup of zombie processes + // NOTE: We're using our own handler, instead of SA_NOCLDWAIT because the + // latter breaks wait, and thus os.execute. + // NOTE: This isn't perfect, due to multithreading our SIGCHLD can happen + // on a different thread than the one calling wait(), thus causing a race. struct sigaction act = {0}; sigemptyset(&act.sa_mask); - act.sa_handler = SIG_DFL; - act.sa_flags = SA_NOCLDWAIT; - - // Requires linux 2.6 or higher, so anything remotely modern + act.sa_handler = sigchld_handler; + act.sa_flags = SA_RESTART; sigaction(SIGCHLD, &act, nullptr); #endif }