/ duct-tape / xnu / osfmk / kern / thread_call.h
thread_call.h
  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_HIGH          = 0,
350  	THREAD_CALL_INDEX_KERNEL        = 1,
351  	THREAD_CALL_INDEX_USER          = 2,
352  	THREAD_CALL_INDEX_LOW           = 3,
353  	THREAD_CALL_INDEX_KERNEL_HIGH   = 4,
354  	THREAD_CALL_INDEX_QOS_UI        = 5,
355  	THREAD_CALL_INDEX_QOS_IN        = 6,
356  	THREAD_CALL_INDEX_QOS_UT        = 7,
357  	THREAD_CALL_INDEX_MAX           = 8,    /* count of thread call indexes */
358  });
359  
360  __options_closed_decl(thread_call_flags_t, uint16_t, {
361  	THREAD_CALL_ALLOC               = 0x0001,       /* memory owned by thread_call.c */
362  	THREAD_CALL_WAIT                = 0x0002,       /* thread waiting for call to finish running */
363  	THREAD_CALL_DELAYED             = 0x0004,       /* deadline based */
364  	THREAD_CALL_RUNNING             = 0x0008,       /* currently executing on a thread */
365  	THREAD_CALL_SIGNAL              = 0x0010,       /* call from timer interrupt instead of thread */
366  	THREAD_CALL_ONCE                = 0x0020,       /* pend the enqueue if re-armed while running */
367  	THREAD_CALL_RESCHEDULE          = 0x0040,       /* enqueue is pending due to re-arm while running */
368  	THREAD_CALL_RATELIMITED         = 0x0080,       /* timer doesn't fire until slop+deadline */
369  	THREAD_CALL_FLAG_CONTINUOUS     = 0x0100,       /* deadline is in continuous time */
370  });
371  
372  struct thread_call {
373  	/* Originally requested deadline */
374  	uint64_t                                tc_soft_deadline;
375  	/* Deadline presented to hardware (post-leeway) stored in tc_pqlink.deadline */
376  	struct priority_queue_entry_deadline    tc_pqlink;
377  	/* Which queue head is this call enqueued on */
378  	queue_head_t                            *tc_queue;
379  	queue_chain_t                           tc_qlink;
380  	thread_call_index_t                     tc_index;
381  	thread_call_flags_t                     tc_flags;
382  	int32_t                                 tc_refs;
383  	/* Time to deadline at creation */
384  	uint64_t                                tc_ttd;
385  	/* Timestamp of enqueue on pending queue */
386  	uint64_t                                tc_pending_timestamp;
387  	thread_call_func_t                      tc_func;
388  	thread_call_param_t                     tc_param0;
389  	thread_call_param_t                     tc_param1;
390  	uint64_t                                tc_submit_count;
391  	uint64_t                                tc_finish_count;
392  };
393  
394  typedef struct thread_call thread_call_data_t;
395  
396  extern void             thread_call_initialize(void);
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_ */