2 * Copyright (c) 2004,2007-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
31 * - timer source based on <kern/thread_call.h>
35 * Modification History:
37 * June 22, 2004 Dieter Siegmund (dieter@apple.com)
40 #include <sys/param.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
43 #include <kern/thread_call.h>
44 #include <net/devtimer.h>
45 #include <libkern/OSAtomic.h>
48 #define _devtimer_printf printf
49 #else /* !DEVTIMER_DEBUG */
50 static __inline__
void
51 _devtimer_printf(__unused
const char * fmt
, ...)
54 #endif /* !DEVTIMER_DEBUG */
58 devtimer_timeout_func dt_timeout_func
;
59 devtimer_process_func dt_process_func
;
64 UInt32 dt_retain_count
;
67 #define M_DEVTIMER M_DEVBUF
69 static __inline__
void
70 timeval_add(struct timeval tv1
, struct timeval tv2
,
71 struct timeval
* result
)
73 result
->tv_sec
= tv1
.tv_sec
+ tv2
.tv_sec
;
74 result
->tv_usec
= tv1
.tv_usec
+ tv2
.tv_usec
;
75 if (result
->tv_usec
> DEVTIMER_USECS_PER_SEC
) {
76 result
->tv_usec
-= DEVTIMER_USECS_PER_SEC
;
82 static __inline__
uint64_t
83 timeval_to_absolutetime(struct timeval tv
)
88 clock_interval_to_absolutetime_interval(tv
.tv_sec
, NSEC_PER_SEC
,
90 clock_interval_to_absolutetime_interval(tv
.tv_usec
, NSEC_PER_USEC
,
92 return (secs
+ usecs
);
96 __private_extern__
int
97 devtimer_valid(devtimer_ref timer
)
99 return (timer
->dt_callout
!= NULL
);
102 __private_extern__
void
103 devtimer_retain(devtimer_ref timer
)
105 OSIncrementAtomic(&timer
->dt_retain_count
);
109 __private_extern__
void
110 devtimer_invalidate(devtimer_ref timer
)
112 devtimer_cancel(timer
);
113 timer
->dt_arg0
= NULL
;
114 if (timer
->dt_callout
!= NULL
) {
115 thread_call_free(timer
->dt_callout
);
116 timer
->dt_callout
= NULL
;
121 __private_extern__
void
122 devtimer_release(devtimer_ref timer
)
124 UInt32 old_retain_count
;
126 old_retain_count
= OSDecrementAtomic(&timer
->dt_retain_count
);
127 switch (old_retain_count
) {
129 panic("devtimer_release: retain count is 0\n");
132 devtimer_invalidate(timer
);
133 FREE(timer
, M_DEVTIMER
);
134 _devtimer_printf("devtimer: timer released\n");
143 devtimer_process(void * param0
, void * param1
)
145 int generation
= *(int*)param1
;
146 devtimer_process_func process_func
;
147 devtimer_timeout_func timeout_func
;
148 devtimer_ref timer
= (devtimer_ref
)param0
;
150 process_func
= timer
->dt_process_func
;
151 if (process_func
!= NULL
) {
152 (*process_func
)(timer
, devtimer_process_func_event_lock
);
154 timeout_func
= timer
->dt_timeout_func
;
155 if (timeout_func
!= NULL
) {
156 timer
->dt_timeout_func
= NULL
;
157 if (timer
->dt_generation
== generation
) {
158 (*timeout_func
)(timer
->dt_arg0
, timer
->dt_arg1
, timer
->dt_arg2
);
161 devtimer_release(timer
);
162 if (process_func
!= NULL
) {
163 (*process_func
)(timer
, devtimer_process_func_event_unlock
);
168 __private_extern__
void *
169 devtimer_arg0(devtimer_ref timer
)
171 return (timer
->dt_arg0
);
174 __private_extern__ devtimer_ref
175 devtimer_create(devtimer_process_func process_func
, void * arg0
)
179 timer
= _MALLOC(sizeof(*timer
), M_DEVTIMER
, M_WAITOK
);
183 bzero(timer
, sizeof(*timer
));
184 devtimer_retain(timer
);
185 timer
->dt_callout
= thread_call_allocate(devtimer_process
, timer
);
186 if (timer
->dt_callout
== NULL
) {
187 _devtimer_printf("devtimer: thread_call_allocate failed\n");
188 devtimer_release(timer
);
191 timer
->dt_process_func
= process_func
;
192 timer
->dt_arg0
= arg0
;
196 __private_extern__
void
197 devtimer_set_absolute(devtimer_ref timer
,
198 struct timeval abs_time
,
199 devtimer_timeout_func timeout_func
,
200 void * arg1
, void * arg2
)
202 if (timer
->dt_callout
== NULL
) {
203 printf("devtimer_set_absolute: uninitialized/freed timer\n");
206 devtimer_cancel(timer
);
207 if (timeout_func
== NULL
) {
210 timer
->dt_timeout_func
= timeout_func
;
211 timer
->dt_arg1
= arg1
;
212 timer
->dt_arg2
= arg2
;
213 _devtimer_printf("devtimer: wakeup time is (%d.%d)\n",
214 abs_time
.tv_sec
, abs_time
.tv_usec
);
215 timer
->dt_generation
++;
216 devtimer_retain(timer
);
217 thread_call_enter1_delayed(timer
->dt_callout
,
218 &timer
->dt_generation
,
219 timeval_to_absolutetime(abs_time
));
223 __private_extern__
void
224 devtimer_set_relative(devtimer_ref timer
,
225 struct timeval rel_time
,
226 devtimer_timeout_func timeout_func
,
227 void * arg1
, void * arg2
)
229 struct timeval abs_time
;
230 struct timeval current_time
;
232 current_time
= devtimer_current_time();
233 timeval_add(current_time
, rel_time
, &abs_time
);
234 devtimer_set_absolute(timer
, abs_time
, timeout_func
, arg1
, arg2
);
238 __private_extern__
void
239 devtimer_cancel(devtimer_ref timer
)
241 if (timer
->dt_timeout_func
!= NULL
) {
242 timer
->dt_timeout_func
= NULL
;
243 if (timer
->dt_callout
!= NULL
) {
244 _devtimer_printf("devtimer: cancelling timer source\n");
245 if (thread_call_cancel(timer
->dt_callout
)) {
246 devtimer_release(timer
);
249 _devtimer_printf("devtimer: delayed release\n");
256 __private_extern__
int
257 devtimer_enabled(devtimer_ref timer
)
259 return (timer
->dt_timeout_func
!= NULL
);
262 __private_extern__
int32_t
263 devtimer_current_secs(void)
267 tv
= devtimer_current_time();
271 __private_extern__
struct timeval
272 devtimer_current_time(void)
278 clock_get_system_microtime(&sec
, &usec
);