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