• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // commit: 7e6be42a77989c01155bdc7333ea58206e1563d4 2011-03-08
2 // pthread_once should not deadlock
3 #include <pthread.h>
4 #include <semaphore.h>
5 #include <errno.h>
6 #include <string.h>
7 #include "test.h"
8 
9 #define T(f) if ((r=(f))) t_error(#f " failed: %s\n", strerror(r))
10 #define E(f) if (f) t_error(#f " failed: %s\n", strerror(errno))
11 
12 static int count;
13 
init(void)14 static void init(void)
15 {
16 	count++;
17 }
18 
start(void * arg)19 static void *start(void *arg)
20 {
21 	void **a = arg;
22 	int r;
23 	E(sem_post(a[1]));
24 	T(pthread_once(a[0], init));
25 	E(sem_post(a[1]));
26 	return 0;
27 }
28 
deadlocked(sem_t * s)29 static int deadlocked(sem_t *s)
30 {
31 	struct timespec ts;
32 
33 	E(sem_wait(s));
34 	E(clock_gettime(CLOCK_REALTIME, &ts));
35 	ts.tv_nsec += 100*1000*1000;
36 	if (ts.tv_nsec >= 1000*1000*1000) {
37 		ts.tv_nsec -= 1000*1000*1000;
38 		ts.tv_sec += 1;
39 	}
40 	errno = 0;
41 	E(sem_timedwait(s,&ts));
42 	if (errno != ETIMEDOUT)
43 		return 0;
44 	t_error("pthread_once deadlocked\n");
45 	return 1;
46 }
47 
main(void)48 int main(void)
49 {
50 	pthread_t t1,t2,t3;
51 	pthread_once_t once = PTHREAD_ONCE_INIT;
52 	sem_t s1,s2,s3;
53 	void *p;
54 	int r;
55 
56 	E(sem_init(&s1,0,0));
57 	E(sem_init(&s2,0,0));
58 	E(sem_init(&s3,0,0));
59 	T(pthread_create(&t1, 0, start, (void*[]){&once,&s1}));
60 	T(pthread_create(&t2, 0, start, (void*[]){&once,&s2}));
61 	T(pthread_create(&t3, 0, start, (void*[]){&once,&s3}));
62 	if (!deadlocked(&s1)) T(pthread_join(t1,&p));
63 	if (!deadlocked(&s2)) T(pthread_join(t2,&p));
64 	if (!deadlocked(&s3)) T(pthread_join(t3,&p));
65 	if (count != 1)
66 		t_error("pthread_once ran init %d times instead of once\n", count);
67 	E(sem_destroy(&s1));
68 	E(sem_destroy(&s2));
69 	E(sem_destroy(&s3));
70 	return t_status;
71 }
72