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