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
43struct thread_call;
44typedef struct thread_call *thread_call_t;
45
46typedef void *thread_call_param_t;
47typedef 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 */
68typedef 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
76enum {
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};
84typedef 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 */
99extern 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 */
111extern 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 */
127extern 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 */
141extern 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 */
202extern 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 */
222extern 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 */
240extern 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 */
252extern 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 */
266extern 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 */
282extern 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 */
300extern thread_call_t
301thread_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 */
313extern boolean_t
314thread_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 */
329extern 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 */
339boolean_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
374struct 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
396typedef struct thread_call thread_call_data_t;
397
398extern void thread_call_setup(
399 thread_call_t call,
400 thread_call_func_t func,
401 thread_call_param_t param0);
402
403extern 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
410extern void thread_call_delayed_timer_rescan_all(void);
411extern uint64_t thread_call_get_armed_deadline(thread_call_t call);
412
413struct 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
428extern void thread_call_func_delayed(
429 thread_call_func_t func,
430 thread_call_param_t param,
431 uint64_t deadline);
432
433extern 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 */
446extern 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 */
454extern void adjust_cont_time_thread_calls(void);
455
456/* called by IOTimerEventSource to track when the workloop lock has been taken */
457extern 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