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
timeout(void (* func)(void *),void * arg,clock_t delta)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
untimeout(timeout_id_t id_arg)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