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) */
maybe_stall(int myid)57 void maybe_stall ( int myid )
58 {
59 assert(myid >= 0 && myid < NUM_THREADS);
60 if (myid > 0)
61 sleep(1);
62 }
63
welcome(void)64 void welcome(void) {
65 printf("welcome: Welcome\n");
66 unprotected1++; /* this is harmless */
67 }
68
child(void * argV)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
main(void)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 printf("main: Hello\n");
85 for (i = 0; i < NUM_THREADS; i++) {
86 id_arg[i] = i;
87 r= pthread_create(&threads[i], NULL, child, &id_arg[i]);
88 assert(!r);
89 }
90
91 for (i = 0; i < NUM_THREADS; i++) {
92 pthread_join(threads[i], NULL);
93 /* printf("main: joined to thread %d\n", i); */
94 }
95 printf("main: Goodbye\n");
96 return 0;
97 }
98