From: Julian Seward Date: Wed, 29 May 2002 20:47:19 +0000 (+0000) Subject: Tests for cancellation/cleanup mechanisms. X-Git-Tag: svn/VALGRIND_1_0_3~129 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=05cbb83b34f63cd4f41716e605beb81250aad2f3;p=thirdparty%2Fvalgrind.git Tests for cancellation/cleanup mechanisms. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@337 --- diff --git a/tests/Makefile.am b/tests/Makefile.am index 21a8d20a81..8770a85c20 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -29,4 +29,5 @@ EXTRA_DIST = \ pth_threadpool.c pth_specific.c pth_mutexspeed.c malloc3.c \ pth_once.c weirdioctl.c pth_signal1.c pth_signal2.c \ discard.c pth_semaphore1.c new_override.cpp pth_yield.c \ - sigaltstack.c erringfds.c sigwait_all.c + sigaltstack.c erringfds.c sigwait_all.c \ + pth_cancel1.c pth_cancel2.c diff --git a/tests/pth_cancel1.c b/tests/pth_cancel1.c new file mode 100644 index 0000000000..b8802c6af2 --- /dev/null +++ b/tests/pth_cancel1.c @@ -0,0 +1,274 @@ +/******************************************************** + * An example source module to accompany... + * + * "Using POSIX Threads: Programming with Pthreads" + * by Brad nichols, Dick Buttlar, Jackie Farrell + * O'Reilly & Associates, Inc. + * + ******************************************************** + * cancel.c -- + * + * Demonstrates pthread cancellation. + * + */ + +#include +#include +#include +#include + +#include + +#define NUM_THREADS 3 +#define MESSAGE_MAX_LEN 80 + +int count=NUM_THREADS; /* number of threads active */ +pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER; /* mutual exclusion + for count */ +pthread_cond_t init_done=PTHREAD_COND_INITIALIZER; /* signaled by + each thread after + completing initial- + ization */ +int id_arg[3] = {0,1,2}; + +/* + * Cleanup routine: last_breath() + */ +void last_breath(char *messagep) +{ + printf("\n\n%s last_breath() cleanup routine: free'ing %p\n\n", + messagep, messagep); + + free(messagep); +} + +/* + * print_count() + */ +void print_count(char *messagep, int id, int i) +{ + int last_type,tmp_type; + + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_type); + switch(id) { + case 0: + printf("%s %4d\n", messagep, i); + break; + case 1: + printf("%s \t%4d\n", messagep, i); + break; + case 2: + printf("%s \t\t%4d\n", messagep, i); + break; + } + pthread_setcanceltype(last_type, &tmp_type); +} + +/* + * bullet_proof() + */ +void *bullet_proof(void *id_p) +{ + int i=0, last_state; + int *my_id = id_p; + char *messagep; + + + messagep = (char *)malloc(MESSAGE_MAX_LEN); + sprintf(messagep, "Bullet Proof, thread #%d: ", *my_id); + + printf("%s\tI'm Alive, setting general cancellation OFF\n", + messagep); + + /* push last_breath() routine onto stack */ + pthread_cleanup_push( (void *)last_breath, (void *)messagep ); + + /* We turn off general cancelability here ... */ + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &last_state); + + pthread_mutex_lock(&lock); + { + printf("\n%s signaling main that my init is done\n", messagep); + count -= 1; + /* signal to program that entering loop */ + pthread_cond_signal(&init_done); + pthread_mutex_unlock(&lock); + } + + /* loop forever until picked off with a cancel */ + for(;;i++) { + if (i%1000 == 0) + print_count(messagep, *my_id, i); + if (i%100000 == 0) { + printf("\n%s This is the thread that never ends... #%d\n", + messagep, i); + } + } + + /* Never get this far */ + + /* This pop is required by the standard, every push must have a pop + in the same lexical block. */ + pthread_cleanup_pop(0); + + return(NULL); +} + +/* + * ask_for_it() + */ +void *ask_for_it(void *id_p) +{ + int i=0, last_state, last_type; + int *my_id = id_p; + char *messagep; + + + messagep = (char *)malloc(MESSAGE_MAX_LEN); + sprintf(messagep, "Ask For It, thread #%d: ", *my_id); + + /* push last_breath() routine onto stack */ + pthread_cleanup_push( (void *)last_breath, (void *)messagep); + + /* We can turn on general cancelability here. Disable async cancellation */ + printf("%s\tI'm Alive, setting deferred cancellation ON\n", + messagep); + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_type); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_state); + + pthread_mutex_lock(&lock); + { + printf("\n%s signaling main that my init is done\n", messagep); + count -= 1; + /* signal to program that entering loop */ + pthread_cond_signal(&init_done); + pthread_mutex_unlock(&lock); + } + + /* loop forever until picked off with a cancel */ + for(;;i++) { + if (i%1000 == 0) + print_count(messagep, *my_id, i); + if (i%10000 == 0) { + printf("\n%s\tLook, %d, I'll tell you when you can cancel me.\n", + messagep, i); + } + pthread_testcancel(); + } + + /* never get this far */ + + /* This pop is required by the standard, every push must have a pop + in the same lexical block. */ + pthread_cleanup_pop(0); + + return(NULL); +} + +/* + * sitting_duck() + */ +void *sitting_duck(void *id_p) +{ + int i=0, last_state, last_type, last_tmp; + int *my_id = id_p; + char *messagep; + + + messagep = (char *)malloc(MESSAGE_MAX_LEN); + sprintf(messagep, "Sitting Duck, thread #%d: ", *my_id); + + /* push last_breath() routine onto stack */ + pthread_cleanup_push( (void *)last_breath, (void *)messagep); + + pthread_mutex_lock(&lock); + { + printf("\n%s signaling main that my init is done\n", messagep); + count -= 1; + /* signal to program that entering loop */ + pthread_cond_signal(&init_done); + pthread_mutex_unlock(&lock); + } + + /* Now, we're safe to turn on async cancellability */ + printf("%s\tI'm Alive, setting async cancellation ON\n", + messagep); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &last_type); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_state); + + /* loop forever until picked off with a cancel */ + for(;;i++) { + if (i%1000 == 0) + print_count(messagep, *my_id, i++); + if (i%10000 == 0) { + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_tmp); + printf("\n%s\tHum, nobody here but us chickens. %d\n", messagep,i); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &last_tmp); + } + } + + /* never get this far */ + + /* This pop is required by the standard, every push must have a pop + in the same lexical block. */ + pthread_cleanup_pop(0); + + return(NULL); +} + +extern int +main(void) +{ + int i; + void *statusp; + pthread_t threads[NUM_THREADS]; + + + /* spawn the threads */ + pthread_create(&(threads[0]), + NULL, + ask_for_it, + (void *) &(id_arg[0])); + + pthread_create(&(threads[1]), + NULL, + sitting_duck, + (void *) &(id_arg[1])); + + pthread_create(&(threads[2]), + NULL, + bullet_proof, + (void *) &(id_arg[2])); + + printf("main(): %d threads created\n", NUM_THREADS); + + pthread_mutex_lock(&lock); + + /* wait until all threads have entered loops */ + while (count != 0) { + pthread_cond_wait(&init_done, &lock); + } + + pthread_mutex_unlock(&lock); + + printf("main(): all threads have signaled that ready\n"); + + /* cancel each thread */ + for (i=0; i +#include +#include +#include +#include +#include + +#include + + +#define async_cancel_safe_read(fd,buf,amt) \ + { \ + int oldtype; \ + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); \ + if (read(fd,buf,amt) < 0) \ + perror("read"),exit(1); \ + pthread_setcanceltype(oldtype,NULL); \ + pthread_testcancel(); \ + } + + +#define async_cancel_safe_write(fd,buf,amt) \ + { \ + int oldtype; \ + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); \ + if (write(fd,buf,amt) < 0) \ + perror("write"), exit(1); \ + pthread_setcanceltype(oldtype,NULL); \ + pthread_testcancel(); \ + } + + +static int fd; + +void *io(void *arg) +{ + int *fd=(int *)arg; + char buf[20]="String"; + int amt=20; + + for (;;) { + async_cancel_safe_write(*fd,buf,amt); + async_cancel_safe_read(*fd,buf,amt); + } + return(NULL); +} + +void *killer(void *arg) +{ + pthread_t * target = (pthread_t *)arg; + sleep(1); + pthread_cancel(*target); + return(NULL); +} + +extern int +main(void) +{ + pthread_t io_thread, killer_thread; + + extern void *io(void *); + extern void *killer(void *); + + if ((fd = open(".ktemp",O_CREAT | O_RDWR, 0666)) < 0) + perror("open"), exit(1); + + pthread_create(&io_thread, + NULL, + io, + (void *)&fd); + pthread_create(&killer_thread, + NULL, + killer, + (void *)&io_thread); + + pthread_join(io_thread, NULL); + + pthread_join(killer_thread,NULL); + + if ((close(fd)) < 0) + perror("close"),exit(1); + if ((unlink(".ktemp")) < 0) + perror("unlink"),exit(1); + + return 0; +}