1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 14 */ 15 16 /* 17 * Implement timeout(9f), untimeout(9f) on top of 18 * libc timer_create, timer_settime, etc. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/systm.h> 23 #include <time.h> 24 25 typedef void (*sigev_notify_func_t)(union sigval); 26 27 /* 28 * We never actually reference anything in this array, using it 29 * just as a collection of addresses mapped from/to int values. 30 * It would be fine to take addresses even beyond the end, but 31 * to avoid confusion it's sized larger than _TIMER_MAX (32). 32 */ 33 static char timeout_base[100]; 34 35 timeout_id_t 36 timeout(void (*func)(void *), void *arg, clock_t delta) 37 { 38 struct sigevent sev; 39 struct itimerspec its; 40 timer_t tid; 41 int err; 42 43 if (delta <= 0) 44 return (NULL); 45 46 bzero(&sev, sizeof (sev)); 47 sev.sigev_notify = SIGEV_THREAD; 48 sev.sigev_value.sival_ptr = arg; 49 sev.sigev_notify_function = (sigev_notify_func_t)(uintptr_t)func; 50 err = timer_create(CLOCK_REALTIME, &sev, &tid); 51 if (err != 0) 52 return (NULL); 53 54 bzero(&its, sizeof (its)); 55 TICK_TO_TIMESTRUC(delta, &its.it_value); 56 err = timer_settime(tid, 0, &its, NULL); 57 if (err != 0) { 58 (void) timer_delete(tid); 59 return (NULL); 60 } 61 62 /* Convert return to a (sort of) pointer */ 63 return (timeout_base + tid); 64 } 65 66 clock_t 67 untimeout(timeout_id_t id_arg) 68 { 69 struct itimerspec its, oits; 70 char *id_cp = id_arg; 71 clock_t delta; 72 timer_t tid; 73 int rc; 74 75 if (id_arg == NULL) 76 return (-1); 77 78 /* Convert id_arg back to small integer. */ 79 tid = (int)(id_cp - timeout_base); 80 81 bzero(&its, sizeof (its)); 82 bzero(&oits, sizeof (oits)); 83 rc = timer_settime(tid, 0, &its, &oits); 84 if (rc != 0) { 85 delta = 0; 86 } else { 87 delta = TIMESTRUC_TO_TICK(&oits.it_value); 88 if (delta < 0) 89 delta = 0; 90 } 91 92 rc = timer_delete(tid); 93 if (rc != 0) 94 delta = -1; 95 96 return (delta); 97 } 98