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