summaryrefslogtreecommitdiff
path: root/tests/cancel1.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/cancel1.c')
-rw-r--r--tests/cancel1.c273
1 files changed, 273 insertions, 0 deletions
diff --git a/tests/cancel1.c b/tests/cancel1.c
new file mode 100644
index 0000000..189fc64
--- /dev/null
+++ b/tests/cancel1.c
@@ -0,0 +1,273 @@
+/********************************************************
+ * 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 <stdio.h>
+#include "pthread.h"
+
+#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 0x%x\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, 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<NUM_THREADS; i++) {
+ pthread_cancel(threads[i]);
+ }
+
+ /* wait until all threads have finished */
+ for (i=0; i<NUM_THREADS; i++) {
+ pthread_join(threads[i], &statusp);
+ if (statusp == PTHREAD_CANCELED) {
+ printf("main(): joined to thread %d, statusp=PTHREAD_CANCELED\n",i);
+ } else {
+ printf("main(): joined to thread %d\n",i);
+ }
+ }
+
+ printf("main()\t\tall %d threads have finished. \n", NUM_THREADS);
+
+ return 0;
+}
+
+
+
+