1/* 2 * Copyright (c) 1993-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 * Timer interrupt callout module. 30 */ 31 32#include <mach/mach_types.h> 33 34#include <kern/clock.h> 35#include <kern/processor.h> 36#include <kern/etimer.h> 37#include <kern/timer_call.h> 38#include <kern/timer_queue.h> 39#include <kern/call_entry.h> 40 41#include <sys/kdebug.h> 42 43#if CONFIG_DTRACE && (DEVELOPMENT || DEBUG ) 44#include <mach/sdt.h> 45#endif 46 47decl_simple_lock_data(static,timer_call_lock) 48 49#define qe(x) ((queue_entry_t)(x)) 50#define TC(x) ((timer_call_t)(x)) 51 52void 53timer_call_initialize(void) 54{ 55 simple_lock_init(&timer_call_lock, 0); 56} 57 58void 59timer_call_setup( 60 timer_call_t call, 61 timer_call_func_t func, 62 timer_call_param_t param0) 63{ 64 call_entry_setup(call, func, param0); 65} 66 67__inline__ queue_t 68call_entry_enqueue_deadline( 69 call_entry_t entry, 70 queue_t queue, 71 uint64_t deadline) 72{ 73 queue_t old_queue = entry->queue; 74 timer_call_t current; 75 76 if (old_queue != queue || entry->deadline < deadline) { 77 if (old_queue != queue) 78 current = TC(queue_first(queue)); 79 else 80 current = TC(queue_next(qe(entry))); 81 82 if (old_queue != NULL) 83 (void)remque(qe(entry)); 84 85 while (TRUE) { 86 if ( queue_end(queue, qe(current)) || 87 deadline < current->deadline ) { 88 current = TC(queue_prev(qe(current))); 89 break; 90 } 91 92 current = TC(queue_next(qe(current))); 93 } 94 95 insque(qe(entry), qe(current)); 96 } 97 else 98 if (deadline < entry->deadline) { 99 current = TC(queue_prev(qe(entry))); 100 101 (void)remque(qe(entry)); 102 103 while (TRUE) { 104 if ( queue_end(queue, qe(current)) || 105 current->deadline <= deadline ) { 106 break; 107 } 108 109 current = TC(queue_prev(qe(current))); 110 } 111 112 insque(qe(entry), qe(current)); 113 } 114 115 entry->queue = queue; 116 entry->deadline = deadline; 117 118 return (old_queue); 119} 120 121__inline__ queue_t 122call_entry_enqueue_tail( 123 call_entry_t entry, 124 queue_t queue) 125{ 126 queue_t old_queue = entry->queue; 127 128 if (old_queue != NULL) 129 (void)remque(qe(entry)); 130 131 enqueue_tail(queue, qe(entry)); 132 133 entry->queue = queue; 134 135 return (old_queue); 136} 137 138__inline__ queue_t 139call_entry_dequeue( 140 call_entry_t entry) 141{ 142 queue_t old_queue = entry->queue; 143 144 if (old_queue != NULL) 145 (void)remque(qe(entry)); 146 147 entry->queue = NULL; 148 149 return (old_queue); 150} 151 152boolean_t 153timer_call_enter( 154 timer_call_t call, 155 uint64_t deadline) 156{ 157 queue_t queue, old_queue; 158 spl_t s; 159 160 s = splclock(); 161 simple_lock(&timer_call_lock); 162 163 queue = timer_queue_assign(deadline); 164 165 old_queue = call_entry_enqueue_deadline(call, queue, deadline); 166 167 call->param1 = NULL; 168 169 simple_unlock(&timer_call_lock); 170 splx(s); 171 172 return (old_queue != NULL); 173} 174 175boolean_t 176timer_call_enter1( 177 timer_call_t call, 178 timer_call_param_t param1, 179 uint64_t deadline) 180{ 181 queue_t queue, old_queue; 182 spl_t s; 183 184 s = splclock(); 185 simple_lock(&timer_call_lock); 186 187 queue = timer_queue_assign(deadline); 188 189 old_queue = call_entry_enqueue_deadline(call, queue, deadline); 190 191 call->param1 = param1; 192 193 simple_unlock(&timer_call_lock); 194 splx(s); 195 196 return (old_queue != NULL); 197} 198 199boolean_t 200timer_call_cancel( 201 timer_call_t call) 202{ 203 queue_t old_queue; 204 spl_t s; 205 206 s = splclock(); 207 simple_lock(&timer_call_lock); 208 209 old_queue = call_entry_dequeue(call); 210 211 if (old_queue != NULL) { 212 if (!queue_empty(old_queue)) 213 timer_queue_cancel(old_queue, call->deadline, TC(queue_first(old_queue))->deadline); 214 else 215 timer_queue_cancel(old_queue, call->deadline, UINT64_MAX); 216 } 217 218 simple_unlock(&timer_call_lock); 219 splx(s); 220 221 return (old_queue != NULL); 222} 223 224void 225timer_queue_shutdown( 226 queue_t queue) 227{ 228 timer_call_t call; 229 queue_t new_queue; 230 spl_t s; 231 232 s = splclock(); 233 simple_lock(&timer_call_lock); 234 235 call = TC(queue_first(queue)); 236 237 while (!queue_end(queue, qe(call))) { 238 new_queue = timer_queue_assign(call->deadline); 239 240 call_entry_enqueue_deadline(call, new_queue, call->deadline); 241 242 call = TC(queue_first(queue)); 243 } 244 245 simple_unlock(&timer_call_lock); 246 splx(s); 247} 248 249uint64_t 250timer_queue_expire( 251 queue_t queue, 252 uint64_t deadline) 253{ 254 timer_call_t call; 255 256 simple_lock(&timer_call_lock); 257 258 call = TC(queue_first(queue)); 259 260 while (!queue_end(queue, qe(call))) { 261 if (call->deadline <= deadline) { 262 timer_call_func_t func; 263 timer_call_param_t param0, param1; 264 265 call_entry_dequeue(call); 266 267 func = call->func; 268 param0 = call->param0; 269 param1 = call->param1; 270 271 simple_unlock(&timer_call_lock); 272 273 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 274 2) 275 | DBG_FUNC_START, 276 (unsigned int)func, 277 (unsigned int)param0, 278 (unsigned int)param1, 0, 0); 279 280#if CONFIG_DTRACE && (DEVELOPMENT || DEBUG ) 281 DTRACE_TMR3(callout__start, timer_call_func_t, func, 282 timer_call_param_t, param0, 283 timer_call_param_t, param1); 284#endif 285 286 (*func)(param0, param1); 287 288#if CONFIG_DTRACE && (DEVELOPMENT || DEBUG ) 289 DTRACE_TMR3(callout__end, timer_call_func_t, func, 290 timer_call_param_t, param0, 291 timer_call_param_t, param1); 292#endif 293 294 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 295 2) 296 | DBG_FUNC_END, 297 (unsigned int)func, 298 (unsigned int)param0, 299 (unsigned int)param1, 0, 0); 300 301 simple_lock(&timer_call_lock); 302 } 303 else 304 break; 305 306 call = TC(queue_first(queue)); 307 } 308 309 if (!queue_end(queue, qe(call))) 310 deadline = call->deadline; 311 else 312 deadline = UINT64_MAX; 313 314 simple_unlock(&timer_call_lock); 315 316 return (deadline); 317} 318