xref: /netbsd-src/tests/lib/libc/sys/t_timer_create.c (revision ca453df649ce9db45b64d73678ba06cbccf9aa11)
1 /*	$NetBSD: t_timer_create.c,v 1.1 2011/07/07 06:57:54 jruoho Exp $ */
2 
3 /*-
4  * Copyright (c) 2010 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <errno.h>
30 #include <pthread.h>
31 #include <signal.h>
32 #include <string.h>
33 #include <time.h>
34 #include <unistd.h>
35 
36 #include <atf-c.h>
37 
38 #include "../../../h_macros.h"
39 
40 static void	timer_signal_create(clockid_t, int);
41 static void	timer_signal_handler(int, siginfo_t *, void *);
42 static int	timer_wait(time_t);
43 
44 #if 0
45 /*
46  * XXX: SIGEV_THREAD is not yet supported.
47  */
48 static void	timer_thread_create(clockid_t);
49 static void	timer_thread_handler(sigval_t);
50 #endif
51 
52 static timer_t t;
53 static bool error;
54 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
55 static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
56 
57 ATF_TC(timer_create_bogus);
58 ATF_TC_HEAD(timer_create_bogus, tc)
59 {
60 
61 	/* Cf. PR lib/42434. */
62 	atf_tc_set_md_var(tc, "descr",
63 	    "Checks timer_create(2)'s error checking");
64 }
65 
66 ATF_TC_BODY(timer_create_bogus, tc)
67 {
68 	struct sigevent evt;
69 
70 	(void)memset(&evt, 0, sizeof(struct sigevent));
71 
72 	evt.sigev_signo = -1;
73 	evt.sigev_notify = SIGEV_SIGNAL;
74 
75 	if (timer_create(CLOCK_REALTIME, &evt, &t) == 0)
76 		goto fail;
77 
78 	evt.sigev_signo = SIGUSR1;
79 	evt.sigev_notify = SIGEV_THREAD + 100;
80 
81 	if (timer_create(CLOCK_REALTIME, &evt, &t) == 0)
82 		goto fail;
83 
84 	evt.sigev_signo = SIGUSR1;
85 	evt.sigev_value.sival_int = 0;
86 	evt.sigev_notify = SIGEV_SIGNAL;
87 
88 	if (timer_create(CLOCK_REALTIME + 100, &evt, &t) == 0)
89 		goto fail;
90 
91 	t = 0;
92 
93 	return;
94 
95 fail:
96 	atf_tc_fail("timer_create() successful with bogus values");
97 }
98 
99 ATF_TC(timer_create_signal_realtime);
100 ATF_TC_HEAD(timer_create_signal_realtime, tc)
101 {
102 
103 	atf_tc_set_md_var(tc, "descr",
104 	    "Checks timer_create(2) with CLOCK_REALTIME and sigevent(3), "
105 	    "SIGEV_SIGNAL");
106 }
107 
108 ATF_TC_BODY(timer_create_signal_realtime, tc)
109 {
110 	int i, signals[6] = {
111 		SIGALRM, SIGIO, SIGPROF, SIGUSR1, SIGUSR2, -1
112 	};
113 
114 	for (i = 0; signals[i] > 0; i++)
115 		timer_signal_create(CLOCK_REALTIME, signals[i]);
116 }
117 
118 ATF_TC(timer_create_signal_monotonic);
119 ATF_TC_HEAD(timer_create_signal_monotonic, tc)
120 {
121 
122 	atf_tc_set_md_var(tc, "descr",
123 	    "Checks timer_create(2) with CLOCK_MONOTONIC and sigevent(3), "
124 	    "SIGEV_SIGNAL");
125 }
126 
127 ATF_TC_BODY(timer_create_signal_monotonic, tc)
128 {
129 	int i, signals[6] = {
130 		SIGALRM, SIGIO, SIGPROF, SIGUSR1, SIGUSR2, -1
131 	};
132 
133 	for (i = 0; signals[i] > 0; i++)
134 		timer_signal_create(CLOCK_MONOTONIC, signals[i]);
135 }
136 
137 static void
138 timer_signal_create(clockid_t cid, int sig)
139 {
140 	struct itimerspec tim;
141 	struct sigaction act;
142 	struct sigevent evt;
143 	const char *errstr;
144 	sigset_t set;
145 
146 	error = true;
147 
148 	(void)memset(&evt, 0, sizeof(struct sigevent));
149 	(void)memset(&act, 0, sizeof(struct sigaction));
150 	(void)memset(&tim, 0, sizeof(struct itimerspec));
151 
152 	act.sa_flags = SA_SIGINFO;
153 	act.sa_sigaction = timer_signal_handler;
154 
155 	(void)sigemptyset(&act.sa_mask);
156 
157 	if (sigaction(sig, &act, NULL) != 0) {
158 		errstr = "sigaction()";
159 		goto fail;
160 	}
161 
162 	(void)sigemptyset(&set);
163 	(void)sigaddset(&set, sig);
164 
165 	if (sigprocmask(SIG_SETMASK, &set, NULL) != 0) {
166 		errstr = "sigprocmask()";
167 		goto fail;
168 	}
169 
170 	evt.sigev_signo = sig;
171 	evt.sigev_value.sival_ptr = &t;
172 	evt.sigev_notify = SIGEV_SIGNAL;
173 
174 	if (timer_create(cid, &evt, &t) != 0) {
175 		errstr = "timer_create()";
176 		goto fail;
177 	}
178 
179 	tim.it_value.tv_sec = 0;
180 	tim.it_value.tv_nsec = 1000 * 1000;
181 
182 	if (timer_settime(t, 0, &tim, NULL) != 0) {
183 		errstr = "timer_settime()";
184 		goto fail;
185 	}
186 
187 	if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) {
188 		errstr = "sigprocmask()";
189 		goto fail;
190 	}
191 
192 	errno = timer_wait(1);
193 
194 	if (errno != 0) {
195 		errstr = "timer_wait()";
196 		goto fail;
197 	}
198 
199 	return;
200 
201 fail:
202 	atf_tc_fail_errno("%s failed (sig %d, clock %d)", errstr, sig, cid);
203 }
204 
205 static void
206 timer_signal_handler(int signo, siginfo_t *si, void *osi)
207 {
208 	timer_t *tp;
209 
210 	if (pthread_mutex_lock(&mtx) != 0)
211 		return;
212 
213 	tp = si->si_value.sival_ptr;
214 
215 	if (*tp == t)
216 		error = false;
217 
218 	(void)pthread_cond_signal(&cond);
219 	(void)pthread_mutex_unlock(&mtx);
220 	(void)signal(signo, SIG_IGN);
221 }
222 
223 static int
224 timer_wait(time_t wait)
225 {
226 	struct timespec ts;
227 	int rv;
228 
229 	rv = pthread_mutex_lock(&mtx);
230 
231 	if (rv != 0)
232 		return rv;
233 
234 	errno = 0;
235 
236 	if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
237 
238 		if (errno == 0)
239 			errno = EFAULT;
240 
241 		return errno;
242 	}
243 
244 	ts.tv_sec += wait;
245 	rv = pthread_cond_timedwait(&cond, &mtx, &ts);
246 
247 	if (rv != 0)
248 		return rv;
249 
250 	rv = pthread_mutex_unlock(&mtx);
251 
252 	if (rv != 0)
253 		return rv;
254 
255 	if (error != false)
256 		return EPROCUNAVAIL;
257 
258 	return timer_delete(t);
259 }
260 
261 #if 0
262 ATF_TC(timer_create_thread);
263 ATF_TC_HEAD(timer_create_thread, tc)
264 {
265 
266 	atf_tc_set_md_var(tc, "descr",
267 	    "Checks timer_create(2) and sigevent(3), SIGEV_THREAD");
268 }
269 
270 ATF_TC_BODY(timer_create_thread, tc)
271 {
272 	timer_thread_create(CLOCK_REALTIME);
273 }
274 
275 static void
276 timer_thread_create(clockid_t cid)
277 {
278 	struct itimerspec tim;
279 	struct sigevent evt;
280 	const char *errstr;
281 
282 	error = true;
283 
284 	(void)memset(&evt, 0, sizeof(struct sigevent));
285 	(void)memset(&tim, 0, sizeof(struct itimerspec));
286 
287 	evt.sigev_notify = SIGEV_THREAD;
288 	evt.sigev_value.sival_ptr = &t;
289 	evt.sigev_notify_function = timer_thread_handler;
290 	evt.sigev_notify_attributes = NULL;
291 
292 	if (timer_create(cid, &evt, &t) != 0) {
293 		errstr = "timer_create()";
294 		goto fail;
295 	}
296 
297 	tim.it_value.tv_sec = 1;
298 	tim.it_value.tv_nsec = 0;
299 
300 	if (timer_settime(t, 0, &tim, NULL) != 0) {
301 		errstr = "timer_settime()";
302 		goto fail;
303 	}
304 
305 	errno = timer_wait(3);
306 
307 	if (errno != 0) {
308 		errstr = "timer_wait()";
309 		goto fail;
310 	}
311 
312 	return;
313 
314 fail:
315 	atf_tc_fail_errno("%s failed (clock %d)", errstr, cid);
316 }
317 
318 static void
319 timer_thread_handler(sigval_t sv)
320 {
321 	timer_t *tp;
322 
323 	if (pthread_mutex_lock(&mtx) != 0)
324 		return;
325 
326 	tp = sv.sival_ptr;
327 
328 	if (*tp == t)
329 		error = false;
330 
331 	(void)pthread_cond_signal(&cond);
332 	(void)pthread_mutex_unlock(&mtx);
333 }
334 #endif
335 
336 ATF_TP_ADD_TCS(tp)
337 {
338 
339 	ATF_TP_ADD_TC(tp, timer_create_bogus);
340 	ATF_TP_ADD_TC(tp, timer_create_signal_realtime);
341 	ATF_TP_ADD_TC(tp, timer_create_signal_monotonic);
342      /*	ATF_TP_ADD_TC(tp, timer_create_thread); */
343 
344 	return atf_no_error();
345 }
346