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 | |