xref: /openbsd-src/regress/lib/libpthread/cancel/cancel.c (revision 04e62e6e0a2e1a9ab86abf920a37067c05e53e14)
1*04e62e6eSotto /*	$OpenBSD: cancel.c,v 1.9 2016/09/20 17:25:06 otto Exp $	*/
2b2ea75c1Sfgsch /* David Leonard <d@openbsd.org>, 1999. Public Domain. */
3b2ea75c1Sfgsch 
4b2ea75c1Sfgsch #include <pthread.h>
5b2ea75c1Sfgsch #include <pthread_np.h>
6b2ea75c1Sfgsch #include <unistd.h>
7f2da64fbSotto #include <util.h>
8b2ea75c1Sfgsch #include <stdio.h>
9b2ea75c1Sfgsch #include <fcntl.h>
108445c537Stodd #include <stdlib.h>
11b2ea75c1Sfgsch #include "test.h"
12b2ea75c1Sfgsch 
13b2ea75c1Sfgsch static pthread_cond_t cond;
14b2ea75c1Sfgsch static pthread_mutex_t mutex;
15b2ea75c1Sfgsch static struct timespec expiretime;
16b2ea75c1Sfgsch 
17b99c213aSmarc static volatile int pv_state = 0;
18b99c213aSmarc 
19db3296cfSderaadt static void
p(void)20db3296cfSderaadt p(void)
21db3296cfSderaadt {
22b2ea75c1Sfgsch 	CHECKr(pthread_mutex_lock(&mutex));
23b2ea75c1Sfgsch 	if (pv_state <= 0) {
24b2ea75c1Sfgsch 		CHECKr(pthread_cond_timedwait(&cond, &mutex, &expiretime));
25b2ea75c1Sfgsch 	}
26b2ea75c1Sfgsch 	pv_state--;
27b2ea75c1Sfgsch 	CHECKr(pthread_mutex_unlock(&mutex));
28b2ea75c1Sfgsch }
29b2ea75c1Sfgsch 
30db3296cfSderaadt static void
v(void)31db3296cfSderaadt v(void)
32db3296cfSderaadt {
33b2ea75c1Sfgsch 	int needsignal;
34b2ea75c1Sfgsch 
35b2ea75c1Sfgsch 	CHECKr(pthread_mutex_lock(&mutex));
36b2ea75c1Sfgsch 	pv_state++;
37b2ea75c1Sfgsch 	needsignal = (pv_state == 1);
38b2ea75c1Sfgsch 	if (needsignal)
39b2ea75c1Sfgsch 		CHECKr(pthread_cond_signal(&cond));
40b2ea75c1Sfgsch 	CHECKr(pthread_mutex_unlock(&mutex));
41b2ea75c1Sfgsch }
42b2ea75c1Sfgsch 
43db3296cfSderaadt static void
c1handler(void * arg)442badd5e3Sfgsch c1handler(void *arg)
45b2ea75c1Sfgsch {
462badd5e3Sfgsch 	CHECKe(close(*(int *)arg));
47b2ea75c1Sfgsch 	v();
48b2ea75c1Sfgsch }
49b2ea75c1Sfgsch 
50db3296cfSderaadt static void *
child1fn(void * arg)51db3296cfSderaadt child1fn(void *arg)
52b2ea75c1Sfgsch {
53f2da64fbSotto 	int fd, dummy;
54b2ea75c1Sfgsch 	char buf[1024];
55b2ea75c1Sfgsch 	int len;
56b2ea75c1Sfgsch 
57b2ea75c1Sfgsch 	SET_NAME("c1");
58b2ea75c1Sfgsch 	CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL));
59b2ea75c1Sfgsch 	/* something that will block */
60*04e62e6eSotto 	CHECKe(openpty(&dummy, &fd, NULL, NULL, NULL));
612badd5e3Sfgsch 	pthread_cleanup_push(c1handler, (void *)&fd);
62b2ea75c1Sfgsch 	v();
63b2ea75c1Sfgsch 	while (1) {
64b2ea75c1Sfgsch 		CHECKe(len = read(fd, &buf, sizeof buf));
65b2ea75c1Sfgsch 		printf("child 1 read %d bytes\n", len);
66b2ea75c1Sfgsch 	}
672bcd7660Sguenther 	pthread_cleanup_pop(0);
68b2ea75c1Sfgsch 	PANIC("child 1");
69b2ea75c1Sfgsch }
70b2ea75c1Sfgsch 
71b2ea75c1Sfgsch static int c2_in_test = 0;
72b2ea75c1Sfgsch 
73db3296cfSderaadt static void
c2handler(void * arg)74b2ea75c1Sfgsch c2handler(void *arg)
75b2ea75c1Sfgsch {
76b2ea75c1Sfgsch 	ASSERT(c2_in_test);
77b2ea75c1Sfgsch 	v();
78b2ea75c1Sfgsch }
79b2ea75c1Sfgsch 
80b2ea75c1Sfgsch static int message_seen = 0;
81db3296cfSderaadt static void *
child2fn(void * arg)82db3296cfSderaadt child2fn(void *arg)
83b2ea75c1Sfgsch {
84b2ea75c1Sfgsch 	SET_NAME("c2");
85b2ea75c1Sfgsch 
86b2ea75c1Sfgsch 	CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL));
87b2ea75c1Sfgsch 	pthread_cleanup_push(c2handler, NULL);
88b2ea75c1Sfgsch 	v();
89b2ea75c1Sfgsch 
90b2ea75c1Sfgsch 	while (1) {
91b2ea75c1Sfgsch 		struct timespec now;
92b2ea75c1Sfgsch 		struct timespec end;
93b2ea75c1Sfgsch 
94b2ea75c1Sfgsch 		/*
95b2ea75c1Sfgsch 		 * XXX Be careful not to call any cancellation points
96b2ea75c1Sfgsch 		 * until pthread_testcancel()
97b2ea75c1Sfgsch 		 */
98b2ea75c1Sfgsch 
99b2ea75c1Sfgsch 		CHECKe(clock_gettime(CLOCK_REALTIME, &end));
100b2ea75c1Sfgsch 		end.tv_sec ++;
101b2ea75c1Sfgsch 
102b2ea75c1Sfgsch 		while (1) {
103b2ea75c1Sfgsch 			CHECKe(clock_gettime(CLOCK_REALTIME, &now));
104b2ea75c1Sfgsch 			if (timespeccmp(&now, &end, >=))
105b2ea75c1Sfgsch 				break;
106b2ea75c1Sfgsch 			pthread_yield();
107b2ea75c1Sfgsch 		}
108b2ea75c1Sfgsch 
109b2ea75c1Sfgsch 		/* XXX write() contains a cancellation point */
110b2ea75c1Sfgsch 		/* printf("child 2 testing for cancel\n"); */
111b2ea75c1Sfgsch 
112b2ea75c1Sfgsch 		c2_in_test = 1;
113b2ea75c1Sfgsch 		pthread_testcancel();
114b2ea75c1Sfgsch 		printf("you should see this message exactly once\n");
115b2ea75c1Sfgsch 		message_seen++;
116b2ea75c1Sfgsch 		c2_in_test = 0;
117b2ea75c1Sfgsch 		ASSERT(message_seen == 1);
118b7d634bcSmarc 		v();
119b2ea75c1Sfgsch 	}
1202bcd7660Sguenther 	pthread_cleanup_pop(0);
121b2ea75c1Sfgsch 	PANIC("child 2");
122b2ea75c1Sfgsch }
123b2ea75c1Sfgsch 
124b2ea75c1Sfgsch static int c3_cancel_survived;
125b2ea75c1Sfgsch 
126db3296cfSderaadt static void
c3handler(void * arg)127b2ea75c1Sfgsch c3handler(void *arg)
128b2ea75c1Sfgsch {
129b2ea75c1Sfgsch 	printf("(fyi, cancellation of self %s instantaneous)\n",
130b2ea75c1Sfgsch 		(c3_cancel_survived ? "was not" : "was"));
131b2ea75c1Sfgsch 	v();
132b2ea75c1Sfgsch }
133b2ea75c1Sfgsch 
134db3296cfSderaadt static void *
child3fn(void * arg)135db3296cfSderaadt child3fn(void *arg)
136b2ea75c1Sfgsch {
137b2ea75c1Sfgsch 	SET_NAME("c3");
138b2ea75c1Sfgsch 	pthread_cleanup_push(c3handler, NULL);
139b2ea75c1Sfgsch 
140b2ea75c1Sfgsch 	/* Cancel myself */
141b2ea75c1Sfgsch 	CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL));
142b2ea75c1Sfgsch 	c3_cancel_survived = 0;
143b2ea75c1Sfgsch 	pthread_cancel(pthread_self());
144b2ea75c1Sfgsch 	c3_cancel_survived = 1;
145b2ea75c1Sfgsch 	pthread_testcancel();
1462bcd7660Sguenther 	pthread_cleanup_pop(0);
147b2ea75c1Sfgsch 
148b2ea75c1Sfgsch 	PANIC("child 3");
149b2ea75c1Sfgsch }
150b2ea75c1Sfgsch 
1512bcd7660Sguenther static int c4_cancel_early;
1522bcd7660Sguenther 
1532bcd7660Sguenther static void
c4handler(void * arg)1542bcd7660Sguenther c4handler(void *arg)
1552bcd7660Sguenther {
1562bcd7660Sguenther 	printf("early = %d\n", c4_cancel_early);
1572bcd7660Sguenther 	ASSERT(c4_cancel_early == 0);
1582bcd7660Sguenther 	v();
1592bcd7660Sguenther }
1602bcd7660Sguenther 
1612bcd7660Sguenther static void *
child4fn(void * arg)1622bcd7660Sguenther child4fn(void *arg)
1632bcd7660Sguenther {
1642bcd7660Sguenther 	SET_NAME("c4");
1652bcd7660Sguenther 	pthread_cleanup_push(c4handler, NULL);
1662bcd7660Sguenther 
1672bcd7660Sguenther 	/* Cancel myself */
1682bcd7660Sguenther 	CHECKr(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL));
1692bcd7660Sguenther 
1702bcd7660Sguenther 	c4_cancel_early = 3;
1712bcd7660Sguenther 	pthread_cancel(pthread_self());
1722bcd7660Sguenther 
1732bcd7660Sguenther 	c4_cancel_early = 2;
1742bcd7660Sguenther 	pthread_testcancel();
1752bcd7660Sguenther 
1762bcd7660Sguenther 	c4_cancel_early = 1;
1772bcd7660Sguenther 	CHECKr(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL));
1782bcd7660Sguenther 
1792bcd7660Sguenther 	c4_cancel_early = 0;
1802bcd7660Sguenther 	pthread_testcancel();
1812bcd7660Sguenther 
1822bcd7660Sguenther 	pthread_cleanup_pop(0);
1832bcd7660Sguenther 
1842bcd7660Sguenther 	PANIC("child 4");
1852bcd7660Sguenther }
1862bcd7660Sguenther 
187b2ea75c1Sfgsch int
main(int argc,char * argv[])188db3296cfSderaadt main(int argc, char *argv[])
189b2ea75c1Sfgsch {
1902bcd7660Sguenther 	pthread_t child1, child2, child3, child4;
191b2ea75c1Sfgsch 
192b2ea75c1Sfgsch 	/* Set up our control flow */
193b2ea75c1Sfgsch 	CHECKr(pthread_mutex_init(&mutex, NULL));
194b2ea75c1Sfgsch 	CHECKr(pthread_cond_init(&cond, NULL));
195b2ea75c1Sfgsch 	CHECKe(clock_gettime(CLOCK_REALTIME, &expiretime));
196b2ea75c1Sfgsch 	expiretime.tv_sec += 5; /* this test shouldn't run over 5 seconds */
197b2ea75c1Sfgsch 
198b2ea75c1Sfgsch 	CHECKr(pthread_create(&child1, NULL, child1fn, NULL));
199b2ea75c1Sfgsch 	CHECKr(pthread_create(&child2, NULL, child2fn, NULL));
200b2ea75c1Sfgsch 	p();
201b2ea75c1Sfgsch 	p();
202b2ea75c1Sfgsch 
203b2ea75c1Sfgsch 	CHECKr(pthread_cancel(child1));
204b2ea75c1Sfgsch 	p();
205b2ea75c1Sfgsch 
206b2ea75c1Sfgsch 	/* Give thread 2 a chance to go through its deferred loop once */
207b7d634bcSmarc 	p();
208b2ea75c1Sfgsch 	CHECKr(pthread_cancel(child2));
209b2ea75c1Sfgsch 	p();
210b2ea75c1Sfgsch 
211b2ea75c1Sfgsch 	/* Child 3 cancels itself */
212b2ea75c1Sfgsch 	CHECKr(pthread_create(&child3, NULL, child3fn, NULL));
213b2ea75c1Sfgsch 	p();
214b2ea75c1Sfgsch 
2152bcd7660Sguenther 	/* Child 4 also cancels itself */
2162bcd7660Sguenther 	CHECKr(pthread_create(&child4, NULL, child4fn, NULL));
2172bcd7660Sguenther 	p();
2182bcd7660Sguenther 
219b2ea75c1Sfgsch 	/* Make sure they're all gone */
2202bcd7660Sguenther 	CHECKr(pthread_join(child4, NULL));
221b2ea75c1Sfgsch 	CHECKr(pthread_join(child3, NULL));
222b2ea75c1Sfgsch 	CHECKr(pthread_join(child2, NULL));
223b2ea75c1Sfgsch 	CHECKr(pthread_join(child1, NULL));
224b2ea75c1Sfgsch 
225b2ea75c1Sfgsch 	exit(0);
226b2ea75c1Sfgsch }
227