1 /* 2 * Copyright (c) 2004,2007-2008 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 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. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 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. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29 /* 30 * devtimer.c 31 * - timer source based on <kern/thread_call.h> 32 */ 33 34 /* 35 * Modification History: 36 * 37 * June 22, 2004 Dieter Siegmund ([email protected]) 38 * - created 39 */ 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 <os/refcnt.h> 46 47 #ifdef DEVTIMER_DEBUG 48 #define _devtimer_printf printf 49 #else /* !DEVTIMER_DEBUG */ 50 static __inline__ void 51 _devtimer_printf(__unused const char * fmt, ...) 52 { 53 } 54 #endif /* !DEVTIMER_DEBUG */ 55 56 struct devtimer_s { 57 void * dt_callout; 58 devtimer_timeout_func dt_timeout_func; 59 devtimer_process_func dt_process_func; 60 void * dt_arg0; 61 void * dt_arg1; 62 void * dt_arg2; 63 int dt_generation; 64 struct os_refcnt dt_retain_count; 65 }; 66 67 #define M_DEVTIMER M_DEVBUF 68 69 static __inline__ void 70 timeval_add(struct timeval tv1, struct timeval tv2, 71 struct timeval * result) 72 { 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; 77 result->tv_sec++; 78 } 79 return; 80 } 81 82 static __inline__ uint64_t 83 timeval_to_absolutetime(struct timeval tv) 84 { 85 uint64_t secs; 86 uint64_t usecs; 87 88 clock_interval_to_absolutetime_interval(tv.tv_sec, NSEC_PER_SEC, 89 &secs); 90 clock_interval_to_absolutetime_interval(tv.tv_usec, NSEC_PER_USEC, 91 &usecs); 92 return secs + usecs; 93 } 94 95 96 __private_extern__ int 97 devtimer_valid(devtimer_ref timer) 98 { 99 return timer->dt_callout != NULL; 100 } 101 102 __private_extern__ void 103 devtimer_retain(devtimer_ref timer) 104 { 105 os_ref_retain(&timer->dt_retain_count); 106 } 107 108 __private_extern__ void 109 devtimer_invalidate(devtimer_ref timer) 110 { 111 devtimer_cancel(timer); 112 timer->dt_arg0 = NULL; 113 if (timer->dt_callout != NULL) { 114 thread_call_free(timer->dt_callout); 115 timer->dt_callout = NULL; 116 } 117 return; 118 } 119 120 __private_extern__ void 121 devtimer_release(devtimer_ref timer) 122 { 123 if (os_ref_release(&timer->dt_retain_count) == 0) { 124 devtimer_invalidate(timer); 125 FREE(timer, M_DEVTIMER); 126 _devtimer_printf("devtimer: timer released\n"); 127 } 128 } 129 130 static void 131 devtimer_process(void * param0, void * param1) 132 { 133 int generation = *(int*)param1; 134 devtimer_process_func process_func; 135 devtimer_timeout_func timeout_func; 136 devtimer_ref timer = (devtimer_ref)param0; 137 138 process_func = timer->dt_process_func; 139 if (process_func != NULL) { 140 (*process_func)(timer, devtimer_process_func_event_lock); 141 } 142 timeout_func = timer->dt_timeout_func; 143 if (timeout_func != NULL) { 144 timer->dt_timeout_func = NULL; 145 if (timer->dt_generation == generation) { 146 (*timeout_func)(timer->dt_arg0, timer->dt_arg1, timer->dt_arg2); 147 } 148 } 149 devtimer_release(timer); 150 if (process_func != NULL) { 151 (*process_func)(timer, devtimer_process_func_event_unlock); 152 } 153 return; 154 } 155 156 __private_extern__ void * 157 devtimer_arg0(devtimer_ref timer) 158 { 159 return timer->dt_arg0; 160 } 161 162 __private_extern__ devtimer_ref 163 devtimer_create(devtimer_process_func process_func, void * arg0) 164 { 165 devtimer_ref timer; 166 167 timer = _MALLOC(sizeof(*timer), M_DEVTIMER, M_WAITOK | M_ZERO); 168 if (timer == NULL) { 169 return timer; 170 } 171 os_ref_init(&timer->dt_retain_count, NULL); 172 timer->dt_callout = thread_call_allocate(devtimer_process, timer); 173 if (timer->dt_callout == NULL) { 174 _devtimer_printf("devtimer: thread_call_allocate failed\n"); 175 devtimer_release(timer); 176 timer = NULL; 177 } 178 timer->dt_process_func = process_func; 179 timer->dt_arg0 = arg0; 180 return timer; 181 } 182 183 __private_extern__ void 184 devtimer_set_absolute(devtimer_ref timer, 185 struct timeval abs_time, 186 devtimer_timeout_func timeout_func, 187 void * arg1, void * arg2) 188 { 189 if (timer->dt_callout == NULL) { 190 printf("devtimer_set_absolute: uninitialized/freed timer\n"); 191 return; 192 } 193 devtimer_cancel(timer); 194 if (timeout_func == NULL) { 195 return; 196 } 197 timer->dt_timeout_func = timeout_func; 198 timer->dt_arg1 = arg1; 199 timer->dt_arg2 = arg2; 200 _devtimer_printf("devtimer: wakeup time is (%d.%d)\n", 201 abs_time.tv_sec, abs_time.tv_usec); 202 timer->dt_generation++; 203 devtimer_retain(timer); 204 thread_call_enter1_delayed(timer->dt_callout, 205 &timer->dt_generation, 206 timeval_to_absolutetime(abs_time)); 207 return; 208 } 209 210 __private_extern__ void 211 devtimer_set_relative(devtimer_ref timer, 212 struct timeval rel_time, 213 devtimer_timeout_func timeout_func, 214 void * arg1, void * arg2) 215 { 216 struct timeval abs_time; 217 struct timeval current_time; 218 219 current_time = devtimer_current_time(); 220 timeval_add(current_time, rel_time, &abs_time); 221 devtimer_set_absolute(timer, abs_time, timeout_func, arg1, arg2); 222 return; 223 } 224 225 __private_extern__ void 226 devtimer_cancel(devtimer_ref timer) 227 { 228 if (timer->dt_timeout_func != NULL) { 229 timer->dt_timeout_func = NULL; 230 if (timer->dt_callout != NULL) { 231 _devtimer_printf("devtimer: cancelling timer source\n"); 232 if (thread_call_cancel(timer->dt_callout)) { 233 devtimer_release(timer); 234 } else { 235 _devtimer_printf("devtimer: delayed release\n"); 236 } 237 } 238 } 239 return; 240 } 241 242 __private_extern__ int 243 devtimer_enabled(devtimer_ref timer) 244 { 245 return timer->dt_timeout_func != NULL; 246 } 247 248 __private_extern__ int32_t 249 devtimer_current_secs(void) 250 { 251 struct timeval tv; 252 253 tv = devtimer_current_time(); 254 return tv.tv_sec; 255 } 256 257 __private_extern__ struct timeval 258 devtimer_current_time(void) 259 { 260 struct timeval tv; 261 clock_sec_t sec; 262 clock_usec_t usec; 263 264 clock_get_system_microtime(&sec, &usec); 265 tv.tv_sec = sec; 266 tv.tv_usec = usec; 267 return tv; 268 } 269