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