1/*
2 * This is a demonstration program to test pthreads on rumprun.
3 * It's not very complete ...
4 */
5
6#include <sys/types.h>
7
8#include <err.h>
9#include <errno.h>
10#include <fcntl.h>
11#include <pthread.h>
12#include <unistd.h>
13#include <stdlib.h>
14#include <stdio.h>
15#include <string.h>
16
17#include <rumprun/tester.h>
18
19static pthread_mutex_t mtx;
20static pthread_cond_t cv, cv2;
21
22static int nthreads = 4;
23
24static pthread_key_t thrnumkey;
25
26static void
27threxit(void *arg)
28{
29
30	pthread_mutex_lock(&mtx);
31	if (--nthreads == 0) {
32		printf("signalling\n");
33		pthread_cond_signal(&cv2);
34	}
35	pthread_mutex_unlock(&mtx);
36
37	if (pthread_getspecific(thrnumkey) != arg) {
38		printf("ERROR: specificdata fail");
39		abort();
40	}
41
42	printf("thread %p EXIT %d\n", arg, nthreads);
43}
44
45static void *
46mythread(void *arg)
47{
48
49	printf("thread %p\n", arg);
50	pthread_setspecific(thrnumkey, arg);
51
52	pthread_mutex_lock(&mtx);
53	printf("got lock %p\n", arg);
54	sched_yield();
55	pthread_mutex_unlock(&mtx);
56	printf("unlocked lock %p\n", arg);
57	sched_yield();
58
59	threxit(arg);
60
61	return NULL;
62}
63
64static int predicate;
65
66static void *
67waitthread(void *arg)
68{
69
70	printf("thread %p\n", arg);
71	pthread_setspecific(thrnumkey, arg);
72	pthread_mutex_lock(&mtx);
73	while (!predicate) {
74		printf("no good, need to wait %p\n", arg);
75		pthread_cond_wait(&cv, &mtx);
76	}
77	pthread_mutex_unlock(&mtx);
78	printf("condvar complete %p!\n", arg);
79
80	threxit(arg);
81
82	return NULL;
83}
84
85static void *
86wakeupthread(void *arg)
87{
88
89	printf("thread %p\n", arg);
90	pthread_setspecific(thrnumkey, arg);
91	pthread_mutex_lock(&mtx);
92	predicate = 1;
93	printf("rise and shine %p!\n", arg);
94	pthread_cond_signal(&cv);
95	pthread_mutex_unlock(&mtx);
96
97	threxit(arg);
98
99	return NULL;
100}
101
102static void *
103jointhread(void *arg)
104{
105
106	return (void *)37;
107}
108
109/* verify that a fd created in the main thread is accessible in another */
110static void *
111fdthread(void *arg)
112{
113	int fd = *(int *)arg;
114	char buf[1];
115
116	if (read(fd, buf, 1) != 0)
117		err(1, "fdthread read");
118	if (close(fd) != 0)
119		err(1, "fdthread close");
120	return (void *)0;
121}
122
123int
124rumprun_test(int argc, char *argv[])
125{
126	struct timespec ts;
127	pthread_t pt;
128	void *rv;
129	int nullfd;
130
131	pthread_key_create(&thrnumkey, NULL);
132
133	pthread_mutex_init(&mtx, NULL);
134	pthread_cond_init(&cv, NULL);
135	pthread_cond_init(&cv2, NULL);
136
137	printf("testing pthread_join\n");
138	if (pthread_create(&pt, NULL, jointhread, NULL) != 0)
139		errx(1, "pthread jointhread create");
140	if (pthread_join(pt, &rv) != 0)
141		errx(1, "pthread_join()");
142	if (rv != (void *)37)
143		errx(1, "joiner returned incorrect value");
144	printf("success\n");
145
146	if (pthread_create(&pt, NULL, mythread, (void *)0x01) != 0)
147		errx(1, "pthread_create()");
148
149	clock_gettime(CLOCK_REALTIME, &ts);
150	ts.tv_nsec += 100*1000*1000;
151	pthread_mutex_lock(&mtx);
152	if (pthread_cond_timedwait(&cv2, &mtx, &ts) != ETIMEDOUT) {
153		printf("cond_timedwait fail\n");
154		abort();
155	}
156	pthread_mutex_unlock(&mtx);
157
158	if (pthread_create(&pt, NULL, mythread, (void *)0x02) != 0)
159		errx(1, "pthread_create()");
160	if (pthread_create(&pt, NULL, waitthread, (void *)0x03) != 0)
161		errx(1, "pthread_create()");
162	if (pthread_create(&pt, NULL, wakeupthread, (void *)0x04) != 0)
163		errx(1, "pthread_create()");
164
165	pthread_mutex_lock(&mtx);
166	/* get time after locking => ensure loop runs before threads finish */
167	clock_gettime(CLOCK_REALTIME, &ts);
168	ts.tv_sec++;
169	while (nthreads) {
170		int rv;
171
172		printf("mainthread condwaiting\n");
173		if ((rv = pthread_cond_timedwait(&cv2, &mtx, &ts)) != 0) {
174			printf("drain condwait fail %d %d\n", rv, nthreads);
175		}
176	}
177	pthread_mutex_unlock(&mtx);
178
179	if ((nullfd = open("/dev/null", O_RDONLY)) < 0)
180		err(1, "open(/dev/null)");
181	if (pthread_create(&pt, NULL, fdthread, (void *)&nullfd) != 0)
182		errx(1, "pthread_create()");
183	if (pthread_join(pt, &rv) != 0)
184		errx(1, "pthread_join()");
185
186	printf("main thread done\n");
187
188	return 0;
189}
190