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 
| M_ZERO
); 
 183     devtimer_retain(timer
); 
 184     timer
->dt_callout 
= thread_call_allocate(devtimer_process
, timer
); 
 185     if (timer
->dt_callout 
== NULL
) { 
 186         _devtimer_printf("devtimer: thread_call_allocate failed\n"); 
 187         devtimer_release(timer
); 
 190     timer
->dt_process_func 
= process_func
; 
 191     timer
->dt_arg0 
= arg0
; 
 195 __private_extern__ 
void 
 196 devtimer_set_absolute(devtimer_ref timer
,  
 197                       struct timeval abs_time
,  
 198                       devtimer_timeout_func timeout_func
,  
 199                       void * arg1
, void * arg2
) 
 201     if (timer
->dt_callout 
== NULL
) { 
 202         printf("devtimer_set_absolute: uninitialized/freed timer\n"); 
 205     devtimer_cancel(timer
); 
 206     if (timeout_func 
== NULL
) { 
 209     timer
->dt_timeout_func 
= timeout_func
; 
 210     timer
->dt_arg1 
= arg1
; 
 211     timer
->dt_arg2 
= arg2
; 
 212     _devtimer_printf("devtimer: wakeup time is (%d.%d)\n",  
 213                      abs_time
.tv_sec
, abs_time
.tv_usec
); 
 214     timer
->dt_generation
++; 
 215     devtimer_retain(timer
); 
 216     thread_call_enter1_delayed(timer
->dt_callout
,  
 217                                &timer
->dt_generation
, 
 218                                timeval_to_absolutetime(abs_time
)); 
 222 __private_extern__ 
void 
 223 devtimer_set_relative(devtimer_ref timer
,  
 224                       struct timeval rel_time
,  
 225                       devtimer_timeout_func timeout_func
,  
 226                       void * arg1
, void * arg2
) 
 228     struct timeval              abs_time
; 
 229     struct timeval              current_time
; 
 231     current_time 
= devtimer_current_time(); 
 232     timeval_add(current_time
, rel_time
, &abs_time
); 
 233     devtimer_set_absolute(timer
, abs_time
, timeout_func
, arg1
, arg2
); 
 237 __private_extern__ 
void 
 238 devtimer_cancel(devtimer_ref timer
) 
 240     if (timer
->dt_timeout_func 
!= NULL
) { 
 241         timer
->dt_timeout_func 
= NULL
; 
 242         if (timer
->dt_callout 
!= NULL
) { 
 243             _devtimer_printf("devtimer: cancelling timer source\n"); 
 244             if (thread_call_cancel(timer
->dt_callout
)) { 
 245                 devtimer_release(timer
); 
 248                 _devtimer_printf("devtimer: delayed release\n"); 
 255 __private_extern__ 
int 
 256 devtimer_enabled(devtimer_ref timer
) 
 258     return (timer
->dt_timeout_func 
!= NULL
); 
 261 __private_extern__ 
int32_t 
 262 devtimer_current_secs(void) 
 266     tv 
= devtimer_current_time(); 
 270 __private_extern__ 
struct timeval
 
 271 devtimer_current_time(void) 
 277     clock_get_system_microtime(&sec
, &usec
);