1570af302Sopenharmony_ci// sem_wait and sem_timedwait are cancellation points
2570af302Sopenharmony_ci#include <pthread.h>
3570af302Sopenharmony_ci#include <semaphore.h>
4570af302Sopenharmony_ci#include <string.h>
5570af302Sopenharmony_ci#include "test.h"
6570af302Sopenharmony_ci
7570af302Sopenharmony_ci#define TESTC(c, m) ( (c) || (t_error("%s failed (" m ")\n", #c), 0) )
8570af302Sopenharmony_ci#define TESTR(r, f, m) ( \
9570af302Sopenharmony_ci	((r) = (f)) == 0 || (t_error("%s failed: %s (" m ")\n", #f, strerror(r)), 0) )
10570af302Sopenharmony_ci
11570af302Sopenharmony_ciextern int __sem_timedwait_time64(sem_t *__restrict, const struct timespec *__restrict);
12570af302Sopenharmony_ci
13570af302Sopenharmony_cistatic sem_t sem1, sem2;
14570af302Sopenharmony_ci
15570af302Sopenharmony_cistatic int seqno;
16570af302Sopenharmony_ci
17570af302Sopenharmony_cistatic void wait_cancel(void *arg)
18570af302Sopenharmony_ci{
19570af302Sopenharmony_ci	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
20570af302Sopenharmony_ci	while (sem_wait(&sem1));
21570af302Sopenharmony_ci	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
22570af302Sopenharmony_ci	seqno = 1;
23570af302Sopenharmony_ci}
24570af302Sopenharmony_ci
25570af302Sopenharmony_cistatic void *start_sem_wait(void *arg)
26570af302Sopenharmony_ci{
27570af302Sopenharmony_ci	wait_cancel(arg);
28570af302Sopenharmony_ci	sem_wait(&sem2);
29570af302Sopenharmony_ci	seqno = 2;
30570af302Sopenharmony_ci	return 0;
31570af302Sopenharmony_ci}
32570af302Sopenharmony_ci
33570af302Sopenharmony_cistatic void *start_sem_timedwait(void *arg)
34570af302Sopenharmony_ci{
35570af302Sopenharmony_ci	wait_cancel(arg);
36570af302Sopenharmony_ci	sem_timedwait(&sem2, &(struct timespec){1, 0});
37570af302Sopenharmony_ci	seqno = 2;
38570af302Sopenharmony_ci	return 0;
39570af302Sopenharmony_ci}
40570af302Sopenharmony_ci
41570af302Sopenharmony_cistatic void *start_sem_timedwait_time64(void *arg)
42570af302Sopenharmony_ci{
43570af302Sopenharmony_ci	wait_cancel(arg);
44570af302Sopenharmony_ci	__sem_timedwait_time64(&sem2, &(struct timespec){1, 0});
45570af302Sopenharmony_ci	seqno = 2;
46570af302Sopenharmony_ci	return 0;
47570af302Sopenharmony_ci}
48570af302Sopenharmony_ci
49570af302Sopenharmony_ciint main(void)
50570af302Sopenharmony_ci{
51570af302Sopenharmony_ci	pthread_t td;
52570af302Sopenharmony_ci	int r;
53570af302Sopenharmony_ci	void *res;
54570af302Sopenharmony_ci
55570af302Sopenharmony_ci	TESTR(r, sem_init(&sem1, 0, 0), "creating semaphore");
56570af302Sopenharmony_ci	TESTR(r, sem_init(&sem2, 0, 1), "creating semaphore");
57570af302Sopenharmony_ci
58570af302Sopenharmony_ci	/* Cancellation on uncontended sem_wait */
59570af302Sopenharmony_ci	seqno = 0;
60570af302Sopenharmony_ci	TESTR(r, pthread_create(&td, 0, start_sem_wait, 0), "failed to create thread");
61570af302Sopenharmony_ci	TESTR(r, pthread_cancel(td), "canceling");
62570af302Sopenharmony_ci	sem_post(&sem1);
63570af302Sopenharmony_ci	TESTR(r, pthread_join(td, &res), "joining canceled thread after uncontended sem_wait");
64570af302Sopenharmony_ci	TESTC(res == PTHREAD_CANCELED, "canceled thread exit status after uncontended sem_wait");
65570af302Sopenharmony_ci	TESTC(seqno == 1, "uncontended sem_wait");
66570af302Sopenharmony_ci
67570af302Sopenharmony_ci	/* Cancellation on blocking sem_wait */
68570af302Sopenharmony_ci	seqno = 0;
69570af302Sopenharmony_ci	sem_trywait(&sem2);
70570af302Sopenharmony_ci	TESTR(r, pthread_create(&td, 0, start_sem_wait, 0), "failed to create thread");
71570af302Sopenharmony_ci	TESTR(r, pthread_cancel(td), "canceling");
72570af302Sopenharmony_ci	sem_post(&sem1);
73570af302Sopenharmony_ci	TESTR(r, pthread_join(td, &res), "joining canceled thread after blocking sem_wait");
74570af302Sopenharmony_ci	TESTC(res == PTHREAD_CANCELED, "canceled thread exit status after blocking sem_wait");
75570af302Sopenharmony_ci	TESTC(seqno == 1, "blocking sem_wait");
76570af302Sopenharmony_ci
77570af302Sopenharmony_ci	/* Cancellation on uncontended sem_timedwait */
78570af302Sopenharmony_ci	seqno = 0;
79570af302Sopenharmony_ci	sem_post(&sem2);
80570af302Sopenharmony_ci	TESTR(r, pthread_create(&td, 0, start_sem_timedwait, 0), "failed to create thread");
81570af302Sopenharmony_ci	TESTR(r, pthread_cancel(td), "canceling");
82570af302Sopenharmony_ci	sem_post(&sem1);
83570af302Sopenharmony_ci	TESTR(r, pthread_join(td, &res), "joining canceled thread after uncontended sem_timedwait");
84570af302Sopenharmony_ci	TESTC(res == PTHREAD_CANCELED, "canceled thread exit status after uncontended sem_timedwait");
85570af302Sopenharmony_ci	TESTC(seqno == 1, "uncontended sem_timedwait");
86570af302Sopenharmony_ci
87570af302Sopenharmony_ci	/* Cancellation on blocking sem_timedwait */
88570af302Sopenharmony_ci	seqno = 0;
89570af302Sopenharmony_ci	sem_trywait(&sem2);
90570af302Sopenharmony_ci	TESTR(r, pthread_create(&td, 0, start_sem_timedwait, 0), "failed to create thread");
91570af302Sopenharmony_ci	TESTR(r, pthread_cancel(td), "canceling");
92570af302Sopenharmony_ci	sem_post(&sem1);
93570af302Sopenharmony_ci	TESTR(r, pthread_join(td, &res), "joining canceled thread after blocking sem_timedwait");
94570af302Sopenharmony_ci	TESTC(res == PTHREAD_CANCELED, "canceled thread exit status after blocking sem_timedwait");
95570af302Sopenharmony_ci	TESTC(seqno == 1, "blocking sem_timedwait");
96570af302Sopenharmony_ci
97570af302Sopenharmony_ci	/* Cancellation on blocking __sem_timedwait_time64 */
98570af302Sopenharmony_ci	seqno = 0;
99570af302Sopenharmony_ci	sem_trywait(&sem2);
100570af302Sopenharmony_ci	TESTR(r, pthread_create(&td, 0, start_sem_timedwait_time64, 0), "failed to create thread");
101570af302Sopenharmony_ci	TESTR(r, pthread_cancel(td), "canceling");
102570af302Sopenharmony_ci	sem_post(&sem1);
103570af302Sopenharmony_ci	TESTR(r, pthread_join(td, &res), "joining canceled thread after blocking __sem_timedwait_time64");
104570af302Sopenharmony_ci	TESTC(res == PTHREAD_CANCELED, "canceled thread exit status after blocking __sem_timedwait_time64");
105570af302Sopenharmony_ci	TESTC(seqno == 1, "blocking __sem_timedwait_time64");
106570af302Sopenharmony_ci
107570af302Sopenharmony_ci	return t_status;
108570af302Sopenharmony_ci}
109