[PATCH] Make exit thread-safe

Sripathi Kodi sripathik@in.ibm.com
Thu Feb 24 09:40:00 GMT 2005


Hi,

I have noticed that exit() in stdlib/exit.c is not thread-safe. I have a 
testcase that creates 10 threads, and they all call 'exit' almost 
immediately. I saw that multiple threads walk the __exit_funcs link list 
simultaneously and remove it's elements, but the list has no locks to 
protect it. Eventually one of the threads receives a SEGV. I have seen 
this problem only on SMP, but I think it could happen on uniprocessor 
machine as well. My testcase gets a SEGV 3-5 times out of 10.

I have noticed that there are no restrictions in POSIX on calls to 
exit() based on threads, hence I think we need to take care of this 
situation.  I am attaching a testcase that demonstrates the problem. I 
am also attaching a patch that adds a lock to be held while walking the 
__exit_funcs link list. Please let me know if the patch is alright.

Thanks and regards,
Sripathi.

Testcase:
---------
#include <pthread.h>
#include <stdio.h>

#define NUM_THREADS     10
void *Thread(void *v)
{
   int x;
   x = 1;
   exit(10);
}

int
main(int argc, char **argv)
{
   int  i, n[NUM_THREADS];
   pthread_t  e_th[NUM_THREADS];
   int  rc;

   for (i=0; i<NUM_THREADS; i++) {
     n[i] = i + 1;
     if (rc = pthread_create(&e_th[i], NULL, Thread, (void *)&n[i])) {
       fprintf(stderr, "pthread_create failed <%d>.\n", rc);
       exit(-1);
     }
   }

   for (i=0; i<NUM_THREADS; i++) {
     if (rc = pthread_join(e_th[i], NULL)) {
       fprintf(stderr, "pthread_join failed <%d>.\n", rc);
       exit(-1);
     }
   }
}

Patch:
------
2005-02-25  Sripathi Kodi  <sripathik@in.ibm.com>
	* stdlib/exit.c: New lock in exit()

--- glibc-2.3.4/stdlib/exit.c	2002-08-03 18:29:00.000000000 +0530
+++ /home/sripathi/13981/patch_2.3.4/exit.c	2005-02-22 
15:35:42.941454496 +0530
@@ -20,12 +20,14 @@
  #include <stdlib.h>
  #include <unistd.h>
  #include "exit.h"
+#include <bits/libc-lock.h>

  #ifdef HAVE_GNU_LD
  #include "set-hooks.h"
  DEFINE_HOOK (__libc_atexit, (void))
  #endif

+__libc_lock_define_initialized (static, exit_lock)

  /* Call all functions registered with `atexit' and `on_exit',
     in the reverse of the order in which they were registered
@@ -37,6 +39,7 @@ exit (int status)
       the functions registered with `atexit' and `on_exit'. We call
       everyone on the list and use the status value in the last
       exit (). */
+  __libc_lock_lock(exit_lock);
    while (__exit_funcs != NULL)
      {
        struct exit_function_list *old;
@@ -69,6 +72,7 @@ exit (int status)
  	   allocate element.  */
  	free (old);
      }
+  __libc_lock_unlock(exit_lock);

  #ifdef	HAVE_GNU_LD
    RUN_HOOK (__libc_atexit, ());



More information about the Libc-alpha mailing list