Lock thread_pool.wait_mutex before forking to avoid a race condition between rad_fork...
authorJames Rouzier <jrouzier@inverse.ca>
Tue, 28 Oct 2014 21:13:43 +0000 (17:13 -0400)
committerJames Rouzier <jrouzier@inverse.ca>
Tue, 28 Oct 2014 21:13:43 +0000 (17:13 -0400)
There is a race condition that can occur under high load where a child is reaped before being added to the waiters list.

src/main/threads.c

index 72d849f..d4de4ff 100644 (file)
@@ -1142,6 +1142,7 @@ pid_t rad_fork(void)
        /*
         *      Fork & save the PID for later reaping.
         */
+       pthread_mutex_lock(&thread_pool.wait_mutex);
        child_pid = fork();
        if (child_pid > 0) {
                int rcode;
@@ -1152,9 +1153,7 @@ pid_t rad_fork(void)
 
                tf->pid = child_pid;
 
-               pthread_mutex_lock(&thread_pool.wait_mutex);
                rcode = fr_hash_table_insert(thread_pool.waiters, tf);
-               pthread_mutex_unlock(&thread_pool.wait_mutex);
 
                if (!rcode) {
                        radlog(L_ERR, "Failed to store PID, creating what will be a zombie process %d",
@@ -1162,6 +1161,12 @@ pid_t rad_fork(void)
                        free(tf);
                }
        }
+       /*
+        *      Do not unlock in child process
+        */
+       if(child_pid != 0 ) {
+               pthread_mutex_unlock(&thread_pool.wait_mutex);
+       }
 
        /*
         *      Return whatever we were told.