Implement thread cleanup stacks.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@329 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_libpthread.c b/coregrind/vg_libpthread.c
index b541d8b..7fba3b0 100644
--- a/coregrind/vg_libpthread.c
+++ b/coregrind/vg_libpthread.c
@@ -279,8 +279,19 @@
__attribute__((noreturn))
void thread_exit_wrapper ( void* ret_val )
{
- int detached, res;
+ int detached, res;
+ CleanupEntry cu;
/* Run this thread's cleanup handlers. */
+ while (1) {
+ VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
+ VG_USERREQ__CLEANUP_POP,
+ &cu, 0, 0, 0);
+ if (res == -1) break; /* stack empty */
+ assert(res == 0);
+ if (0) printf("running exit cleanup handler");
+ cu.fn ( cu.arg );
+ }
+
/* Run this thread's key finalizers. */
/* Decide on my final disposition. */
@@ -471,6 +482,94 @@
/* ---------------------------------------------------
+ CLEANUP STACKS
+ ------------------------------------------------ */
+
+void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
+ void (*__routine) (void *),
+ void *__arg)
+{
+ int res;
+ CleanupEntry cu;
+ ensure_valgrind("_pthread_cleanup_push");
+ cu.fn = __routine;
+ cu.arg = __arg;
+ VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
+ VG_USERREQ__CLEANUP_PUSH,
+ &cu, 0, 0, 0);
+ assert(res == 0);
+}
+
+
+void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
+ void (*__routine) (void *),
+ void *__arg)
+{
+ /* As _pthread_cleanup_push, but first save the thread's original
+ cancellation type in __buffer and set it to Deferred. */
+ int orig_ctype;
+ ensure_valgrind("_pthread_cleanup_push_defer");
+ /* Set to Deferred, and put the old cancellation type in res. */
+ assert(-1 != PTHREAD_CANCEL_DEFERRED);
+ assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
+ assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
+ VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
+ VG_USERREQ__SET_CANCELTYPE,
+ PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
+ assert(orig_ctype != -1);
+ *((int*)(__buffer)) = orig_ctype;
+ /* Now push the cleanup. */
+ _pthread_cleanup_push(NULL, __routine, __arg);
+}
+
+
+void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
+ int __execute)
+{
+ int res;
+ CleanupEntry cu;
+ ensure_valgrind("_pthread_cleanup_push");
+ cu.fn = cu.arg = NULL; /* paranoia */
+ VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
+ VG_USERREQ__CLEANUP_POP,
+ &cu, 0, 0, 0);
+ if (res == 0) {
+ /* pop succeeded */
+ if (__execute) {
+ cu.fn ( cu.arg );
+ }
+ return;
+ }
+ if (res == -1) {
+ /* stack underflow */
+ return;
+ }
+ barf("_pthread_cleanup_pop");
+}
+
+
+void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
+ int __execute)
+{
+ int orig_ctype, fake_ctype;
+ /* As _pthread_cleanup_pop, but after popping/running the handler,
+ restore the thread's original cancellation type from the first
+ word of __buffer. */
+ _pthread_cleanup_pop(NULL, __execute);
+ orig_ctype = *((int*)(__buffer));
+ assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
+ || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
+ assert(-1 != PTHREAD_CANCEL_DEFERRED);
+ assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
+ assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
+ VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
+ VG_USERREQ__SET_CANCELTYPE,
+ orig_ctype, 0, 0, 0);
+ assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
+}
+
+
+/* ---------------------------------------------------
MUTEX ATTRIBUTES
------------------------------------------------ */
@@ -2446,43 +2545,6 @@
weak_alias(_IO_funlockfile, funlockfile);
-void _pthread_cleanup_push_defer ( void )
-{
- static int moans = N_MOANS;
- if (moans-- > 0)
- ignored("_pthread_cleanup_push_defer");
-}
-
-void _pthread_cleanup_pop_restore ( void )
-{
- static int moans = N_MOANS;
- if (moans-- > 0)
- ignored("_pthread_cleanup_pop_restore");
-}
-
-/*--------*/
-void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
- void (*__routine) (void *),
- void *__arg)
-{
- static int moans = N_MOANS;
- if (moans-- > 0)
- ignored("_pthread_cleanup_push");
-}
-
-void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
- int __execute)
-{
- static int moans = N_MOANS;
- if (moans-- > 0) {
- if (__execute)
- ignored("_pthread_cleanup_pop-EXECUTE");
- else
- ignored("_pthread_cleanup_pop-NO-EXECUTE");
- }
-}
-
-
/* This doesn't seem to be needed to simulate libpthread.so's external
interface, but many people complain about its absence. */