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