]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Tests for cancellation/cleanup mechanisms.
authorJulian Seward <jseward@acm.org>
Wed, 29 May 2002 20:47:19 +0000 (20:47 +0000)
committerJulian Seward <jseward@acm.org>
Wed, 29 May 2002 20:47:19 +0000 (20:47 +0000)
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@337

tests/Makefile.am
tests/pth_cancel1.c [new file with mode: 0644]
tests/pth_cancel2.c [new file with mode: 0644]

index 21a8d20a81cfc72f4a5b28c87e489e2cdbeed3de..8770a85c20eced3f647b114b6e8926a9756b1d70 100644 (file)
@@ -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 (file)
index 0000000..b8802c6
--- /dev/null
@@ -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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.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 %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<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;
+}
diff --git a/tests/pth_cancel2.c b/tests/pth_cancel2.c
new file mode 100644 (file)
index 0000000..688dded
--- /dev/null
@@ -0,0 +1,101 @@
+/********************************************************
+ * An example source module to accompany...
+ *
+ * "Using POSIX Threads: Programming with Pthreads"
+ *     by Brad nichols, Dick Buttlar, Jackie Farrell
+ *     O'Reilly & Associates, Inc.
+ *
+ ********************************************************
+ * async_safe --
+ *
+ * Example showing macro wrappers for calling non-async
+ * safe routines when the caller has asynchronous 
+ * cancellation turned on
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <pthread.h>
+
+
+#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;
+}