sewardj | b411202 | 2007-11-09 22:49:28 +0000 | [diff] [blame^] | 1 | |
| 2 | /* This really exists to check that Thrcheck behaves plausibly |
| 3 | with pthread_once calls. Which it appears to. |
| 4 | |
| 5 | The original source of this program is as shown below, although it |
| 6 | has been modified somewhat. See |
| 7 | http://www.oreilly.com/pub/a/oreilly/ask_tim/2001/codepolicy.html |
| 8 | for OReilly's policy on using bits of their code examples. |
| 9 | */ |
| 10 | |
| 11 | |
| 12 | /******************************************************** |
| 13 | * An example source module to accompany... |
| 14 | * |
| 15 | * "Using POSIX Threads: Programming with Pthreads" |
| 16 | * by Brad Nichols, Dick Buttlar, Jackie Farrell |
| 17 | * O'Reilly & Associates, Inc. |
| 18 | * |
| 19 | ******************************************************** |
| 20 | * once_exam.c |
| 21 | * |
| 22 | * An example of using the pthreads_once() call to execute an |
| 23 | * initialization procedure. |
| 24 | * |
| 25 | * A program spawns multiple threads and each one tries to |
| 26 | * execute the routine welcome() using the once call. Only |
| 27 | * the first thread into the once routine will actually |
| 28 | * execute welcome(). |
| 29 | * |
| 30 | * The program's main thread synchronizes its exit with the |
| 31 | * exit of the threads using the pthread_join() operation. |
| 32 | * |
| 33 | */ |
| 34 | |
| 35 | #include <stdlib.h> |
| 36 | #include <stdio.h> |
| 37 | #include <unistd.h> |
| 38 | #include <sys/types.h> |
| 39 | #include <assert.h> |
| 40 | |
| 41 | #include <pthread.h> |
| 42 | |
| 43 | /* With more than 2 threads, the precise error reports vary between |
| 44 | platforms, in terms of the number of races detected. Make life |
| 45 | simple and just have 2 threads and so just 1 race. */ |
| 46 | #define NUM_THREADS 2 |
| 47 | |
| 48 | static pthread_once_t welcome_once_block = PTHREAD_ONCE_INIT; |
| 49 | |
| 50 | static int unprotected1 = 0; |
| 51 | static int unprotected2 = 0; |
| 52 | |
| 53 | /* This is a hack: delay threads except the first enough so as to |
| 54 | ensure threads[0] gets to the pthread_once call first. This is so |
| 55 | as to ensure that this test produces results which aren't |
| 56 | scheduling sensitive. (sigh) */ |
| 57 | void maybe_stall ( int myid ) |
| 58 | { |
| 59 | assert(myid >= 0 && myid < NUM_THREADS); |
| 60 | if (myid > 0) |
| 61 | sleep(1); |
| 62 | } |
| 63 | |
| 64 | void welcome(void) { |
| 65 | printf("welcome: Welcome\n"); |
| 66 | unprotected1++; /* this is harmless */ |
| 67 | } |
| 68 | |
| 69 | void* child ( void* argV ) { |
| 70 | int r; |
| 71 | maybe_stall( *(int*)argV ); |
| 72 | r= pthread_once(&welcome_once_block, welcome); assert(!r); |
| 73 | printf("child: Hi, I'm thread %d\n", *(int*)argV); |
| 74 | unprotected2++; /* whereas this is a race */ |
| 75 | return NULL; |
| 76 | } |
| 77 | |
| 78 | int main ( void ) { |
| 79 | int *id_arg, i, r; |
| 80 | pthread_t threads[NUM_THREADS]; |
| 81 | |
| 82 | id_arg = (int *)malloc(NUM_THREADS*sizeof(int)); |
| 83 | |
| 84 | for (i = 0; i < NUM_THREADS; i++) { |
| 85 | id_arg[i] = i; |
| 86 | r= pthread_create(&threads[i], NULL, child, &id_arg[i]); |
| 87 | assert(!r); |
| 88 | } |
| 89 | |
| 90 | for (i = 0; i < NUM_THREADS; i++) { |
| 91 | pthread_join(threads[i], NULL); |
| 92 | /* printf("main: joined to thread %d\n", i); */ |
| 93 | } |
| 94 | printf("main: Goodbye\n"); |
| 95 | return 0; |
| 96 | } |