1 /* 2 * Copyright (c) 2004-2021 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 static __inline__ void 68 timeval_add(struct timeval tv1, struct timeval tv2, 69 struct timeval * result) 70 { 71 result->tv_sec = tv1.tv_sec + tv2.tv_sec; 72 result->tv_usec = tv1.tv_usec + tv2.tv_usec; 73 if (result->tv_usec > DEVTIMER_USECS_PER_SEC) { 74 result->tv_usec -= DEVTIMER_USECS_PER_SEC; 75 result->tv_sec++; 76 } 77 return; 78 } 79 80 static __inline__ uint64_t 81 timeval_to_absolutetime(struct timeval tv) 82 { 83 uint64_t secs; 84 uint64_t usecs; 85 86 clock_interval_to_absolutetime_interval(tv.tv_sec, NSEC_PER_SEC, 87 &secs); 88 clock_interval_to_absolutetime_interval(tv.tv_usec, NSEC_PER_USEC, 89 &usecs); 90 return secs + usecs; 91 } 92 93 94 __private_extern__ int 95 devtimer_valid(devtimer_ref timer) 96 { 97 return timer->dt_callout != NULL; 98 } 99 100 __private_extern__ void 101 devtimer_retain(devtimer_ref timer) 102 { 103 os_ref_retain(&timer->dt_retain_count); 104 } 105 106 __private_extern__ void 107 devtimer_invalidate(devtimer_ref timer) 108 { 109 devtimer_cancel(timer); 110 timer->dt_arg0 = NULL; 111 if (timer->dt_callout != NULL) { 112 thread_call_free(timer->dt_callout); 113 timer->dt_callout = NULL; 114 } 115 return; 116 } 117 118 __private_extern__ void 119 devtimer_release(devtimer_ref timer) 120 { 121 if (os_ref_release(&timer->dt_retain_count) == 0) { 122 devtimer_invalidate(timer); 123 kfree_type(struct devtimer_s, timer); 124 _devtimer_printf("devtimer: timer released\n"); 125 } 126 } 127 128 static void 129 devtimer_process(void * param0, void * param1) 130 { 131 int generation = *(int*)param1; 132 devtimer_process_func process_func; 133 devtimer_timeout_func timeout_func; 134 devtimer_ref timer = (devtimer_ref)param0; 135 136 process_func = timer->dt_process_func; 137 if (process_func != NULL) { 138 (*process_func)(timer, devtimer_process_func_event_lock); 139 } 140 timeout_func = timer->dt_timeout_func; 141 if (timeout_func != NULL) { 142 timer->dt_timeout_func = NULL; 143 if (timer->dt_generation == generation) { 144 (*timeout_func)(timer->dt_arg0, timer->dt_arg1, timer->dt_arg2); 145 } 146 } 147 devtimer_release(timer); 148 if (process_func != NULL) { 149 (*process_func)(timer, devtimer_process_func_event_unlock); 150 } 151 return; 152 } 153 154 __private_extern__ void * 155 devtimer_arg0(devtimer_ref timer) 156 { 157 return timer->dt_arg0; 158 } 159 160 __private_extern__ devtimer_ref 161 devtimer_create(devtimer_process_func process_func, void * arg0) 162 { 163 devtimer_ref timer; 164 165 timer = kalloc_type(struct devtimer_s, Z_WAITOK | Z_ZERO | Z_NOFAIL); 166 os_ref_init(&timer->dt_retain_count, NULL); 167 timer->dt_callout = thread_call_allocate(devtimer_process, timer); 168 if (timer->dt_callout == NULL) { 169 _devtimer_printf("devtimer: thread_call_allocate failed\n"); 170 devtimer_release(timer); 171 timer = NULL; 172 } 173 timer->dt_process_func = process_func; 174 timer->dt_arg0 = arg0; 175 return timer; 176 } 177 178 __private_extern__ void 179 devtimer_set_absolute(devtimer_ref timer, 180 struct timeval abs_time, 181 devtimer_timeout_func timeout_func, 182 void * arg1, void * arg2) 183 { 184 if (timer->dt_callout == NULL) { 185 printf("devtimer_set_absolute: uninitialized/freed timer\n"); 186 return; 187 } 188 devtimer_cancel(timer); 189 if (timeout_func == NULL) { 190 return; 191 } 192 timer->dt_timeout_func = timeout_func; 193 timer->dt_arg1 = arg1; 194 timer->dt_arg2 = arg2; 195 _devtimer_printf("devtimer: wakeup time is (%d.%d)\n", 196 abs_time.tv_sec, abs_time.tv_usec); 197 timer->dt_generation++; 198 devtimer_retain(timer); 199 thread_call_enter1_delayed(timer->dt_callout, 200 &timer->dt_generation, 201 timeval_to_absolutetime(abs_time)); 202 return; 203 } 204 205 __private_extern__ void 206 devtimer_set_relative(devtimer_ref timer, 207 struct timeval rel_time, 208 devtimer_timeout_func timeout_func, 209 void * arg1, void * arg2) 210 { 211 struct timeval abs_time; 212 struct timeval current_time; 213 214 current_time = devtimer_current_time(); 215 timeval_add(current_time, rel_time, &abs_time); 216 devtimer_set_absolute(timer, abs_time, timeout_func, arg1, arg2); 217 return; 218 } 219 220 __private_extern__ void 221 devtimer_cancel(devtimer_ref timer) 222 { 223 if (timer->dt_timeout_func != NULL) { 224 timer->dt_timeout_func = NULL; 225 if (timer->dt_callout != NULL) { 226 _devtimer_printf("devtimer: cancelling timer source\n"); 227 if (thread_call_cancel(timer->dt_callout)) { 228 devtimer_release(timer); 229 } else { 230 _devtimer_printf("devtimer: delayed release\n"); 231 } 232 } 233 } 234 return; 235 } 236 237 __private_extern__ int 238 devtimer_enabled(devtimer_ref timer) 239 { 240 return timer->dt_timeout_func != NULL; 241 } 242 243 __private_extern__ int32_t 244 devtimer_current_secs(void) 245 { 246 struct timeval tv; 247 248 tv = devtimer_current_time(); 249 return tv.tv_sec; 250 } 251 252 __private_extern__ struct timeval 253 devtimer_current_time(void) 254 { 255 struct timeval tv; 256 clock_sec_t sec; 257 clock_usec_t usec; 258 259 clock_get_system_microtime(&sec, &usec); 260 tv.tv_sec = sec; 261 tv.tv_usec = usec; 262 return tv; 263 } 264