1 /* 2 * Copyright (c) 1993-1995, 1999-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 * @header thread_call.h 31 * @discussion Facilities for executing work asynchronously. 32 */ 33 34 #ifndef _KERN_THREAD_CALL_H_ 35 #define _KERN_THREAD_CALL_H_ 36 37 #include <mach/mach_types.h> 38 39 #include <kern/clock.h> 40 41 #include <sys/cdefs.h> 42 43 struct thread_call; 44 typedef struct thread_call *thread_call_t; 45 46 typedef void *thread_call_param_t; 47 typedef void (*thread_call_func_t)( 48 thread_call_param_t param0, 49 thread_call_param_t param1); 50 /*! 51 * @enum thread_call_priority_t 52 * @discussion Thread call priorities should not be assumed to have any specific 53 * numerical value; they should be interpreted as importances or roles for work 54 * items, priorities for which will be reasonably managed by the subsystem. 55 * @constant THREAD_CALL_PRIORITY_HIGH Importance above everything but realtime. 56 * Thread calls allocated with this priority execute at extremely high priority, 57 * above everything but realtime threads. They are generally executed in serial. 58 * Though they may execute concurrently under some circumstances, no fan-out is implied. 59 * These work items should do very small amounts of work or risk disrupting system 60 * responsiveness. 61 * @constant THREAD_CALL_PRIORITY_KERNEL Importance similar to that of normal kernel 62 * threads. 63 * @constant THREAD_CALL_PRIORITY_USER Importance similar to that of normal user threads. 64 * @constant THREAD_CALL_PRIORITY_LOW Very low importance. 65 * @constant THREAD_CALL_PRIORITY_KERNEL_HIGH Importance higher than most kernel 66 * threads. 67 */ 68 typedef enum { 69 THREAD_CALL_PRIORITY_HIGH = 0, 70 THREAD_CALL_PRIORITY_KERNEL = 1, 71 THREAD_CALL_PRIORITY_USER = 2, 72 THREAD_CALL_PRIORITY_LOW = 3, 73 THREAD_CALL_PRIORITY_KERNEL_HIGH = 4 74 } thread_call_priority_t; 75 76 enum { 77 /* if call is re-submitted while the call is executing on a call thread, then delay the re-enqueue until it returns */ 78 THREAD_CALL_OPTIONS_ONCE = 0x00000001, 79 #ifdef XNU_KERNEL_PRIVATE 80 /* execute call from the timer interrupt instead of from the thread call thread, private interface for IOTES workloop signaling */ 81 THREAD_CALL_OPTIONS_SIGNAL = 0x00000002, 82 #endif /* XNU_KERNEL_PRIVATE */ 83 }; 84 typedef uint32_t thread_call_options_t; 85 86 __BEGIN_DECLS 87 88 /*! 89 * @function thread_call_enter 90 * @abstract Submit a thread call work item for immediate execution. 91 * @discussion If the work item is already scheduled for delayed execution, and it has 92 * not yet begun to run, that delayed invocation will be cancelled. Note that if a 93 * thread call is rescheduled from its own callback, then multiple invocations of the 94 * callback may be in flight at the same time. 95 * @result TRUE if the call was already pending for either delayed or immediate 96 * execution, FALSE otherwise. 97 * @param call The thread call to execute. 98 */ 99 extern boolean_t thread_call_enter( 100 thread_call_t call); 101 /*! 102 * @function thread_call_enter1 103 * @abstract Submit a thread call work item for immediate execution, with an extra parameter. 104 * @discussion This routine is identical to thread_call_enter(), except that 105 * the second parameter to the callback is specified. 106 * @result TRUE if the call was already pending for either delayed or immediate 107 * execution, FALSE otherwise. 108 * @param call The thread call to execute. 109 * @param param1 Parameter to pass callback. 110 */ 111 extern boolean_t thread_call_enter1( 112 thread_call_t call, 113 thread_call_param_t param1); 114 115 /*! 116 * @function thread_call_enter_delayed 117 * @abstract Submit a thread call to be executed at some point in the future. 118 * @discussion If the work item is already scheduled for delayed or immediate execution, 119 * and it has not yet begun to run, that invocation will be cancelled in favor of execution 120 * at the newly specified time. Note that if a thread call is rescheduled from its own callback, 121 * then multiple invocations of the callback may be in flight at the same time. 122 * @result TRUE if the call was already pending for either delayed or immediate 123 * execution, FALSE otherwise. 124 * @param call The thread call to execute. 125 * @param deadline Time, in absolute time units, at which to execute callback. 126 */ 127 extern boolean_t thread_call_enter_delayed( 128 thread_call_t call, 129 uint64_t deadline); 130 /*! 131 * @function thread_call_enter1_delayed 132 * @abstract Submit a thread call to be executed at some point in the future, with an extra parameter. 133 * @discussion This routine is identical to thread_call_enter_delayed(), 134 * except that a second parameter to the callback is specified. 135 * @result TRUE if the call was already pending for either delayed or immediate 136 * execution, FALSE otherwise. 137 * @param call The thread call to execute. 138 * @param param1 Second parameter to callback. 139 * @param deadline Time, in absolute time units, at which to execute callback. 140 */ 141 extern boolean_t thread_call_enter1_delayed( 142 thread_call_t call, 143 thread_call_param_t param1, 144 uint64_t deadline); 145 #ifdef XNU_KERNEL_PRIVATE 146 147 /* 148 * Flags to alter the default timer/timeout coalescing behavior 149 * on a per-thread_call basis. 150 * 151 * The SYS urgency classes indicate that the thread_call is not 152 * directly related to the current thread at the time the thread_call 153 * is entered, so it is ignored in the calculation entirely (only 154 * the subclass specified is used). 155 * 156 * The USER flags indicate that both the current thread scheduling and QoS 157 * attributes, in addition to the per-thread_call urgency specification, 158 * are used to establish coalescing behavior. 159 */ 160 #define THREAD_CALL_DELAY_SYS_NORMAL TIMEOUT_URGENCY_SYS_NORMAL 161 #define THREAD_CALL_DELAY_SYS_CRITICAL TIMEOUT_URGENCY_SYS_CRITICAL 162 #define THREAD_CALL_DELAY_SYS_BACKGROUND TIMEOUT_URGENCY_SYS_BACKGROUND 163 164 #define THREAD_CALL_DELAY_USER_MASK TIMEOUT_URGENCY_USER_MASK 165 #define THREAD_CALL_DELAY_USER_NORMAL TIMEOUT_URGENCY_USER_NORMAL 166 #define THREAD_CALL_DELAY_USER_CRITICAL TIMEOUT_URGENCY_USER_CRITICAL 167 #define THREAD_CALL_DELAY_USER_BACKGROUND TIMEOUT_URGENCY_USER_BACKGROUND 168 169 #define THREAD_CALL_DELAY_URGENCY_MASK TIMEOUT_URGENCY_MASK 170 171 /* 172 * Indicate that a specific leeway value is being provided (otherwise 173 * the leeway parameter is ignored). The supplied value can currently 174 * only be used to extend the leeway calculated internally from the 175 * urgency class provided. 176 */ 177 #define THREAD_CALL_DELAY_LEEWAY TIMEOUT_URGENCY_LEEWAY 178 179 /* 180 * Indicates that the time parameters should be interpreted as 181 * mach_continuous_time values, rather than mach_absolute_time and the timer 182 * be programmed to fire based on continuous time. 183 */ 184 #define THREAD_CALL_CONTINUOUS 0x100 185 186 /*! 187 * @function thread_call_enter_delayed_with_leeway 188 * @abstract Submit a thread call to be executed at some point in the future. 189 * @discussion If the work item is already scheduled for delayed or immediate execution, 190 * and it has not yet begun to run, that invocation will be cancelled in favor of execution 191 * at the newly specified time. Note that if a thread call is rescheduled from its own callback, 192 * then multiple invocations of the callback may be in flight at the same time. 193 * @result TRUE if the call was already pending for either delayed or immediate 194 * execution, FALSE otherwise. 195 * @param call The thread call to execute. 196 * @param param1 Second parameter to callback. 197 * @param deadline Time, in absolute time units, at which to execute callback. 198 * @param leeway Time delta, in absolute time units, which sets range of time allowing kernel 199 * to decide appropriate time to run. 200 * @param flags configuration for timers in kernel. 201 */ 202 extern boolean_t thread_call_enter_delayed_with_leeway( 203 thread_call_t call, 204 thread_call_param_t param1, 205 uint64_t deadline, 206 uint64_t leeway, 207 uint32_t flags); 208 209 #endif /* XNU_KERNEL_PRIVATE */ 210 211 /*! 212 * @function thread_call_cancel 213 * @abstract Attempt to cancel a pending invocation of a thread call. 214 * @discussion Attempt to cancel a thread call which has been scheduled 215 * for execution with a thread_call_enter* variant. If the call has not 216 * yet begun executing, the pending invocation will be cancelled and TRUE 217 * will be returned. If the work item has already begun executing, 218 * thread_call_cancel will return FALSE immediately; the callback may be 219 * about to run, currently running, or already done executing. 220 * @result TRUE if the call was successfully cancelled, FALSE otherwise. 221 */ 222 extern boolean_t thread_call_cancel( 223 thread_call_t call); 224 /*! 225 * @function thread_call_cancel_wait 226 * @abstract Attempt to cancel a pending invocation of a thread call. 227 * If unable to cancel, wait for current invocation to finish. 228 * @discussion Attempt to cancel a thread call which has been scheduled 229 * for execution with a thread_call_enter* variant. If the call has not 230 * yet begun executing, the pending invocation will be cancelled and TRUE 231 * will be returned. If the work item has already begun executing, 232 * thread_call_cancel_wait waits for the most recent invocation to finish. When 233 * called on a work item which has already finished, it will return FALSE immediately. 234 * Note that this routine can only be used on thread calls set up with either 235 * thread_call_allocate or thread_call_allocate_with_priority, and that invocations 236 * of the thread call <i>after</i> the current invocation may be in flight when 237 * thread_call_cancel_wait returns. 238 * @result TRUE if the call was successfully cancelled, FALSE otherwise. 239 */ 240 extern boolean_t thread_call_cancel_wait( 241 thread_call_t call); 242 243 /*! 244 * @function thread_call_allocate 245 * @abstract Allocate a thread call to execute with default (high) priority. 246 * @discussion Allocates a thread call that will run with properties of 247 * THREAD_CALL_PRIORITY_HIGH, binding the first parameter to the callback. 248 * @param func Callback to invoke when thread call is scheduled. 249 * @param param0 First argument ot pass to callback. 250 * @result Thread call which can be passed to thread_call_enter variants. 251 */ 252 extern thread_call_t thread_call_allocate( 253 thread_call_func_t func, 254 thread_call_param_t param0); 255 256 /*! 257 * @function thread_call_allocate_with_priority 258 * @abstract Allocate a thread call to execute with a specified priority. 259 * @discussion Identical to thread_call_allocate, except that priority 260 * is specified by caller. 261 * @param func Callback to invoke when thread call is scheduled. 262 * @param param0 First argument to pass to callback. 263 * @param pri Priority of item. 264 * @result Thread call which can be passed to thread_call_enter variants. 265 */ 266 extern thread_call_t thread_call_allocate_with_priority( 267 thread_call_func_t func, 268 thread_call_param_t param0, 269 thread_call_priority_t pri); 270 271 /*! 272 * @function thread_call_allocate_with_options 273 * @abstract Allocate a thread call to execute with a specified priority. 274 * @discussion Identical to thread_call_allocate, except that priority 275 * and options are specified by caller. 276 * @param func Callback to invoke when thread call is scheduled. 277 * @param param0 First argument to pass to callback. 278 * @param pri Priority of item. 279 * @param options Options for item. 280 * @result Thread call which can be passed to thread_call_enter variants. 281 */ 282 extern thread_call_t thread_call_allocate_with_options( 283 thread_call_func_t func, 284 thread_call_param_t param0, 285 thread_call_priority_t pri, 286 thread_call_options_t options); 287 288 #ifdef KERNEL_PRIVATE 289 /*! 290 * @function thread_call_allocate_with_qos 291 * @abstract Allocate a thread call to execute with a specified QoS. 292 * @discussion Identical to thread_call_allocate_with_options, except it uses the QoS namespace. 293 * Private interface for pthread kext. 294 * @param func Callback to invoke when thread call is scheduled. 295 * @param param0 First argument to pass to callback. 296 * @param qos_tier QoS tier to execute callback at (as in THREAD_QOS_POLICY) 297 * @param options flags from thread_call_options_t to influence the thread call behavior 298 * @result Thread call which can be passed to thread_call_enter variants. 299 */ 300 extern thread_call_t 301 thread_call_allocate_with_qos(thread_call_func_t func, 302 thread_call_param_t param0, 303 int qos_tier, 304 thread_call_options_t options); 305 306 /*! 307 * @function thread_call_wait_once 308 * @abstract Wait for a THREAD_CALL_OPTIONS_ONCE call to finish executing if it is executing 309 * @discussion Only works on THREAD_CALL_OPTIONS_ONCE calls 310 * @param call The thread call to wait for 311 * @result True if it waited, false if it did not wait 312 */ 313 extern boolean_t 314 thread_call_wait_once(thread_call_t call); 315 #endif /* KERNEL_PRIVATE */ 316 317 /*! 318 * @function thread_call_free 319 * @abstract Release a thread call. 320 * @discussion Should only be used on thread calls allocated with thread_call_allocate 321 * or thread_call_allocate_with_priority. Once thread_call_free has been called, 322 * no other operations may be performed on a thread call. If the thread call is 323 * currently pending, thread_call_free will return FALSE and will have no effect. 324 * Calling thread_call_free from a thread call's own callback is safe; the work 325 * item is not considering "pending" at that point. 326 * @result TRUE if the thread call has been successfully released, else FALSE. 327 * @param call The thread call to release. 328 */ 329 extern boolean_t thread_call_free( 330 thread_call_t call); 331 332 /*! 333 * @function thread_call_isactive 334 * @abstract Determine whether a thread call is pending or currently executing. 335 * @param call Thread call to examine. 336 * @result TRUE if the thread call is either scheduled for execution (immediately 337 * or at some point in the future) or is currently executing. 338 */ 339 boolean_t thread_call_isactive( 340 thread_call_t call); 341 __END_DECLS 342 343 #ifdef MACH_KERNEL_PRIVATE 344 345 #include <kern/queue.h> 346 #include <kern/priority_queue.h> 347 348 __enum_closed_decl(thread_call_index_t, uint16_t, { 349 THREAD_CALL_INDEX_INVALID = 0, /* make sure zero tc_index is detected as invalid */ 350 THREAD_CALL_INDEX_HIGH = 1, 351 THREAD_CALL_INDEX_KERNEL = 2, 352 THREAD_CALL_INDEX_USER = 3, 353 THREAD_CALL_INDEX_LOW = 4, 354 THREAD_CALL_INDEX_KERNEL_HIGH = 5, 355 THREAD_CALL_INDEX_QOS_UI = 6, 356 THREAD_CALL_INDEX_QOS_IN = 7, 357 THREAD_CALL_INDEX_QOS_UT = 8, 358 THREAD_CALL_INDEX_MAX = 9, /* count of thread call indexes */ 359 }); 360 361 __options_closed_decl(thread_call_flags_t, uint16_t, { 362 THREAD_CALL_ALLOC = 0x0001, /* memory owned by thread_call.c */ 363 THREAD_CALL_WAIT = 0x0002, /* thread waiting for call to finish running */ 364 THREAD_CALL_DELAYED = 0x0004, /* deadline based */ 365 THREAD_CALL_RUNNING = 0x0008, /* currently executing on a thread */ 366 THREAD_CALL_SIGNAL = 0x0010, /* call from timer interrupt instead of thread */ 367 THREAD_CALL_ONCE = 0x0020, /* pend the enqueue if re-armed while running */ 368 THREAD_CALL_RESCHEDULE = 0x0040, /* enqueue is pending due to re-arm while running */ 369 THREAD_CALL_RATELIMITED = 0x0080, /* timer doesn't fire until slop+deadline */ 370 THREAD_CALL_FLAG_CONTINUOUS = 0x0100, /* deadline is in continuous time */ 371 THREAD_CALL_INITIALIZED = 0x0200, /* thread call is initialized */ 372 }); 373 374 struct thread_call { 375 /* Originally requested deadline */ 376 uint64_t tc_soft_deadline; 377 /* Deadline presented to hardware (post-leeway) stored in tc_pqlink.deadline */ 378 struct priority_queue_entry_deadline tc_pqlink; 379 /* Which queue head is this call enqueued on */ 380 queue_head_t *tc_queue; 381 queue_chain_t tc_qlink; 382 thread_call_index_t tc_index; 383 thread_call_flags_t tc_flags; 384 int32_t tc_refs; 385 /* Time to deadline at creation */ 386 uint64_t tc_ttd; 387 /* Timestamp of enqueue on pending queue */ 388 uint64_t tc_pending_timestamp; 389 thread_call_func_t tc_func; 390 thread_call_param_t tc_param0; 391 thread_call_param_t tc_param1; 392 uint64_t tc_submit_count; 393 uint64_t tc_finish_count; 394 }; 395 396 typedef struct thread_call thread_call_data_t; 397 398 extern void thread_call_setup( 399 thread_call_t call, 400 thread_call_func_t func, 401 thread_call_param_t param0); 402 403 extern void thread_call_setup_with_options( 404 thread_call_t call, 405 thread_call_func_t func, 406 thread_call_param_t param0, 407 thread_call_priority_t pri, 408 thread_call_options_t options); 409 410 extern void thread_call_delayed_timer_rescan_all(void); 411 extern uint64_t thread_call_get_armed_deadline(thread_call_t call); 412 413 struct thread_call_thread_state; 414 415 #endif /* MACH_KERNEL_PRIVATE */ 416 417 #ifdef XNU_KERNEL_PRIVATE 418 419 __BEGIN_DECLS 420 421 /* 422 * These routines are equivalent to their thread_call_enter_XXX 423 * variants, only the thread_call_t is allocated out of a 424 * fixed preallocated pool of memory, and will panic if the pool 425 * is exhausted. 426 */ 427 428 extern void thread_call_func_delayed( 429 thread_call_func_t func, 430 thread_call_param_t param, 431 uint64_t deadline); 432 433 extern void thread_call_func_delayed_with_leeway( 434 thread_call_func_t func, 435 thread_call_param_t param, 436 uint64_t deadline, 437 uint64_t leeway, 438 uint32_t flags); 439 440 /* 441 * This iterates all of the pending or delayed thread calls in the group, 442 * which is really inefficient. 443 * 444 * This is deprecated, switch to an allocated thread call instead. 445 */ 446 extern boolean_t thread_call_func_cancel( 447 thread_call_func_t func, 448 thread_call_param_t param, 449 boolean_t cancel_all); 450 451 /* 452 * Called on the wake path to adjust the thread callouts running in mach_continuous_time 453 */ 454 extern void adjust_cont_time_thread_calls(void); 455 456 /* called by IOTimerEventSource to track when the workloop lock has been taken */ 457 extern void thread_call_start_iotes_invocation(thread_call_t call); 458 459 __END_DECLS 460 461 #endif /* XNU_KERNEL_PRIVATE */ 462 463 #endif /* _KERN_THREAD_CALL_H_ */ 464