xref: /openbsd-src/regress/lib/libpthread/semaphore/sem_timedwait/sem_timedwait.c (revision 6cea90f62a7cf7cc9e535c7671ccd0ca1974f69f)
1*6cea90f6Santon /*	$OpenBSD: sem_timedwait.c,v 1.5 2022/05/13 15:32:49 anton Exp $	*/
2db068fc7Sguenther /*
3db068fc7Sguenther  * Martin Pieuchot <mpi@openbsd.org>, 2011. Public Domain.
4db068fc7Sguenther  */
5db068fc7Sguenther 
6c672e670Scheloha #include <sys/types.h>
7c672e670Scheloha #include <sys/sysctl.h>
8c672e670Scheloha 
9db068fc7Sguenther #include <err.h>
10db068fc7Sguenther #include <errno.h>
11db068fc7Sguenther #include <unistd.h>
12db068fc7Sguenther #include <semaphore.h>
13db068fc7Sguenther #include <signal.h>
14db068fc7Sguenther #include <pthread.h>
15db068fc7Sguenther #include "test.h"
16db068fc7Sguenther 
17db068fc7Sguenther 
18db068fc7Sguenther void *waiter(void *arg);
19db068fc7Sguenther 
20db068fc7Sguenther void
handler(int sig)21db068fc7Sguenther handler(int sig)
22db068fc7Sguenther {
23db068fc7Sguenther 	static char message[] = "got sig\n";
24db068fc7Sguenther 
25db068fc7Sguenther 	write(STDERR_FILENO, message, sizeof(message) - 1);
26db068fc7Sguenther }
27db068fc7Sguenther 
28db068fc7Sguenther sem_t sem;
29db068fc7Sguenther volatile int posted = 0, eintr_ok = 0;
30db068fc7Sguenther 
31db068fc7Sguenther int
main(int argc,char ** argv)32db068fc7Sguenther main(int argc, char **argv)
33db068fc7Sguenther {
34db068fc7Sguenther 	pthread_t th;
35c672e670Scheloha 	struct clockinfo info;
36db068fc7Sguenther 	struct sigaction sa;
37c672e670Scheloha 	struct timespec delay, ts, ts2;
38c672e670Scheloha 	size_t infosize = sizeof(info);
39c672e670Scheloha 	int mib[] = { CTL_KERN, KERN_CLOCKRATE };
40db068fc7Sguenther 
41db068fc7Sguenther 	CHECKr(clock_gettime(CLOCK_REALTIME, &ts));
42db068fc7Sguenther 	ts.tv_sec += 3;
43db068fc7Sguenther 	CHECKn(sem_timedwait(&sem, &ts));
44db068fc7Sguenther 	ASSERT(errno == EINVAL);
45db068fc7Sguenther 
46db068fc7Sguenther 	CHECKr(sem_init(&sem, 0, 0));
47db068fc7Sguenther 
48db068fc7Sguenther 	CHECKr(pthread_create(&th, NULL, waiter, &sem));
49db068fc7Sguenther 
50db068fc7Sguenther 	sleep(1);
51db068fc7Sguenther 
52db068fc7Sguenther 	printf("expect: sem_destroy on semaphore with waiters!\n");
53db068fc7Sguenther 	CHECKn(sem_destroy(&sem));
54db068fc7Sguenther 	ASSERT(errno == EBUSY);
55db068fc7Sguenther 
56db068fc7Sguenther 	posted = 1;
57db068fc7Sguenther 	CHECKr(sem_post(&sem));
58db068fc7Sguenther 	CHECKr(pthread_join(th, NULL));
59db068fc7Sguenther 
60db068fc7Sguenther 	/* test that sem_timedwait() resumes after handling a signal */
61db068fc7Sguenther 	memset(&sa, 0, sizeof sa);
62db068fc7Sguenther 	sa.sa_handler = &handler;
63db068fc7Sguenther 	sigemptyset(&sa.sa_mask);
64fd181be8Spirofti 	sa.sa_flags = SA_RESTART;
65db068fc7Sguenther 	if (sigaction(SIGUSR1, &sa, NULL))
66db068fc7Sguenther 		err(1, "sigaction");
67db068fc7Sguenther 	posted = 0;
68db068fc7Sguenther 	CHECKr(pthread_create(&th, NULL, waiter, &sem));
69db068fc7Sguenther 	sleep(1);
70db068fc7Sguenther 	fprintf(stderr, "sending sig\n");
71db068fc7Sguenther 	eintr_ok = 1;
72db068fc7Sguenther 	pthread_kill(th, SIGUSR1);
73db068fc7Sguenther 	sleep(1);
74db068fc7Sguenther 	fprintf(stderr, "posting\n");
75db068fc7Sguenther 	posted = 1;
76db068fc7Sguenther 	eintr_ok = 0;
77db068fc7Sguenther 	CHECKr(sem_post(&sem));
78db068fc7Sguenther 	CHECKr(pthread_join(th, NULL));
79db068fc7Sguenther 
80db068fc7Sguenther 	CHECKr(clock_gettime(CLOCK_REALTIME, &ts));
81db068fc7Sguenther 	ts.tv_sec += 2;
82db068fc7Sguenther 	CHECKn(sem_timedwait(&sem, &ts));
83db068fc7Sguenther 	ASSERT(errno == ETIMEDOUT);
84db068fc7Sguenther 	CHECKr(clock_gettime(CLOCK_REALTIME, &ts2));
85c672e670Scheloha 
86c672e670Scheloha 	fprintf(stderr, "timeout: expected %lld.%09ld actual %lld.%09ld\n",
87c672e670Scheloha 	    ts.tv_sec, ts.tv_nsec, ts2.tv_sec, ts2.tv_nsec);
88c672e670Scheloha 
89c672e670Scheloha 	/* Check that we don't return early. */
90c672e670Scheloha 	ASSERT(timespeccmp(&ts, &ts2, <=));
91c672e670Scheloha 
92c672e670Scheloha 	/*
93c672e670Scheloha 	 * Check that we don't return unusually late.  Something might be
94c672e670Scheloha 	 * off if the wait returns more than two ticks after our timeout.
95c672e670Scheloha 	 */
96c672e670Scheloha 	CHECKr(sysctl(mib, 2, &info, &infosize, NULL, 0));
97c672e670Scheloha 	delay.tv_sec = 0;
98c672e670Scheloha 	delay.tv_nsec = info.tick * 1000;	/* usecs -> nsecs */
99c672e670Scheloha 	timespecadd(&delay, &delay, &delay);	/* up to two ticks of delay */
100c672e670Scheloha 	timespecadd(&ts, &delay, &ts);
101*6cea90f6Santon 	fprintf(stderr, "timeout: expected %lld.%09ld actual %lld.%09ld\n",
102*6cea90f6Santon 	    ts2.tv_sec, ts2.tv_nsec, ts.tv_sec, ts.tv_nsec);
103c672e670Scheloha 	ASSERT(timespeccmp(&ts2, &ts, <=));
104db068fc7Sguenther 
105db068fc7Sguenther 	CHECKe(sem_destroy(&sem));
106db068fc7Sguenther 
107db068fc7Sguenther 	SUCCEED;
108db068fc7Sguenther }
109db068fc7Sguenther 
110db068fc7Sguenther void *
waiter(void * arg)111db068fc7Sguenther waiter(void *arg)
112db068fc7Sguenther {
113db068fc7Sguenther 	sem_t *semp = arg;
114db068fc7Sguenther 	struct timespec ts;
115db068fc7Sguenther 	int value;
116db068fc7Sguenther 	int r;
117db068fc7Sguenther 
118db068fc7Sguenther 	CHECKr(clock_gettime(CLOCK_REALTIME, &ts));
119db068fc7Sguenther 	ts.tv_sec += 3;
120db068fc7Sguenther 	r = sem_timedwait(semp, &ts);
121db068fc7Sguenther 	CHECKr(sem_getvalue(semp, &value));
122db068fc7Sguenther 	if (r == 0) {
123db068fc7Sguenther 		ASSERT(value == 0);
124db068fc7Sguenther 		ASSERT(posted != 0);
125db068fc7Sguenther 	} else {
126db068fc7Sguenther 		ASSERT(r == -1);
127db068fc7Sguenther 		ASSERT(errno == EINTR);
128db068fc7Sguenther 		ASSERT(eintr_ok);
129db068fc7Sguenther 		if (posted)
130db068fc7Sguenther 			ASSERT(value == 1);
131db068fc7Sguenther 		else
132db068fc7Sguenther 			ASSERT(value == 0);
133db068fc7Sguenther 	}
134db068fc7Sguenther 
135db068fc7Sguenther 	return (NULL);
136db068fc7Sguenther }
137