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
48static pthread_once_t welcome_once_block = PTHREAD_ONCE_INIT;
49
50static int unprotected1 = 0;
51static 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) */
57void maybe_stall ( int myid )
58{
59   assert(myid >= 0 && myid < NUM_THREADS);
60   if (myid > 0)
61      sleep(1);
62}
63
64void welcome(void) {
65   printf("welcome: Welcome\n");
66   unprotected1++; /* this is harmless */
67}
68
69void* 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
78int 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