1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Expect 5 errors total (4 re cvs, 1 re exiting w/lock.).
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Tests passing bogus mutexes to pthread_cond_wait. */
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define _GNU_SOURCE 1 /* needed by glibc <= 2.3 for pthread_rwlock_* */
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <pthread.h>
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <assert.h>
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <unistd.h>
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <semaphore.h>
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdio.h>
9b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include <stdlib.h>
10b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovpthread_mutex_t mx[4];
11b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovpthread_cond_t cv; pthread_rwlock_t rwl;
12b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovsem_t* quit_now;
13b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic sem_t* my_sem_init(char*, int, unsigned);
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int my_sem_destroy(sem_t*);
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int my_sem_wait(sem_t*); static int my_sem_post(sem_t*);
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* rescue_me ( void* uu )
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* wait for, and unblock, the first wait */
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  sleep(1);
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_cond_signal( &cv );
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* wait for, and unblock, the second wait */
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  sleep(1);
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_cond_signal( &cv );
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* wait for, and unblock, the third wait */
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  sleep(1);
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_cond_signal( &cv );
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* wait for, and unblock, the fourth wait */
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  sleep(1);
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_cond_signal( &cv );
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
34b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov  my_sem_wait( quit_now );
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return NULL;
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* grab_the_lock ( void* uu )
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   int r= pthread_mutex_lock( &mx[2] ); assert(!r);
41b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   my_sem_wait( quit_now );
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   r= pthread_mutex_unlock( &mx[2] ); assert(!r);
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return NULL;
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main ( void )
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  int r;
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_t my_rescuer, grabber;
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  r= pthread_mutex_init(&mx[0], NULL); assert(!r);
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  r= pthread_mutex_init(&mx[1], NULL); assert(!r);
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  r= pthread_mutex_init(&mx[2], NULL); assert(!r);
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  r= pthread_mutex_init(&mx[3], NULL); assert(!r);
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  r= pthread_cond_init(&cv, NULL); assert(!r);
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  r= pthread_rwlock_init(&rwl, NULL); assert(!r);
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
59b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov  quit_now = my_sem_init( "quit_now", 0,0 ); assert(quit_now);
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  r= pthread_create( &grabber, NULL, grab_the_lock, NULL ); assert(!r);
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  sleep(1); /* let the grabber get there first */
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  r= pthread_create( &my_rescuer, NULL, rescue_me, NULL );  assert(!r);
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* Do stupid things and hope that rescue_me gets us out of
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     trouble */
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* mx is bogus */
69b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov  r= pthread_cond_wait(&cv, (pthread_mutex_t*)(4 + (char*)&mx[0]) );
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* mx is not locked */
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  r= pthread_cond_wait(&cv, &mx[0]);
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* wrong flavour of lock */
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  r= pthread_cond_wait(&cv, (pthread_mutex_t*)&rwl );
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* mx is held by someone else. */
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  r= pthread_cond_wait(&cv, &mx[2] );
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
80b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov  r= my_sem_post( quit_now ); assert(!r);
81b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov  r= my_sem_post( quit_now ); assert(!r);
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  r= pthread_join( my_rescuer, NULL ); assert(!r);
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  r= pthread_join( grabber, NULL ); assert(!r);
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
86b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov  r= my_sem_destroy( quit_now ); assert(!r);
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return 0;
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
97b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic sem_t* my_sem_init (char* identity, int pshared, unsigned count)
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
99b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   sem_t* s;
100b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_linux)
102b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   s = malloc(sizeof(*s));
103b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (s) {
104b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (sem_init(s, pshared, count) < 0) {
105b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	 perror("sem_init");
106b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	 free(s);
107b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	 s = NULL;
108b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
109b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGO_darwin)
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   char name[100];
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sprintf(name, "anonsem_%s_pid%d", identity, (int)getpid());
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   name[ sizeof(name)-1 ] = 0;
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) printf("name = %s\n", name);
115b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   s = sem_open(name, O_CREAT | O_EXCL, 0600, count);
116b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (s == SEM_FAILED) {
117b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      perror("sem_open");
118b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      s = NULL;
119b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  error "Unsupported OS"
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
123b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
124b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return s;
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int my_sem_destroy ( sem_t* s )
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sem_destroy(s);
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int my_sem_wait(sem_t* s)
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return sem_wait(s);
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int my_sem_post(sem_t* s)
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return sem_post(s);
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
141