xref: /xnu-11215.1.10/osfmk/kern/epoch_sync.h (revision 8d741a5de7ff4191bf97d57b9f54c2f6d4a15585)
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 /*
77  * @enum esync_space_t
78  *
79  * @abstract Identifies the epoch sync space.
80  *
81  * @constant ESYNC_SPACE_EXCLAVES_Q
82  * Exclaves queues.
83  *
84  * @constant ESYNC_SPACE_EXCLAVES_T
85  * Exclaves threads.
86  */
87 typedef enum __enum_closed {
88 	ESYNC_SPACE_TEST       = 0,
89 	ESYNC_SPACE_EXCLAVES_Q = 1,
90 	ESYNC_SPACE_EXCLAVES_T = 2,
91 } esync_space_t;
92 
93 /*!
94  * @enum esync_policy_t
95  *
96  * @abstract Constants defining the policy associated with a synchronization
97  * object.
98  *
99  * @constant ESYNC_POLICY_NONE
100  * Unspecified.
101  *
102  * @constant ESYNC_POLICY_USER
103  * User.
104  *
105  * @constant ESYNC_POLICY_KERNEL
106  * Kernel.
107  */
108 typedef enum __enum_closed {
109 	ESYNC_POLICY_NONE                = 0,
110 	ESYNC_POLICY_USER                = 1,
111 	ESYNC_POLICY_KERNEL              = 2,
112 } esync_policy_t;
113 
114 /*!
115  * @function esync_wait
116  *
117  * @abstract
118  * Wait on a turnstile associated with the specified id
119  *
120  * @param space
121  * Namespace in which 'id' lives
122  *
123  * @param id
124  * Synchronization object identifier
125  *
126  * @param epoch
127  * Latest epoch of the synchronization object
128  *
129  * @param owner_ctid
130  * Owner of the synchronization object
131  *
132  * @param interruptible
133  * Interruptible flag
134  *
135  * @param policy
136  * A user or kernel synchronization object
137  *
138  * @return
139  * Result of blocking call (or THREAD_NOT_WAITING for pre-posted waits)
140  */
141 extern wait_result_t esync_wait(esync_space_t space, uint64_t id,
142     uint64_t epoch, os_atomic(uint64_t) * counter, ctid_t owner_ctid,
143     esync_policy_t policy, wait_interrupt_t interruptible);
144 
145 /*!
146  * @enum esync_wake_mode_t
147  *
148  * @abstract Constants defining modes for esync_wake
149  *
150  * @constant ESYNC_WAKE_ONE
151  * Wake a single waiter
152  *
153  * @constant ESYNC_WAKE_ALL
154  * Wake all waiters
155  *
156  * @constant ESYNC_WAKE_ONE_WITH_OWNER
157  * Wake a single owner and identify the new owner
158  *
159  * @constant ESYNC_WAKE_THREAD
160  * Wake the specified thread. There is no new owner.
161  */
162 typedef enum __enum_closed {
163 	ESYNC_WAKE_ONE            = 1,
164 	ESYNC_WAKE_ALL            = 2,
165 	ESYNC_WAKE_ONE_WITH_OWNER = 3,
166 	ESYNC_WAKE_THREAD         = 4,
167 } esync_wake_mode_t;
168 
169 /*!
170  * @function esync_wake
171  *
172  * @abstract
173  * Wake one or more threads which have blocked on the specified id in esync_wait
174  *
175  * @param space
176  * Namespace in which 'id' lives
177  *
178  * @param id
179  * Synchronization object identifier
180  *
181  * @param epoch
182  * Latest epoch of the synchronization object
183  *
184  * @param mode
185  * Type of wake to perform. All, one or one with specified owner (new
186  * inheritor).
187  *
188  * @param ctid
189  * Thread identifier. Can identifier the new owner (ESYNC_WAKE_ONE_WITH_OWNER)
190  * or the thread to be woken (ESYNC_WAKE_THREAD).
191  *
192  * @return
193  * KERN_SUCCESS or KERN_NOT_WAITING if no thread was woken
194  */
195 extern kern_return_t esync_wake(esync_space_t space, uint64_t id,
196     uint64_t epoch, os_atomic(uint64_t) * counter, esync_wake_mode_t mode,
197     ctid_t ctid);
198 
199 __END_DECLS
200