/* * This illustrates the bug where the cleanup function * of a thread may be called too many times. * * main thread: * - grab mutex * - spawn thread1 * - go to sleep * thread1: * - register cleanup handler via pthread_cleanup_push() * - try to grab mutex and sleep * main: * - kill thread1 * - go to sleep * thread1 cleanup handler: * - try to grab mutex and sleep * main: * - kill thread1 * - go to sleep * thread1 cleanup handler: * - wrongly called again */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <assert.h> #include <unistd.h> #define warn(fmt, args...) fprintf(stderr, "[%p] " fmt, (void*)pthread_self(), ## args) #define warnf(fmt, args...) warn("%s:%i: " fmt, __FUNCTION__, __LINE__, ## args) int ok_to_kill_thread; static void thread_killed(void *arg); static void *KillMeThread(void *thread_par) { pthread_t pthread_id; warnf("Starting child thread\n"); pthread_id = pthread_self(); pthread_cleanup_push(thread_killed, (void *)pthread_id); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); /* main code */ warnf("please kill me now\n"); while (1) { ok_to_kill_thread = 1; sleep(1); } pthread_cleanup_pop(0); return 0; } static void thread_killed(void *arg) { static int num_times_called = 0; warnf("killing %p [cnt=%i]\n", arg, ++num_times_called); assert(num_times_called == 1); /* pick any cancellation endpoint, sleep() will do just fine */ while (1) { warnf("sleeping in cancellation endpoint ...\n"); sleep(1); } warnf("done cleaning up\n"); } int main(int argc, char *argv[]) { int count = 3; pthread_t app_pthread_id; /* need to tweak this test a bit to play nice with signals and LT */ return 0; ok_to_kill_thread = 0; pthread_create(&app_pthread_id, NULL, KillMeThread, NULL); warnf("waiting for thread to prepare itself\n"); while (!ok_to_kill_thread) sleep(1); while (count--) { warnf("killing thread\n"); pthread_cancel(app_pthread_id); sleep(3); } return 0; }