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