1251881Speter/*	$OpenBSD: cancel.c,v 1.9 2016/09/20 17:25:06 otto Exp $	*/
2251881Speter/* David Leonard <d@openbsd.org>, 1999. Public Domain. */
3251881Speter
4251881Speter#include <pthread.h>
5251881Speter#include <pthread_np.h>
6251881Speter#include <unistd.h>
7251881Speter#include <util.h>
8251881Speter#include <stdio.h>
9251881Speter#include <fcntl.h>
10251881Speter#include <stdlib.h>
11251881Speter#include "test.h"
12251881Speter
13251881Speterstatic pthread_cond_t cond;
14251881Speterstatic pthread_mutex_t mutex;
15251881Speterstatic struct timespec expiretime;
16251881Speter
17251881Speterstatic volatile int pv_state = 0;
18251881Speter
19251881Speterstatic void
20251881Speterp(void)
21251881Speter{
22251881Speter	CHECKr(pthread_mutex_lock(&mutex));
23251881Speter	if (pv_state <= 0) {
24251881Speter		CHECKr(pthread_cond_timedwait(&cond, &mutex, &expiretime));
25251881Speter	}
26251881Speter	pv_state--;
27251881Speter	CHECKr(pthread_mutex_unlock(&mutex));
28251881Speter}
29251881Speter
30251881Speterstatic void
31251881Speterv(void)
32251881Speter{
33251881Speter	int needsignal;
34251881Speter
35251881Speter	CHECKr(pthread_mutex_lock(&mutex));
36251881Speter	pv_state++;
37251881Speter	needsignal = (pv_state == 1);
38251881Speter	if (needsignal)
39251881Speter		CHECKr(pthread_cond_signal(&cond));
40251881Speter	CHECKr(pthread_mutex_unlock(&mutex));
41251881Speter}
42251881Speter
43251881Speterstatic void
44251881Speterc1handler(void *arg)
45251881Speter{
46251881Speter	CHECKe(close(*(int *)arg));
47251881Speter	v();
48251881Speter}
49251881Speter
50251881Speterstatic void *
51251881Speterchild1fn(void *arg)
52251881Speter{
53251881Speter	int fd, dummy;
54251881Speter	char buf[1024];
55251881Speter	int len;
56251881Speter
57251881Speter	SET_NAME("c1");
58251881Speter	CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL));
59251881Speter	/* something that will block */
60251881Speter	CHECKe(openpty(&dummy, &fd, NULL, NULL, NULL));
61251881Speter	pthread_cleanup_push(c1handler, (void *)&fd);
62251881Speter	v();
63251881Speter	while (1) {
64251881Speter		CHECKe(len = read(fd, &buf, sizeof buf));
65251881Speter		printf("child 1 read %d bytes\n", len);
66251881Speter	}
67251881Speter	pthread_cleanup_pop(0);
68251881Speter	PANIC("child 1");
69251881Speter}
70251881Speter
71251881Speterstatic int c2_in_test = 0;
72251881Speter
73251881Speterstatic void
74251881Speterc2handler(void *arg)
75251881Speter{
76251881Speter	ASSERT(c2_in_test);
77251881Speter	v();
78251881Speter}
79251881Speter
80251881Speterstatic int message_seen = 0;
81251881Speterstatic void *
82251881Speterchild2fn(void *arg)
83251881Speter{
84251881Speter	SET_NAME("c2");
85251881Speter
86251881Speter	CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL));
87251881Speter	pthread_cleanup_push(c2handler, NULL);
88251881Speter	v();
89251881Speter
90251881Speter	while (1) {
91251881Speter		struct timespec now;
92251881Speter		struct timespec end;
93251881Speter
94251881Speter		/*
95251881Speter		 * XXX Be careful not to call any cancellation points
96251881Speter		 * until pthread_testcancel()
97251881Speter		 */
98251881Speter
99251881Speter		CHECKe(clock_gettime(CLOCK_REALTIME, &end));
100251881Speter		end.tv_sec ++;
101251881Speter
102251881Speter		while (1) {
103251881Speter			CHECKe(clock_gettime(CLOCK_REALTIME, &now));
104251881Speter			if (timespeccmp(&now, &end, >=))
105251881Speter				break;
106251881Speter			pthread_yield();
107251881Speter		}
108251881Speter
109251881Speter		/* XXX write() contains a cancellation point */
110251881Speter		/* printf("child 2 testing for cancel\n"); */
111251881Speter
112251881Speter		c2_in_test = 1;
113251881Speter		pthread_testcancel();
114251881Speter		printf("you should see this message exactly once\n");
115251881Speter		message_seen++;
116251881Speter		c2_in_test = 0;
117251881Speter		ASSERT(message_seen == 1);
118251881Speter		v();
119251881Speter	}
120251881Speter	pthread_cleanup_pop(0);
121251881Speter	PANIC("child 2");
122251881Speter}
123251881Speter
124251881Speterstatic int c3_cancel_survived;
125251881Speter
126251881Speterstatic void
127251881Speterc3handler(void *arg)
128251881Speter{
129251881Speter	printf("(fyi, cancellation of self %s instantaneous)\n",
130251881Speter		(c3_cancel_survived ? "was not" : "was"));
131251881Speter	v();
132251881Speter}
133251881Speter
134251881Speterstatic void *
135251881Speterchild3fn(void *arg)
136251881Speter{
137251881Speter	SET_NAME("c3");
138251881Speter	pthread_cleanup_push(c3handler, NULL);
139251881Speter
140251881Speter	/* Cancel myself */
141251881Speter	CHECKr(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL));
142251881Speter	c3_cancel_survived = 0;
143251881Speter	pthread_cancel(pthread_self());
144251881Speter	c3_cancel_survived = 1;
145251881Speter	pthread_testcancel();
146251881Speter	pthread_cleanup_pop(0);
147251881Speter
148251881Speter	PANIC("child 3");
149251881Speter}
150251881Speter
151251881Speterstatic int c4_cancel_early;
152251881Speter
153251881Speterstatic void
154251881Speterc4handler(void *arg)
155251881Speter{
156251881Speter	printf("early = %d\n", c4_cancel_early);
157251881Speter	ASSERT(c4_cancel_early == 0);
158251881Speter	v();
159251881Speter}
160251881Speter
161251881Speterstatic void *
162251881Speterchild4fn(void *arg)
163251881Speter{
164251881Speter	SET_NAME("c4");
165251881Speter	pthread_cleanup_push(c4handler, NULL);
166251881Speter
167251881Speter	/* Cancel myself */
168251881Speter	CHECKr(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL));
169251881Speter
170251881Speter	c4_cancel_early = 3;
171251881Speter	pthread_cancel(pthread_self());
172251881Speter
173251881Speter	c4_cancel_early = 2;
174251881Speter	pthread_testcancel();
175251881Speter
176251881Speter	c4_cancel_early = 1;
177251881Speter	CHECKr(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL));
178251881Speter
179251881Speter	c4_cancel_early = 0;
180251881Speter	pthread_testcancel();
181251881Speter
182251881Speter	pthread_cleanup_pop(0);
183251881Speter
184251881Speter	PANIC("child 4");
185251881Speter}
186251881Speter
187251881Speterint
188251881Spetermain(int argc, char *argv[])
189251881Speter{
190251881Speter	pthread_t child1, child2, child3, child4;
191251881Speter
192251881Speter	/* Set up our control flow */
193251881Speter	CHECKr(pthread_mutex_init(&mutex, NULL));
194251881Speter	CHECKr(pthread_cond_init(&cond, NULL));
195251881Speter	CHECKe(clock_gettime(CLOCK_REALTIME, &expiretime));
196251881Speter	expiretime.tv_sec += 5; /* this test shouldn't run over 5 seconds */
197251881Speter
198251881Speter	CHECKr(pthread_create(&child1, NULL, child1fn, NULL));
199251881Speter	CHECKr(pthread_create(&child2, NULL, child2fn, NULL));
200251881Speter	p();
201251881Speter	p();
202251881Speter
203251881Speter	CHECKr(pthread_cancel(child1));
204251881Speter	p();
205251881Speter
206251881Speter	/* Give thread 2 a chance to go through its deferred loop once */
207251881Speter	p();
208251881Speter	CHECKr(pthread_cancel(child2));
209251881Speter	p();
210251881Speter
211251881Speter	/* Child 3 cancels itself */
212251881Speter	CHECKr(pthread_create(&child3, NULL, child3fn, NULL));
213251881Speter	p();
214251881Speter
215251881Speter	/* Child 4 also cancels itself */
216251881Speter	CHECKr(pthread_create(&child4, NULL, child4fn, NULL));
217251881Speter	p();
218251881Speter
219251881Speter	/* Make sure they're all gone */
220251881Speter	CHECKr(pthread_join(child4, NULL));
221251881Speter	CHECKr(pthread_join(child3, NULL));
222251881Speter	CHECKr(pthread_join(child2, NULL));
223251881Speter	CHECKr(pthread_join(child1, NULL));
224251881Speter
225251881Speter	exit(0);
226251881Speter}
227251881Speter