]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/devtimer.c
xnu-792.13.8.tar.gz
[apple/xnu.git] / bsd / net / devtimer.c
CommitLineData
91447636 1/*
5d5c5d0d
A
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
8ad349bb 4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
91447636 5 *
8ad349bb
A
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@
91447636
A
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
52static __inline__ void
53_devtimer_printf(__unused const char * fmt, ...)
54{
55}
56#endif DEVTIMER_DEBUG
57
58struct 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
71static __inline__ void
72timeval_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
84static __inline__ uint64_t
85timeval_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
99devtimer_valid(devtimer_ref timer)
100{
101 return (timer->dt_callout != NULL);
102}
103
104__private_extern__ void
105devtimer_retain(devtimer_ref timer)
106{
107 OSIncrementAtomic(&timer->dt_retain_count);
108 return;
109}
110
111__private_extern__ void
112devtimer_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
124devtimer_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
144static void
145devtimer_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 *
171devtimer_arg0(devtimer_ref timer)
172{
173 return (timer->dt_arg0);
174}
175
176__private_extern__ devtimer_ref
177devtimer_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
199devtimer_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
226devtimer_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
241devtimer_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
259devtimer_enabled(devtimer_ref timer)
260{
261 return (timer->dt_timeout_func != NULL);
262}
263
264__private_extern__ int32_t
265devtimer_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
274devtimer_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}