This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
[PATCH] Make exit thread-safe
- From: Sripathi Kodi <sripathik at in dot ibm dot com>
- To: libc-alpha at sources dot redhat dot com
- Date: Thu, 24 Feb 2005 14:51:00 +0530
- Subject: [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, ());