This is the mail archive of the libc-alpha@sources.redhat.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Make exit thread-safe


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, ());


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]