xref: /openbsd-src/regress/lib/libpthread/cancel/cancel.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: cancel.c,v 1.6 2003/07/31 21:48:04 deraadt Exp $	*/
2 /* David Leonard <d@openbsd.org>, 1999. Public Domain. */
3 
4 #include <pthread.h>
5 #include <pthread_np.h>
6 #include <unistd.h>
7 #include <stdio.h>
8 #include <fcntl.h>
9 #include <stdlib.h>
10 #include "test.h"
11 
12 static pthread_cond_t cond;
13 static pthread_mutex_t mutex;
14 static struct timespec expiretime;
15 
16 static volatile int pv_state = 0;
17 
18 static void
19 p(void)
20 {
21 	CHECKr(pthread_mutex_lock(&mutex));
22 	if (pv_state <= 0) {
23 		CHECKr(pthread_cond_timedwait(&cond, &mutex, &expiretime));
24 	}
25 	pv_state--;
26 	CHECKr(pthread_mutex_unlock(&mutex));
27 }
28 
29 static void
30 v(void)
31 {
32 	int needsignal;
33 
34 	CHECKr(pthread_mutex_lock(&mutex));
35 	pv_state++;
36 	needsignal = (pv_state == 1);
37 	if (needsignal)
38 		CHECKr(pthread_cond_signal(&cond));
39 	CHECKr(pthread_mutex_unlock(&mutex));
40 }
41 
42 static void
43 c1handler(void *arg)
44 {
45 	CHECKe(close(*(int *)arg));
46 	v();
47 }
48 
49 static void *
50 child1fn(void *arg)
51 {
52 	int fd;
53 	char buf[1024];
54 	int len;
55 
56 	SET_NAME("c1");
57 	CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL));
58 	/* something that will block */
59 	CHECKe(fd = open("/dev/tty", O_RDONLY));
60 	pthread_cleanup_push(c1handler, (void *)&fd);
61 	v();
62 	while (1) {
63 		CHECKe(len = read(fd, &buf, sizeof buf));
64 		printf("child 1 read %d bytes\n", len);
65 	}
66 	PANIC("child 1");
67 }
68 
69 static int c2_in_test = 0;
70 
71 static void
72 c2handler(void *arg)
73 {
74 	ASSERT(c2_in_test);
75 	v();
76 }
77 
78 static int message_seen = 0;
79 static void *
80 child2fn(void *arg)
81 {
82 	SET_NAME("c2");
83 
84 	CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL));
85 	pthread_cleanup_push(c2handler, NULL);
86 	v();
87 
88 	while (1) {
89 		struct timespec now;
90 		struct timespec end;
91 
92 		/*
93 		 * XXX Be careful not to call any cancellation points
94 		 * until pthread_testcancel()
95 		 */
96 
97 		CHECKe(clock_gettime(CLOCK_REALTIME, &end));
98 		end.tv_sec ++;
99 
100 		while (1) {
101 			CHECKe(clock_gettime(CLOCK_REALTIME, &now));
102 			if (timespeccmp(&now, &end, >=))
103 				break;
104 			pthread_yield();
105 		}
106 
107 		/* XXX write() contains a cancellation point */
108 		/* printf("child 2 testing for cancel\n"); */
109 
110 		c2_in_test = 1;
111 		pthread_testcancel();
112 		printf("you should see this message exactly once\n");
113 		message_seen++;
114 		c2_in_test = 0;
115 		ASSERT(message_seen == 1);
116 		v();
117 	}
118 	PANIC("child 2");
119 }
120 
121 static int c3_cancel_survived;
122 
123 static void
124 c3handler(void *arg)
125 {
126 	printf("(fyi, cancellation of self %s instantaneous)\n",
127 		(c3_cancel_survived ? "was not" : "was"));
128 	v();
129 }
130 
131 static void *
132 child3fn(void *arg)
133 {
134 	SET_NAME("c3");
135 	pthread_cleanup_push(c3handler, NULL);
136 
137 	/* Cancel myself */
138 	CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL));
139 	c3_cancel_survived = 0;
140 	pthread_cancel(pthread_self());
141 	c3_cancel_survived = 1;
142 	pthread_testcancel();
143 
144 	PANIC("child 3");
145 }
146 
147 int
148 main(int argc, char *argv[])
149 {
150 	pthread_t child1, child2, child3;
151 
152 	/* Set up our control flow */
153 	CHECKr(pthread_mutex_init(&mutex, NULL));
154 	CHECKr(pthread_cond_init(&cond, NULL));
155 	CHECKe(clock_gettime(CLOCK_REALTIME, &expiretime));
156 	expiretime.tv_sec += 5; /* this test shouldn't run over 5 seconds */
157 
158 	CHECKr(pthread_create(&child1, NULL, child1fn, NULL));
159 	CHECKr(pthread_create(&child2, NULL, child2fn, NULL));
160 	p();
161 	p();
162 
163 	CHECKr(pthread_cancel(child1));
164 	p();
165 
166 	/* Give thread 2 a chance to go through its deferred loop once */
167 	p();
168 	CHECKr(pthread_cancel(child2));
169 	p();
170 
171 	/* Child 3 cancels itself */
172 	CHECKr(pthread_create(&child3, NULL, child3fn, NULL));
173 	p();
174 
175 	/* Make sure they're all gone */
176 	CHECKr(pthread_join(child3, NULL));
177 	CHECKr(pthread_join(child2, NULL));
178 	CHECKr(pthread_join(child1, NULL));
179 
180 	exit(0);
181 }
182