1 // sem_wait and sem_timedwait are cancellation points
2 #include <pthread.h>
3 #include <semaphore.h>
4 #include <string.h>
5 #include "test.h"
6 
7 #define TESTC(c, m) ( (c) || (t_error("%s failed (" m ")\n", #c), 0) )
8 #define TESTR(r, f, m) ( \
9 	((r) = (f)) == 0 || (t_error("%s failed: %s (" m ")\n", #f, strerror(r)), 0) )
10 
11 extern int __sem_timedwait_time64(sem_t *__restrict, const struct timespec *__restrict);
12 
13 static sem_t sem1, sem2;
14 
15 static int seqno;
16 
wait_cancel(void *arg)17 static void wait_cancel(void *arg)
18 {
19 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
20 	while (sem_wait(&sem1));
21 	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
22 	seqno = 1;
23 }
24 
start_sem_wait(void *arg)25 static void *start_sem_wait(void *arg)
26 {
27 	wait_cancel(arg);
28 	sem_wait(&sem2);
29 	seqno = 2;
30 	return 0;
31 }
32 
start_sem_timedwait(void *arg)33 static void *start_sem_timedwait(void *arg)
34 {
35 	wait_cancel(arg);
36 	sem_timedwait(&sem2, &(struct timespec){1, 0});
37 	seqno = 2;
38 	return 0;
39 }
40 
start_sem_timedwait_time64(void *arg)41 static void *start_sem_timedwait_time64(void *arg)
42 {
43 	wait_cancel(arg);
44 	__sem_timedwait_time64(&sem2, &(struct timespec){1, 0});
45 	seqno = 2;
46 	return 0;
47 }
48 
main(void)49 int main(void)
50 {
51 	pthread_t td;
52 	int r;
53 	void *res;
54 
55 	TESTR(r, sem_init(&sem1, 0, 0), "creating semaphore");
56 	TESTR(r, sem_init(&sem2, 0, 1), "creating semaphore");
57 
58 	/* Cancellation on uncontended sem_wait */
59 	seqno = 0;
60 	TESTR(r, pthread_create(&td, 0, start_sem_wait, 0), "failed to create thread");
61 	TESTR(r, pthread_cancel(td), "canceling");
62 	sem_post(&sem1);
63 	TESTR(r, pthread_join(td, &res), "joining canceled thread after uncontended sem_wait");
64 	TESTC(res == PTHREAD_CANCELED, "canceled thread exit status after uncontended sem_wait");
65 	TESTC(seqno == 1, "uncontended sem_wait");
66 
67 	/* Cancellation on blocking sem_wait */
68 	seqno = 0;
69 	sem_trywait(&sem2);
70 	TESTR(r, pthread_create(&td, 0, start_sem_wait, 0), "failed to create thread");
71 	TESTR(r, pthread_cancel(td), "canceling");
72 	sem_post(&sem1);
73 	TESTR(r, pthread_join(td, &res), "joining canceled thread after blocking sem_wait");
74 	TESTC(res == PTHREAD_CANCELED, "canceled thread exit status after blocking sem_wait");
75 	TESTC(seqno == 1, "blocking sem_wait");
76 
77 	/* Cancellation on uncontended sem_timedwait */
78 	seqno = 0;
79 	sem_post(&sem2);
80 	TESTR(r, pthread_create(&td, 0, start_sem_timedwait, 0), "failed to create thread");
81 	TESTR(r, pthread_cancel(td), "canceling");
82 	sem_post(&sem1);
83 	TESTR(r, pthread_join(td, &res), "joining canceled thread after uncontended sem_timedwait");
84 	TESTC(res == PTHREAD_CANCELED, "canceled thread exit status after uncontended sem_timedwait");
85 	TESTC(seqno == 1, "uncontended sem_timedwait");
86 
87 	/* Cancellation on blocking sem_timedwait */
88 	seqno = 0;
89 	sem_trywait(&sem2);
90 	TESTR(r, pthread_create(&td, 0, start_sem_timedwait, 0), "failed to create thread");
91 	TESTR(r, pthread_cancel(td), "canceling");
92 	sem_post(&sem1);
93 	TESTR(r, pthread_join(td, &res), "joining canceled thread after blocking sem_timedwait");
94 	TESTC(res == PTHREAD_CANCELED, "canceled thread exit status after blocking sem_timedwait");
95 	TESTC(seqno == 1, "blocking sem_timedwait");
96 
97 	/* Cancellation on blocking __sem_timedwait_time64 */
98 	seqno = 0;
99 	sem_trywait(&sem2);
100 	TESTR(r, pthread_create(&td, 0, start_sem_timedwait_time64, 0), "failed to create thread");
101 	TESTR(r, pthread_cancel(td), "canceling");
102 	sem_post(&sem1);
103 	TESTR(r, pthread_join(td, &res), "joining canceled thread after blocking __sem_timedwait_time64");
104 	TESTC(res == PTHREAD_CANCELED, "canceled thread exit status after blocking __sem_timedwait_time64");
105 	TESTC(seqno == 1, "blocking __sem_timedwait_time64");
106 
107 	return t_status;
108 }
109