xref: /xnu-10063.141.1/osfmk/kern/epoch_sync.h (revision d8b80295118ef25ac3a784134bcf95cd8e88109f)
1 /*
2  * Copyright (c) 2022 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 #pragma once
30 
31 #include <kern/thread.h>
32 
33 #include <os/atomic.h>
34 
35 #include <stdint.h>
36 #include <stdbool.h>
37 
38 /*
39  * Epoch WAIT/WAKE blocking.
40  *
41  * Epoch WAIT/WAKE provides a generic means to block and unblock on a turnstile
42  * wait queue with minimal knowledge of the underlying synchronization
43  * implementation. This is useful in environments where it's not possible to
44  * block (like exclaves). No direct access to the memory backing the
45  * synchronization primitive is required (in fact, the exclaves security model
46  * explicitly forbids this).
47  * Instead, an epoch is passed which provides an ordering and hence a means to
48  * detect out-of-order WAITs/WAKEs.
49  *
50  * An epoch is a counter value. The epoch is incremented before calling WAKE
51  * (for example when releasing a lock). Each ID maps to an associated counter.
52  * Counters may be shared by multiple IDs. To avoid blocking when an owner has
53  * already released its resource, the epoch is checked for freshness. A stale
54  * epoch causes WAIT to immediately return without blocking. Too much sharing of
55  * counters can cause waiters to return when they could have blocked.
56  *
57  * There are two major constraints for callers of these APIs:
58  *
59  * 1. The kernel's idea of the owning thread must be kept up-to-date
60  *
61  * - On WAIT, the owner becomes the thread described by 'owner'.
62  * - On WAKE, the owner is the woken thread (iff it's not the last waiter)
63  *
64  * If the owning thread doesn't call back into WAIT or WAKE again it may run
65  * with elevated privileges when it shouldn't.
66  *
67  * 2. WAITs which result in a thread blocking must be woken with WAKE
68  * This one is somewhat obvious. The only way for a thread blocked in WAIT to
69  * come back is to be woken with a WAKE. Pre-posted wakes (wakes when there is
70  * no waiter) or stale waits (out of date epoch) return immediately.
71  *
72  */
73 
74 __BEGIN_DECLS
75 
76 struct ht;
77 
78 /*
79  * @struct esync_queue_ht
80  *
81  * @abstract Identifies the epoch sync space of synchronization objects
82  * associated with "queues".
83  */
84 extern struct ht esync_queue_ht;
85 
86 /*
87  * @struct esync_thread_ht
88  *
89  * @abstract Identifies the epoch sync space of synchronization objects
90  * associated with "threads".
91  */
92 extern struct ht esync_thread_ht;
93 
94 /*!
95  * @enum esync_policy_t
96  *
97  * @abstract Constants defining the policy associated with a synchronization
98  * object.
99  *
100  * @constant ESYNC_POLICY_NONE
101  * Unspecified.
102  *
103  * @constant ESYNC_POLICY_USER
104  * User.
105  *
106  * @constant ESYNC_POLICY_KERNEL
107  * Kernel.
108  */
109 typedef enum __enum_closed {
110 	ESYNC_POLICY_NONE                = 0,
111 	ESYNC_POLICY_USER                = 1,
112 	ESYNC_POLICY_KERNEL              = 2,
113 } esync_policy_t;
114 
115 /*!
116  * @function esync_wait
117  *
118  * @abstract
119  * Wait on a turnstile associated with the specified id
120  *
121  * @param ns
122  * Namespace in which 'id' lives
123  *
124  * @param id
125  * Synchronization object identifier
126  *
127  * @param epoch
128  * Latest epoch of the synchronization object
129  *
130  * @param owner_ctid
131  * Owner of the synchronization object
132  *
133  * @param interruptible
134  * Interruptible flag
135  *
136  * @param policy
137  * A user or kernel synchronization object
138  *
139  * @return
140  * Result of blocking call (or THREAD_NOT_WAITING for pre-posted waits)
141  */
142 extern wait_result_t esync_wait(struct ht *ns, uint64_t id, uint64_t epoch,
143     os_atomic(uint64_t) * counter, ctid_t owner_ctid, esync_policy_t policy,
144     wait_interrupt_t interruptible);
145 
146 /*!
147  * @enum esync_wake_mode_t
148  *
149  * @abstract Constants defining modes for esync_wake
150  *
151  * @constant ESYNC_WAKE_ONE
152  * Wake a single waiter
153  *
154  * @constant ESYNC_WAKE_ALL
155  * Wake all waiters
156  *
157  * @constant ESYNC_WAKE_ONE_WITH_OWNER
158  * Wake a single owner and identify the new owner
159  *
160  * @constant ESYNC_WAKE_THREAD
161  * Wake the specified thread. There is no new owner.
162  */
163 typedef enum __enum_closed {
164 	ESYNC_WAKE_ONE            = 1,
165 	ESYNC_WAKE_ALL            = 2,
166 	ESYNC_WAKE_ONE_WITH_OWNER = 3,
167 	ESYNC_WAKE_THREAD         = 4,
168 } esync_wake_mode_t;
169 
170 /*!
171  * @function esync_wake
172  *
173  * @abstract
174  * Wake one or more threads which have blocked on the specified id in esync_wait
175  *
176  * @param ns
177  * Namespace in which 'id' lives
178  *
179  * @param id
180  * Synchronization object identifier
181  *
182  * @param epoch
183  * Latest epoch of the synchronization object
184  *
185  * @param mode
186  * Type of wake to perform. All, one or one with specified owner (new
187  * inheritor).
188  *
189  * @param ctid
190  * Thread identifier. Can identifier the new owner (ESYNC_WAKE_ONE_WITH_OWNER)
191  * or the thread to be woken (ESYNC_WAKE_THREAD).
192  *
193  * @return
194  * KERN_SUCCESS or KERN_NOT_WAITING if no thread was woken
195  */
196 extern kern_return_t esync_wake(struct ht *ns, uint64_t id, uint64_t epoch,
197     os_atomic(uint64_t) * counter, esync_wake_mode_t mode,
198     ctid_t ctid);
199 
200 __END_DECLS
201