Browse Source

Improve reaping of zombie processes on linux (resolves #1042)

Sadly, it's not a complete fix for #1042, as there seems to be no good way to
deal with system() in multithreaded applications. At least os.execute can
return values other than -1 now.
Bart van Strien 9 years ago
parent
commit
f7d226d072
1 changed files with 20 additions and 4 deletions
  1. 20 4
      src/modules/system/System.cpp

+ 20 - 4
src/modules/system/System.cpp

@@ -41,6 +41,20 @@
 #pragma comment(lib, "shell32.lib")
 #pragma comment(lib, "shell32.lib")
 #endif
 #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 love
 {
 {
 namespace system
 namespace system
@@ -50,12 +64,14 @@ System::System()
 {
 {
 #if defined(LOVE_LINUX)
 #if defined(LOVE_LINUX)
 	// Enable automatic cleanup of zombie processes
 	// 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};
 	struct sigaction act = {0};
 	sigemptyset(&act.sa_mask);
 	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);
 	sigaction(SIGCHLD, &act, nullptr);
 #endif
 #endif
 }
 }