2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
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.
21 * @APPLE_LICENSE_HEADER_END@
26 * - timer source based on <kern/thread_call.h>
30 * Modification History:
32 * June 22, 2004 Dieter Siegmund (dieter@apple.com)
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>
43 #define _devtimer_printf printf
45 static __inline__
void
46 _devtimer_printf(__unused
const char * fmt
, ...)
53 devtimer_timeout_func dt_timeout_func
;
54 devtimer_process_func dt_process_func
;
59 UInt32 dt_retain_count
;
62 #define M_DEVTIMER M_DEVBUF
64 static __inline__
void
65 timeval_add(struct timeval tv1
, struct timeval tv2
,
66 struct timeval
* result
)
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
;
77 static __inline__
uint64_t
78 timeval_to_absolutetime(struct timeval tv
)
83 clock_interval_to_absolutetime_interval(tv
.tv_sec
, NSEC_PER_SEC
,
85 clock_interval_to_absolutetime_interval(tv
.tv_usec
, NSEC_PER_USEC
,
87 return (secs
+ usecs
);
91 __private_extern__
int
92 devtimer_valid(devtimer_ref timer
)
94 return (timer
->dt_callout
!= NULL
);
97 __private_extern__
void
98 devtimer_retain(devtimer_ref timer
)
100 OSIncrementAtomic(&timer
->dt_retain_count
);
104 __private_extern__
void
105 devtimer_invalidate(devtimer_ref timer
)
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
;
116 __private_extern__
void
117 devtimer_release(devtimer_ref timer
)
119 UInt32 old_retain_count
;
121 old_retain_count
= OSDecrementAtomic(&timer
->dt_retain_count
);
122 switch (old_retain_count
) {
124 panic("devtimer_release: retain count is 0\n");
127 devtimer_invalidate(timer
);
128 FREE(timer
, M_DEVTIMER
);
129 _devtimer_printf("devtimer: timer released\n");
138 devtimer_process(void * param0
, void * param1
)
140 int generation
= (int)param1
;
141 devtimer_process_func process_func
;
142 devtimer_timeout_func timeout_func
;
143 devtimer_ref timer
= (devtimer_ref
)param0
;
145 process_func
= timer
->dt_process_func
;
146 if (process_func
!= NULL
) {
147 (*process_func
)(timer
, devtimer_process_func_event_lock
);
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
);
156 devtimer_release(timer
);
157 if (process_func
!= NULL
) {
158 (*process_func
)(timer
, devtimer_process_func_event_unlock
);
163 __private_extern__
void *
164 devtimer_arg0(devtimer_ref timer
)
166 return (timer
->dt_arg0
);
169 __private_extern__ devtimer_ref
170 devtimer_create(devtimer_process_func process_func
, void * arg0
)
174 timer
= _MALLOC(sizeof(*timer
), M_DEVTIMER
, M_WAITOK
);
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
);
186 timer
->dt_process_func
= process_func
;
187 timer
->dt_arg0
= arg0
;
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
)
197 if (timer
->dt_callout
== NULL
) {
198 printf("devtimer_set_absolute: uninitialized/freed timer\n");
201 devtimer_cancel(timer
);
202 if (timeout_func
== NULL
) {
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
));
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
)
224 struct timeval abs_time
;
225 struct timeval current_time
;
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
);
233 __private_extern__
void
234 devtimer_cancel(devtimer_ref timer
)
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
);
244 _devtimer_printf("devtimer: delayed release\n");
251 __private_extern__
int
252 devtimer_enabled(devtimer_ref timer
)
254 return (timer
->dt_timeout_func
!= NULL
);
257 __private_extern__
int32_t
258 devtimer_current_secs(void)
262 tv
= devtimer_current_time();
266 __private_extern__
struct timeval
267 devtimer_current_time(void)
273 clock_get_system_microtime(&sec
, &usec
);