]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/devtimer.c
xnu-792.13.8.tar.gz
[apple/xnu.git] / bsd / net / devtimer.c
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30
31 /*
32 * devtimer.c
33 * - timer source based on <kern/thread_call.h>
34 */
35
36 /*
37 * Modification History:
38 *
39 * June 22, 2004 Dieter Siegmund (dieter@apple.com)
40 * - created
41 */
42 #include <sys/param.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #include <kern/thread_call.h>
46 #include <net/devtimer.h>
47 #include <libkern/OSAtomic.h>
48
49 #ifdef DEVTIMER_DEBUG
50 #define _devtimer_printf printf
51 #else DEVTIMER_DEBUG
52 static __inline__ void
53 _devtimer_printf(__unused const char * fmt, ...)
54 {
55 }
56 #endif DEVTIMER_DEBUG
57
58 struct devtimer_s {
59 void * dt_callout;
60 devtimer_timeout_func dt_timeout_func;
61 devtimer_process_func dt_process_func;
62 void * dt_arg0;
63 void * dt_arg1;
64 void * dt_arg2;
65 int dt_generation;
66 UInt32 dt_retain_count;
67 };
68
69 #define M_DEVTIMER M_DEVBUF
70
71 static __inline__ void
72 timeval_add(struct timeval tv1, struct timeval tv2,
73 struct timeval * result)
74 {
75 result->tv_sec = tv1.tv_sec + tv2.tv_sec;
76 result->tv_usec = tv1.tv_usec + tv2.tv_usec;
77 if (result->tv_usec > DEVTIMER_USECS_PER_SEC) {
78 result->tv_usec -= DEVTIMER_USECS_PER_SEC;
79 result->tv_sec++;
80 }
81 return;
82 }
83
84 static __inline__ uint64_t
85 timeval_to_absolutetime(struct timeval tv)
86 {
87 uint64_t secs;
88 uint64_t usecs;
89
90 clock_interval_to_absolutetime_interval(tv.tv_sec, NSEC_PER_SEC,
91 &secs);
92 clock_interval_to_absolutetime_interval(tv.tv_usec, NSEC_PER_USEC,
93 &usecs);
94 return (secs + usecs);
95 }
96
97
98 __private_extern__ int
99 devtimer_valid(devtimer_ref timer)
100 {
101 return (timer->dt_callout != NULL);
102 }
103
104 __private_extern__ void
105 devtimer_retain(devtimer_ref timer)
106 {
107 OSIncrementAtomic(&timer->dt_retain_count);
108 return;
109 }
110
111 __private_extern__ void
112 devtimer_invalidate(devtimer_ref timer)
113 {
114 devtimer_cancel(timer);
115 timer->dt_arg0 = NULL;
116 if (timer->dt_callout != NULL) {
117 thread_call_free(timer->dt_callout);
118 timer->dt_callout = NULL;
119 }
120 return;
121 }
122
123 __private_extern__ void
124 devtimer_release(devtimer_ref timer)
125 {
126 UInt32 old_retain_count;
127
128 old_retain_count = OSDecrementAtomic(&timer->dt_retain_count);
129 switch (old_retain_count) {
130 case 0:
131 panic("devtimer_release: retain count is 0\n");
132 break;
133 case 1:
134 devtimer_invalidate(timer);
135 FREE(timer, M_DEVTIMER);
136 _devtimer_printf("devtimer: timer released\n");
137 break;
138 default:
139 break;
140 }
141 return;
142 }
143
144 static void
145 devtimer_process(void * param0, void * param1)
146 {
147 int generation = (int)param1;
148 devtimer_process_func process_func;
149 devtimer_timeout_func timeout_func;
150 devtimer_ref timer = (devtimer_ref)param0;
151
152 process_func = timer->dt_process_func;
153 if (process_func != NULL) {
154 (*process_func)(timer, devtimer_process_func_event_lock);
155 }
156 timeout_func = timer->dt_timeout_func;
157 if (timeout_func != NULL) {
158 timer->dt_timeout_func = NULL;
159 if (timer->dt_generation == generation) {
160 (*timeout_func)(timer->dt_arg0, timer->dt_arg1, timer->dt_arg2);
161 }
162 }
163 devtimer_release(timer);
164 if (process_func != NULL) {
165 (*process_func)(timer, devtimer_process_func_event_unlock);
166 }
167 return;
168 }
169
170 __private_extern__ void *
171 devtimer_arg0(devtimer_ref timer)
172 {
173 return (timer->dt_arg0);
174 }
175
176 __private_extern__ devtimer_ref
177 devtimer_create(devtimer_process_func process_func, void * arg0)
178 {
179 devtimer_ref timer;
180
181 timer = _MALLOC(sizeof(*timer), M_DEVTIMER, M_WAITOK);
182 if (timer == NULL) {
183 return (timer);
184 }
185 bzero(timer, sizeof(*timer));
186 devtimer_retain(timer);
187 timer->dt_callout = thread_call_allocate(devtimer_process, timer);
188 if (timer->dt_callout == NULL) {
189 _devtimer_printf("devtimer: thread_call_allocate failed\n");
190 devtimer_release(timer);
191 timer = NULL;
192 }
193 timer->dt_process_func = process_func;
194 timer->dt_arg0 = arg0;
195 return (timer);
196 }
197
198 __private_extern__ void
199 devtimer_set_absolute(devtimer_ref timer,
200 struct timeval abs_time,
201 devtimer_timeout_func timeout_func,
202 void * arg1, void * arg2)
203 {
204 if (timer->dt_callout == NULL) {
205 printf("devtimer_set_absolute: uninitialized/freed timer\n");
206 return;
207 }
208 devtimer_cancel(timer);
209 if (timeout_func == NULL) {
210 return;
211 }
212 timer->dt_timeout_func = timeout_func;
213 timer->dt_arg1 = arg1;
214 timer->dt_arg2 = arg2;
215 _devtimer_printf("devtimer: wakeup time is (%d.%d)\n",
216 abs_time.tv_sec, abs_time.tv_usec);
217 timer->dt_generation++;
218 devtimer_retain(timer);
219 thread_call_enter1_delayed(timer->dt_callout,
220 (thread_call_param_t)timer->dt_generation,
221 timeval_to_absolutetime(abs_time));
222 return;
223 }
224
225 __private_extern__ void
226 devtimer_set_relative(devtimer_ref timer,
227 struct timeval rel_time,
228 devtimer_timeout_func timeout_func,
229 void * arg1, void * arg2)
230 {
231 struct timeval abs_time;
232 struct timeval current_time;
233
234 current_time = devtimer_current_time();
235 timeval_add(current_time, rel_time, &abs_time);
236 devtimer_set_absolute(timer, abs_time, timeout_func, arg1, arg2);
237 return;
238 }
239
240 __private_extern__ void
241 devtimer_cancel(devtimer_ref timer)
242 {
243 if (timer->dt_timeout_func != NULL) {
244 timer->dt_timeout_func = NULL;
245 if (timer->dt_callout != NULL) {
246 _devtimer_printf("devtimer: cancelling timer source\n");
247 if (thread_call_cancel(timer->dt_callout)) {
248 devtimer_release(timer);
249 }
250 else {
251 _devtimer_printf("devtimer: delayed release\n");
252 }
253 }
254 }
255 return;
256 }
257
258 __private_extern__ int
259 devtimer_enabled(devtimer_ref timer)
260 {
261 return (timer->dt_timeout_func != NULL);
262 }
263
264 __private_extern__ int32_t
265 devtimer_current_secs(void)
266 {
267 struct timeval tv;
268
269 tv = devtimer_current_time();
270 return (tv.tv_sec);
271 }
272
273 __private_extern__ struct timeval
274 devtimer_current_time(void)
275 {
276 struct timeval tv;
277 uint32_t sec;
278 uint32_t usec;
279
280 clock_get_system_microtime(&sec, &usec);
281 tv.tv_sec = sec;
282 tv.tv_usec = usec;
283 return (tv);
284 }