Source to osfmk/kern/wait_queue.h
#ifndef _KERN_WAIT_QUEUE_H_
#define _KERN_WAIT_QUEUE_H_
#include <kern/kern_types.h> /* for wait_queue_t */
#include <mach/sync_policy.h>
#ifdef MACH_KERNEL_PRIVATE
#include <kern/lock.h>
#include <kern/queue.h>
/*
* wait_queue_t
* This is the definition of the common event wait queue
* that the scheduler APIs understand. It is used
* internally by the gerneralized event waiting mechanism
* (assert_wait), and also for items that maintain their
* own wait queues (such as ports and semaphores).
*
* It is not published to other kernel components. They
* can create wait queues by calling wait_queue_alloc.
*
* NOTE: Hardware locks are used to protect event wait
* queues since interrupt code is free to post events to
* them.
*/
typedef struct wait_queue {
hw_lock_data_t wq_interlock; /* interlock */
unsigned int /* flags */
/* boolean_t */ wq_fifo:1, /* fifo wakeup policy? */
wq_issub:1, /* is waitq linked? */
:0; /* force to long boundary */
queue_head_t wq_queue; /* queue of elements */
} WaitQueue;
/*
* wait_queue_sub_t
* This is the common definition for a subordinate wait queue.
* These can be linked as members/elements of multiple regular
* wait queues. They have an additional set of linkages to
* identify the linkage structures that point to them.
*/
typedef struct wait_queue_sub {
WaitQueue wqs_wait_queue; /* our wait queue */
queue_head_t wqs_sublinks; /* links from sub perspective */
} WaitQueueSub;
typedef WaitQueueSub *wait_queue_sub_t;
#define WAIT_QUEUE_SUB_NULL ((wait_queue_sub_t)0)
/*
* wait_queue_element_t
* This structure describes the elements on an event wait
* queue. It is the common first fields in a thread shuttle
* and wait_queue_link_t. In that way, a wait queue can
* consist of both thread shuttle elements and links off of
* to other (subordinate) wait queues.
*
* WARNING: The first three fields of the thread shuttle
* definition does not use this definition yet. Any change in
* the layout here will have to be matched with a change there.
*/
typedef struct wait_queue_element {
queue_chain_t wqe_links; /* link of elements on this queue */
wait_queue_t wqe_queue; /* queue this element is on */
event_t wqe_event; /* event this element is waiting for */
} *wait_queue_element_t;
/*
* wait_queue_link_t
* Specialized wait queue element type for linking subordinate
* event waits queues onto a wait queue. In this way, an event
* can be constructed so that any thread waiting on any number
* of associated wait queues can handle the event, while letting
* the thread only be linked on the single wait queue it blocked on.
*
* One use: ports in multiple portsets. Each thread is queued up
* on the portset that it specifically blocked on during a receive
* operation. Each port's event queue links in all the portset
* event queues of which it is a member. An IPC event post associated
* with that port may wake up any thread from any of those portsets,
* or one that was waiting locally on the port itself.
*/
typedef struct wait_queue_link {
struct wait_queue_element wql_element; /* element on master */
wait_queue_sub_t wql_subqueue; /* sub queue */
queue_chain_t wql_sublinks; /* element on sub */
} *wait_queue_link_t;
#define WAIT_QUEUE_LINK_NULL ((wait_queue_link_t)0)
#define wql_links wql_element.wqe_links
#define wql_queue wql_element.wqe_queue
#define wql_event wql_element.wqe_event
extern int wait_queue_subordinate;
#define WAIT_QUEUE_SUBORDINATE &_wait_queue_subordinate
extern void wait_queue_init(
wait_queue_t wait_queue,
int policy);
extern kern_return_t wait_queue_link(
wait_queue_t wait_queue,
wait_queue_sub_t subordinate_queue);
extern kern_return_t wait_queue_unlink(
wait_queue_t wait_queue,
wait_queue_sub_t subordinate_queue);
extern void wait_queue_unlink_one(
wait_queue_t wait_queue,
wait_queue_sub_t *subordinate_queue_pointer);
extern boolean_t wait_queue_member_queue(
wait_queue_t wait_queue,
wait_queue_sub_t subordinate_queue);
extern kern_return_t clear_wait_queue_internal(
thread_t thread,
int result);
extern kern_return_t wait_queue_remove(
thread_t thread);
#define wait_queue_assert_possible(thread) \
((thread)->wait_queue == WAIT_QUEUE_NULL)
#define wait_queue_empty(wq) (queue_empty(&(wq)->wq_queue))
#define wait_queue_held(wq) (hw_lock_held(&(wq)->wq_interlock))
#define wait_queue_is_sub(wqs) ((wqs)->wqs_wait_queue.wq_issub)
#define wqs_lock(wqs) wait_queue_lock(&(wqs)->wqs_wait_queue)
#define wqs_unlock(wqs) wait_queue_unlock(&(wqs)->wqs_wait_queue)
#define wqs_lock_try(wqs) wait_queue__try_lock(&(wqs)->wqs_wait_queue)
/******** Decomposed interfaces (to build higher level constructs) ***********/
extern void wait_queue_lock(
wait_queue_t wait_queue);
extern void wait_queue_unlock(
wait_queue_t wait_queue);
extern boolean_t wait_queue_lock_try(
wait_queue_t wait_queue);
/* assert intent to wait on a locked wait queue */
extern void wait_queue_assert_wait_locked(
wait_queue_t wait_queue,
event_t wait_event,
int interruptible,
boolean_t unlock);
/* peek to see which thread would be chosen for a wakeup - but keep on queue */
extern void wait_queue_peek_locked(
wait_queue_t wait_queue,
event_t event,
thread_t *thread,
wait_queue_t *found_queue);
/* peek to see which thread would be chosen for a wakeup - but keep on queue */
extern void wait_queue_pull_thread_locked(
wait_queue_t wait_queue,
thread_t thread,
boolean_t unlock);
/* wakeup all threads waiting for a particular event on locked queue */
extern kern_return_t wait_queue_wakeup_one_locked(
wait_queue_t wait_queue,
event_t wake_event,
int result,
boolean_t unlock);
/* wakeup one thread waiting for a particular event on locked queue */
extern kern_return_t wait_queue_wakeup_one_locked(
wait_queue_t wait_queue,
event_t wake_event,
int result,
boolean_t unlock);
/* return the identity of a thread that is waiting for <wait_queue, event> */
extern thread_t wait_queue_recommend_locked(
wait_queue_t wait_queue,
event_t wake_event);
/* return identity of a thread awakened for a particular <wait_queue,event> */
extern thread_t wait_queue_wakeup_identity_locked(
wait_queue_t wait_queue,
event_t wake_event,
int result,
boolean_t unlock);
/* wakeup thread iff its still waiting for a particular event on locked queue */
extern kern_return_t wait_queue_wakeup_thread_locked(
wait_queue_t wait_queue,
event_t wake_event,
thread_t thread,
int result,
boolean_t unlock);
#endif /* MACH_KERNEL_PRIVATE */
extern wait_queue_t wait_queue_alloc(
int policy);
extern void wait_queue_free(
wait_queue_t wait_queue);
/******** Standalone interfaces (not a part of a higher construct) ************/
/* assert intent to wait on <wait_queue,event> pair */
extern void wait_queue_assert_wait(
wait_queue_t wait_queue,
event_t wait_event,
boolean_t interruptible);
/* wakeup the most appropriate thread waiting on <wait_queue,event> pair */
extern kern_return_t wait_queue_wakeup_one(
wait_queue_t wait_queue,
event_t wake_event,
int result);
/* wakeup all the threads waiting on <wait_queue,event> pair */
extern kern_return_t wait_queue_wakeup_all(
wait_queue_t wait_queue,
event_t wake_event,
int result);
/* wakeup a specified thread waiting iff waiting on <wait_queue,event> pair */
extern kern_return_t wait_queue_wakeup_thread(
wait_queue_t wait_queue,
event_t wake_event,
thread_t thread,
int result);
#endif /* _KERN_WAIT_QUEUE_H_ */