2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
25 * - timer source based on <kern/thread_call.h>
29 * Modification History:
31 * June 22, 2004 Dieter Siegmund (dieter@apple.com)
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <kern/thread_call.h>
38 #include <net/devtimer.h>
39 #include <libkern/OSAtomic.h>
42 #define _devtimer_printf printf
44 static __inline__
void
45 _devtimer_printf(__unused
const char * fmt
, ...)
52 devtimer_timeout_func dt_timeout_func
;
53 devtimer_process_func dt_process_func
;
58 UInt32 dt_retain_count
;
61 #define M_DEVTIMER M_DEVBUF
63 static __inline__
void
64 timeval_add(struct timeval tv1
, struct timeval tv2
,
65 struct timeval
* result
)
67 result
->tv_sec
= tv1
.tv_sec
+ tv2
.tv_sec
;
68 result
->tv_usec
= tv1
.tv_usec
+ tv2
.tv_usec
;
69 if (result
->tv_usec
> DEVTIMER_USECS_PER_SEC
) {
70 result
->tv_usec
-= DEVTIMER_USECS_PER_SEC
;
76 static __inline__
uint64_t
77 timeval_to_absolutetime(struct timeval tv
)
82 clock_interval_to_absolutetime_interval(tv
.tv_sec
, NSEC_PER_SEC
,
84 clock_interval_to_absolutetime_interval(tv
.tv_usec
, NSEC_PER_USEC
,
86 return (secs
+ usecs
);
90 __private_extern__
int
91 devtimer_valid(devtimer_ref timer
)
93 return (timer
->dt_callout
!= NULL
);
96 __private_extern__
void
97 devtimer_retain(devtimer_ref timer
)
99 OSIncrementAtomic(&timer
->dt_retain_count
);
103 __private_extern__
void
104 devtimer_invalidate(devtimer_ref timer
)
106 devtimer_cancel(timer
);
107 timer
->dt_arg0
= NULL
;
108 if (timer
->dt_callout
!= NULL
) {
109 thread_call_free(timer
->dt_callout
);
110 timer
->dt_callout
= NULL
;
115 __private_extern__
void
116 devtimer_release(devtimer_ref timer
)
118 UInt32 old_retain_count
;
120 old_retain_count
= OSDecrementAtomic(&timer
->dt_retain_count
);
121 switch (old_retain_count
) {
123 panic("devtimer_release: retain count is 0\n");
126 devtimer_invalidate(timer
);
127 FREE(timer
, M_DEVTIMER
);
128 _devtimer_printf("devtimer: timer released\n");
137 devtimer_process(void * param0
, void * param1
)
139 int generation
= (int)param1
;
140 devtimer_process_func process_func
;
141 devtimer_timeout_func timeout_func
;
142 devtimer_ref timer
= (devtimer_ref
)param0
;
144 process_func
= timer
->dt_process_func
;
145 if (process_func
!= NULL
) {
146 (*process_func
)(timer
, devtimer_process_func_event_lock
);
148 timeout_func
= timer
->dt_timeout_func
;
149 if (timeout_func
!= NULL
) {
150 timer
->dt_timeout_func
= NULL
;
151 if (timer
->dt_generation
== generation
) {
152 (*timeout_func
)(timer
->dt_arg0
, timer
->dt_arg1
, timer
->dt_arg2
);
155 devtimer_release(timer
);
156 if (process_func
!= NULL
) {
157 (*process_func
)(timer
, devtimer_process_func_event_unlock
);
162 __private_extern__
void *
163 devtimer_arg0(devtimer_ref timer
)
165 return (timer
->dt_arg0
);
168 __private_extern__ devtimer_ref
169 devtimer_create(devtimer_process_func process_func
, void * arg0
)
173 timer
= _MALLOC(sizeof(*timer
), M_DEVTIMER
, M_WAITOK
);
177 bzero(timer
, sizeof(*timer
));
178 devtimer_retain(timer
);
179 timer
->dt_callout
= thread_call_allocate(devtimer_process
, timer
);
180 if (timer
->dt_callout
== NULL
) {
181 _devtimer_printf("devtimer: thread_call_allocate failed\n");
182 devtimer_release(timer
);
185 timer
->dt_process_func
= process_func
;
186 timer
->dt_arg0
= arg0
;
190 __private_extern__
void
191 devtimer_set_absolute(devtimer_ref timer
,
192 struct timeval abs_time
,
193 devtimer_timeout_func timeout_func
,
194 void * arg1
, void * arg2
)
196 if (timer
->dt_callout
== NULL
) {
197 printf("devtimer_set_absolute: uninitialized/freed timer\n");
200 devtimer_cancel(timer
);
201 if (timeout_func
== NULL
) {
204 timer
->dt_timeout_func
= timeout_func
;
205 timer
->dt_arg1
= arg1
;
206 timer
->dt_arg2
= arg2
;
207 _devtimer_printf("devtimer: wakeup time is (%d.%d)\n",
208 abs_time
.tv_sec
, abs_time
.tv_usec
);
209 timer
->dt_generation
++;
210 devtimer_retain(timer
);
211 thread_call_enter1_delayed(timer
->dt_callout
,
212 (thread_call_param_t
)timer
->dt_generation
,
213 timeval_to_absolutetime(abs_time
));
217 __private_extern__
void
218 devtimer_set_relative(devtimer_ref timer
,
219 struct timeval rel_time
,
220 devtimer_timeout_func timeout_func
,
221 void * arg1
, void * arg2
)
223 struct timeval abs_time
;
224 struct timeval current_time
;
226 current_time
= devtimer_current_time();
227 timeval_add(current_time
, rel_time
, &abs_time
);
228 devtimer_set_absolute(timer
, abs_time
, timeout_func
, arg1
, arg2
);
232 __private_extern__
void
233 devtimer_cancel(devtimer_ref timer
)
235 if (timer
->dt_timeout_func
!= NULL
) {
236 timer
->dt_timeout_func
= NULL
;
237 if (timer
->dt_callout
!= NULL
) {
238 _devtimer_printf("devtimer: cancelling timer source\n");
239 if (thread_call_cancel(timer
->dt_callout
)) {
240 devtimer_release(timer
);
243 _devtimer_printf("devtimer: delayed release\n");
250 __private_extern__
int
251 devtimer_enabled(devtimer_ref timer
)
253 return (timer
->dt_timeout_func
!= NULL
);
256 __private_extern__
int32_t
257 devtimer_current_secs(void)
261 tv
= devtimer_current_time();
265 __private_extern__
struct timeval
266 devtimer_current_time(void)
272 clock_get_system_microtime(&sec
, &usec
);