| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 | /* * 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;}
 |