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