From: Julian Seward Date: Wed, 29 May 2002 01:06:47 +0000 (+0000) Subject: When a thread exits, run the destructors for the thread's specific data. X-Git-Tag: svn/VALGRIND_1_0_3~136 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6471fc14ca0cd07a0901d531cf17ed3716d942fb;p=thirdparty%2Fvalgrind.git When a thread exits, run the destructors for the thread's specific data. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@330 --- diff --git a/coregrind/arch/x86-linux/vg_libpthread.c b/coregrind/arch/x86-linux/vg_libpthread.c index 7fba3b0f80..d98b73076a 100644 --- a/coregrind/arch/x86-linux/vg_libpthread.c +++ b/coregrind/arch/x86-linux/vg_libpthread.c @@ -279,8 +279,10 @@ static __attribute__((noreturn)) void thread_exit_wrapper ( void* ret_val ) { - int detached, res; - CleanupEntry cu; + int detached, res; + CleanupEntry cu; + pthread_key_t key; + /* Run this thread's cleanup handlers. */ while (1) { VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */, @@ -292,7 +294,21 @@ void thread_exit_wrapper ( void* ret_val ) cu.fn ( cu.arg ); } - /* Run this thread's key finalizers. */ + /* Run this thread's key finalizers. Really this should be run + PTHREAD_DESTRUCTOR_ITERATIONS times. */ + for (key = 0; key < VG_N_THREAD_KEYS; key++) { + VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */, + VG_USERREQ__GET_KEY_D_AND_S, + key, &cu, 0, 0 ); + if (res == 0) { + /* valid key */ + if (cu.fn && cu.arg) + cu.fn /* destructor for key */ + ( cu.arg /* specific for key for this thread */ ); + continue; + } + assert(res == -1); + } /* Decide on my final disposition. */ VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */, diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h index 6a078f631c..290fbec739 100644 --- a/coregrind/vg_include.h +++ b/coregrind/vg_include.h @@ -476,6 +476,7 @@ extern Bool VG_(is_empty_arena) ( ArenaId aid ); #define VG_USERREQ__CLEANUP_PUSH 0x3020 #define VG_USERREQ__CLEANUP_POP 0x3021 +#define VG_USERREQ__GET_KEY_D_AND_S 0x3022 /* Cosmetic ... */ #define VG_USERREQ__GET_PTHREAD_TRACE_LEVEL 0x3101 diff --git a/coregrind/vg_libpthread.c b/coregrind/vg_libpthread.c index 7fba3b0f80..d98b73076a 100644 --- a/coregrind/vg_libpthread.c +++ b/coregrind/vg_libpthread.c @@ -279,8 +279,10 @@ static __attribute__((noreturn)) void thread_exit_wrapper ( void* ret_val ) { - int detached, res; - CleanupEntry cu; + int detached, res; + CleanupEntry cu; + pthread_key_t key; + /* Run this thread's cleanup handlers. */ while (1) { VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */, @@ -292,7 +294,21 @@ void thread_exit_wrapper ( void* ret_val ) cu.fn ( cu.arg ); } - /* Run this thread's key finalizers. */ + /* Run this thread's key finalizers. Really this should be run + PTHREAD_DESTRUCTOR_ITERATIONS times. */ + for (key = 0; key < VG_N_THREAD_KEYS; key++) { + VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */, + VG_USERREQ__GET_KEY_D_AND_S, + key, &cu, 0, 0 ); + if (res == 0) { + /* valid key */ + if (cu.fn && cu.arg) + cu.fn /* destructor for key */ + ( cu.arg /* specific for key for this thread */ ); + continue; + } + assert(res == -1); + } /* Decide on my final disposition. */ VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */, diff --git a/coregrind/vg_scheduler.c b/coregrind/vg_scheduler.c index 7eeee5181c..60c6c28e88 100644 --- a/coregrind/vg_scheduler.c +++ b/coregrind/vg_scheduler.c @@ -2672,7 +2672,8 @@ void do_pthread_key_create ( ThreadId tid, " increase and recompile"); } - vg_thread_keys[i].inuse = True; + vg_thread_keys[i].inuse = True; + vg_thread_keys[i].destructor = destructor; /* TODO: check key for addressibility */ *key = i; @@ -2762,6 +2763,33 @@ void do_pthread_setspecific ( ThreadId tid, } +/* Helper for calling destructors at thread exit. If key is valid, + copy the thread's specific value into cu->arg and put the *key*'s + destructor fn address in cu->fn. Then return 0 to the caller. + Otherwise return non-zero to the caller. */ +static +void do__get_key_destr_and_spec ( ThreadId tid, + pthread_key_t key, + CleanupEntry* cu ) +{ + Char msg_buf[100]; + if (VG_(clo_trace_pthread_level) >= 1) { + VG_(sprintf)(msg_buf, + "get_key_destr_and_arg (key = %d)", key ); + print_pthread_event(tid, msg_buf); + } + vg_assert(VG_(is_valid_tid)(tid)); + vg_assert(key >= 0 && key < VG_N_THREAD_KEYS); + if (!vg_thread_keys[key].inuse) { + SET_EDX(tid, -1); + return; + } + cu->fn = vg_thread_keys[key].destructor; + cu->arg = VG_(threads)[tid].specifics[key]; + SET_EDX(tid, 0); +} + + /* --------------------------------------------------- SIGNALS ------------------------------------------------ */ @@ -2971,6 +2999,12 @@ void do_nontrivial_clientreq ( ThreadId tid ) (void*)arg[2] ); break; + case VG_USERREQ__GET_KEY_D_AND_S: + do__get_key_destr_and_spec ( tid, + (pthread_key_t)arg[1], + (CleanupEntry*)arg[2] ); + break; + case VG_USERREQ__MAKE_NOACCESS: case VG_USERREQ__MAKE_WRITABLE: case VG_USERREQ__MAKE_READABLE: diff --git a/vg_include.h b/vg_include.h index 6a078f631c..290fbec739 100644 --- a/vg_include.h +++ b/vg_include.h @@ -476,6 +476,7 @@ extern Bool VG_(is_empty_arena) ( ArenaId aid ); #define VG_USERREQ__CLEANUP_PUSH 0x3020 #define VG_USERREQ__CLEANUP_POP 0x3021 +#define VG_USERREQ__GET_KEY_D_AND_S 0x3022 /* Cosmetic ... */ #define VG_USERREQ__GET_PTHREAD_TRACE_LEVEL 0x3101 diff --git a/vg_libpthread.c b/vg_libpthread.c index 7fba3b0f80..d98b73076a 100644 --- a/vg_libpthread.c +++ b/vg_libpthread.c @@ -279,8 +279,10 @@ static __attribute__((noreturn)) void thread_exit_wrapper ( void* ret_val ) { - int detached, res; - CleanupEntry cu; + int detached, res; + CleanupEntry cu; + pthread_key_t key; + /* Run this thread's cleanup handlers. */ while (1) { VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */, @@ -292,7 +294,21 @@ void thread_exit_wrapper ( void* ret_val ) cu.fn ( cu.arg ); } - /* Run this thread's key finalizers. */ + /* Run this thread's key finalizers. Really this should be run + PTHREAD_DESTRUCTOR_ITERATIONS times. */ + for (key = 0; key < VG_N_THREAD_KEYS; key++) { + VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */, + VG_USERREQ__GET_KEY_D_AND_S, + key, &cu, 0, 0 ); + if (res == 0) { + /* valid key */ + if (cu.fn && cu.arg) + cu.fn /* destructor for key */ + ( cu.arg /* specific for key for this thread */ ); + continue; + } + assert(res == -1); + } /* Decide on my final disposition. */ VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */, diff --git a/vg_scheduler.c b/vg_scheduler.c index 7eeee5181c..60c6c28e88 100644 --- a/vg_scheduler.c +++ b/vg_scheduler.c @@ -2672,7 +2672,8 @@ void do_pthread_key_create ( ThreadId tid, " increase and recompile"); } - vg_thread_keys[i].inuse = True; + vg_thread_keys[i].inuse = True; + vg_thread_keys[i].destructor = destructor; /* TODO: check key for addressibility */ *key = i; @@ -2762,6 +2763,33 @@ void do_pthread_setspecific ( ThreadId tid, } +/* Helper for calling destructors at thread exit. If key is valid, + copy the thread's specific value into cu->arg and put the *key*'s + destructor fn address in cu->fn. Then return 0 to the caller. + Otherwise return non-zero to the caller. */ +static +void do__get_key_destr_and_spec ( ThreadId tid, + pthread_key_t key, + CleanupEntry* cu ) +{ + Char msg_buf[100]; + if (VG_(clo_trace_pthread_level) >= 1) { + VG_(sprintf)(msg_buf, + "get_key_destr_and_arg (key = %d)", key ); + print_pthread_event(tid, msg_buf); + } + vg_assert(VG_(is_valid_tid)(tid)); + vg_assert(key >= 0 && key < VG_N_THREAD_KEYS); + if (!vg_thread_keys[key].inuse) { + SET_EDX(tid, -1); + return; + } + cu->fn = vg_thread_keys[key].destructor; + cu->arg = VG_(threads)[tid].specifics[key]; + SET_EDX(tid, 0); +} + + /* --------------------------------------------------- SIGNALS ------------------------------------------------ */ @@ -2971,6 +2999,12 @@ void do_nontrivial_clientreq ( ThreadId tid ) (void*)arg[2] ); break; + case VG_USERREQ__GET_KEY_D_AND_S: + do__get_key_destr_and_spec ( tid, + (pthread_key_t)arg[1], + (CleanupEntry*)arg[2] ); + break; + case VG_USERREQ__MAKE_NOACCESS: case VG_USERREQ__MAKE_WRITABLE: case VG_USERREQ__MAKE_READABLE: