xref: /xnu-8796.121.2/osfmk/kern/thread_call.h (revision c54f35ca767986246321eb901baf8f5ff7923f6a)
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