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