When a thread exits, run the destructors for the thread's specific data.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@330 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/arch/x86-linux/vg_libpthread.c b/coregrind/arch/x86-linux/vg_libpthread.c
index 7fba3b0..d98b730 100644
--- a/coregrind/arch/x86-linux/vg_libpthread.c
+++ b/coregrind/arch/x86-linux/vg_libpthread.c
@@ -279,8 +279,10 @@
__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 @@
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 6a078f6..290fbec 100644
--- a/coregrind/vg_include.h
+++ b/coregrind/vg_include.h
@@ -476,6 +476,7 @@
#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 7fba3b0..d98b730 100644
--- a/coregrind/vg_libpthread.c
+++ b/coregrind/vg_libpthread.c
@@ -279,8 +279,10 @@
__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 @@
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 7eeee51..60c6c28 100644
--- a/coregrind/vg_scheduler.c
+++ b/coregrind/vg_scheduler.c
@@ -2672,7 +2672,8 @@
" 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 @@
}
+/* 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*)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: