xref: /illumos-gate/usr/src/lib/libc/port/rt/clock_timer.c (revision 3db86aab)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #pragma	weak clock_getres = _clock_getres
30 #pragma	weak clock_gettime = _clock_gettime
31 #pragma	weak clock_settime = _clock_settime
32 #pragma	weak timer_create = _timer_create
33 #pragma	weak timer_delete = _timer_delete
34 #pragma	weak timer_getoverrun = _timer_getoverrun
35 #pragma	weak timer_gettime = _timer_gettime
36 #pragma	weak timer_settime = _timer_settime
37 
38 #include "synonyms.h"
39 #include <time.h>
40 #include <sys/types.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <errno.h>
44 #include "sigev_thread.h"
45 
46 /*
47  * System call wrappers found elsewhere in libc (common/sys/__clock_timer.s).
48  */
49 extern int __clock_getres(clockid_t, timespec_t *);
50 extern int __clock_gettime(clockid_t, timespec_t *);
51 extern int __clock_settime(clockid_t, const timespec_t *);
52 extern int __timer_create(clockid_t, struct sigevent *, timer_t *);
53 extern int __timer_delete(timer_t);
54 extern int __timer_getoverrun(timer_t);
55 extern int __timer_gettime(timer_t, itimerspec_t *);
56 extern int __timer_settime(timer_t, int, const itimerspec_t *, itimerspec_t *);
57 
58 /*
59  * Array of pointers to tcd's, indexed by timer id.
60  * No more than 'timer_max' timers can be created by any process.
61  */
62 int timer_max = 0;
63 thread_communication_data_t **timer_tcd;
64 static pthread_once_t timer_once = PTHREAD_ONCE_INIT;
65 
66 static void
67 timer_init(void)
68 {
69 	timer_max = (int)_sysconf(_SC_TIMER_MAX);
70 	timer_tcd = malloc(timer_max * sizeof (*timer_tcd));
71 	(void) memset(timer_tcd, 0, timer_max * sizeof (*timer_tcd));
72 }
73 
74 int
75 _clock_getres(clockid_t clock_id, timespec_t *res)
76 {
77 	return (__clock_getres(clock_id, res));
78 }
79 
80 int
81 _clock_gettime(clockid_t clock_id, timespec_t *tp)
82 {
83 	return (__clock_gettime(clock_id, tp));
84 }
85 
86 int
87 _clock_settime(clockid_t clock_id, const timespec_t *tp)
88 {
89 	return (__clock_settime(clock_id, tp));
90 }
91 
92 int
93 _timer_create(clockid_t clock_id, struct sigevent *sigevp, timer_t *timerid)
94 {
95 	struct sigevent sigevent;
96 	port_notify_t port_notify;
97 	thread_communication_data_t *tcdp;
98 	int sigev_thread = 0;
99 	int rc;
100 
101 	(void) pthread_once(&timer_once, timer_init);
102 
103 	if (sigevp != NULL &&
104 	    sigevp->sigev_notify == SIGEV_THREAD &&
105 	    sigevp->sigev_notify_function != NULL) {
106 		sigev_thread = 1;
107 		tcdp = setup_sigev_handler(sigevp, TIMER);
108 		if (tcdp == NULL)
109 			return (-1);
110 		/* copy the sigevent structure so we can modify it */
111 		sigevent = *sigevp;
112 		sigevp = &sigevent;
113 		port_notify.portnfy_port = tcdp->tcd_port;
114 		port_notify.portnfy_user = NULL;
115 		sigevp->sigev_value.sival_ptr = &port_notify;
116 	}
117 
118 	rc = __timer_create(clock_id, sigevp, timerid);
119 
120 	if (sigev_thread) {
121 		if (rc == 0) {
122 			if ((rc = launch_spawner(tcdp)) != 0)
123 				__timer_delete(*timerid);
124 			else
125 				timer_tcd[*timerid] = tcdp;
126 		}
127 		if (rc != 0)
128 			free_sigev_handler(tcdp);
129 	}
130 
131 	return (rc);
132 }
133 
134 int
135 _timer_delete(timer_t timerid)
136 {
137 	int rc;
138 
139 	if ((rc = del_sigev_timer(timerid)) == 0)
140 		return (__timer_delete(timerid));
141 	else
142 		return (rc);
143 }
144 
145 int
146 _timer_getoverrun(timer_t timerid)
147 {
148 	return (__timer_getoverrun(timerid) + sigev_timer_getoverrun(timerid));
149 }
150 
151 int
152 _timer_gettime(timer_t timerid, itimerspec_t *value)
153 {
154 	return (__timer_gettime(timerid, value));
155 }
156 
157 int
158 _timer_settime(timer_t timerid, int flags, const itimerspec_t *value,
159 	itimerspec_t *ovalue)
160 {
161 	return (__timer_settime(timerid, flags, value, ovalue));
162 }
163 
164 /*
165  * Cleanup after fork1() in the child process.
166  */
167 void
168 postfork1_child_sigev_timer(void)
169 {
170 	thread_communication_data_t *tcdp;
171 	int timer;
172 
173 	for (timer = 0; timer < timer_max; timer++) {
174 		if ((tcdp = timer_tcd[timer]) != NULL) {
175 			timer_tcd[timer] = NULL;
176 			tcd_teardown(tcdp);
177 		}
178 	}
179 }
180