2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
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
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
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.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
33 * - timer source based on <kern/thread_call.h>
37 * Modification History:
39 * June 22, 2004 Dieter Siegmund (dieter@apple.com)
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>
50 #define _devtimer_printf printf
52 static __inline__
void
53 _devtimer_printf(__unused
const char * fmt
, ...)
60 devtimer_timeout_func dt_timeout_func
;
61 devtimer_process_func dt_process_func
;
66 UInt32 dt_retain_count
;
69 #define M_DEVTIMER M_DEVBUF
71 static __inline__
void
72 timeval_add(struct timeval tv1
, struct timeval tv2
,
73 struct timeval
* result
)
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
;
84 static __inline__
uint64_t
85 timeval_to_absolutetime(struct timeval tv
)
90 clock_interval_to_absolutetime_interval(tv
.tv_sec
, NSEC_PER_SEC
,
92 clock_interval_to_absolutetime_interval(tv
.tv_usec
, NSEC_PER_USEC
,
94 return (secs
+ usecs
);
98 __private_extern__
int
99 devtimer_valid(devtimer_ref timer
)
101 return (timer
->dt_callout
!= NULL
);
104 __private_extern__
void
105 devtimer_retain(devtimer_ref timer
)
107 OSIncrementAtomic(&timer
->dt_retain_count
);
111 __private_extern__
void
112 devtimer_invalidate(devtimer_ref timer
)
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
;
123 __private_extern__
void
124 devtimer_release(devtimer_ref timer
)
126 UInt32 old_retain_count
;
128 old_retain_count
= OSDecrementAtomic(&timer
->dt_retain_count
);
129 switch (old_retain_count
) {
131 panic("devtimer_release: retain count is 0\n");
134 devtimer_invalidate(timer
);
135 FREE(timer
, M_DEVTIMER
);
136 _devtimer_printf("devtimer: timer released\n");
145 devtimer_process(void * param0
, void * param1
)
147 int generation
= (int)param1
;
148 devtimer_process_func process_func
;
149 devtimer_timeout_func timeout_func
;
150 devtimer_ref timer
= (devtimer_ref
)param0
;
152 process_func
= timer
->dt_process_func
;
153 if (process_func
!= NULL
) {
154 (*process_func
)(timer
, devtimer_process_func_event_lock
);
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
);
163 devtimer_release(timer
);
164 if (process_func
!= NULL
) {
165 (*process_func
)(timer
, devtimer_process_func_event_unlock
);
170 __private_extern__
void *
171 devtimer_arg0(devtimer_ref timer
)
173 return (timer
->dt_arg0
);
176 __private_extern__ devtimer_ref
177 devtimer_create(devtimer_process_func process_func
, void * arg0
)
181 timer
= _MALLOC(sizeof(*timer
), M_DEVTIMER
, M_WAITOK
);
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
);
193 timer
->dt_process_func
= process_func
;
194 timer
->dt_arg0
= arg0
;
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
)
204 if (timer
->dt_callout
== NULL
) {
205 printf("devtimer_set_absolute: uninitialized/freed timer\n");
208 devtimer_cancel(timer
);
209 if (timeout_func
== NULL
) {
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
));
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
)
231 struct timeval abs_time
;
232 struct timeval current_time
;
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
);
240 __private_extern__
void
241 devtimer_cancel(devtimer_ref timer
)
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
);
251 _devtimer_printf("devtimer: delayed release\n");
258 __private_extern__
int
259 devtimer_enabled(devtimer_ref timer
)
261 return (timer
->dt_timeout_func
!= NULL
);
264 __private_extern__
int32_t
265 devtimer_current_secs(void)
269 tv
= devtimer_current_time();
273 __private_extern__
struct timeval
274 devtimer_current_time(void)
280 clock_get_system_microtime(&sec
, &usec
);