xref: /xnu-10063.121.3/osfmk/kern/epoch_sync.h (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
1*2c2f96dcSApple OSS Distributions /*
2*2c2f96dcSApple OSS Distributions  * Copyright (c) 2022 Apple Inc. All rights reserved.
3*2c2f96dcSApple OSS Distributions  *
4*2c2f96dcSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*2c2f96dcSApple OSS Distributions  *
6*2c2f96dcSApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*2c2f96dcSApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*2c2f96dcSApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*2c2f96dcSApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*2c2f96dcSApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*2c2f96dcSApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*2c2f96dcSApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*2c2f96dcSApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*2c2f96dcSApple OSS Distributions  *
15*2c2f96dcSApple OSS Distributions  * Please obtain a copy of the License at
16*2c2f96dcSApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*2c2f96dcSApple OSS Distributions  *
18*2c2f96dcSApple OSS Distributions  * The Original Code and all software distributed under the License are
19*2c2f96dcSApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*2c2f96dcSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*2c2f96dcSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*2c2f96dcSApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*2c2f96dcSApple OSS Distributions  * Please see the License for the specific language governing rights and
24*2c2f96dcSApple OSS Distributions  * limitations under the License.
25*2c2f96dcSApple OSS Distributions  *
26*2c2f96dcSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*2c2f96dcSApple OSS Distributions  */
28*2c2f96dcSApple OSS Distributions 
29*2c2f96dcSApple OSS Distributions #pragma once
30*2c2f96dcSApple OSS Distributions 
31*2c2f96dcSApple OSS Distributions #include <kern/thread.h>
32*2c2f96dcSApple OSS Distributions 
33*2c2f96dcSApple OSS Distributions #include <os/atomic.h>
34*2c2f96dcSApple OSS Distributions 
35*2c2f96dcSApple OSS Distributions #include <stdint.h>
36*2c2f96dcSApple OSS Distributions #include <stdbool.h>
37*2c2f96dcSApple OSS Distributions 
38*2c2f96dcSApple OSS Distributions /*
39*2c2f96dcSApple OSS Distributions  * Epoch WAIT/WAKE blocking.
40*2c2f96dcSApple OSS Distributions  *
41*2c2f96dcSApple OSS Distributions  * Epoch WAIT/WAKE provides a generic means to block and unblock on a turnstile
42*2c2f96dcSApple OSS Distributions  * wait queue with minimal knowledge of the underlying synchronization
43*2c2f96dcSApple OSS Distributions  * implementation. This is useful in environments where it's not possible to
44*2c2f96dcSApple OSS Distributions  * block (like exclaves). No direct access to the memory backing the
45*2c2f96dcSApple OSS Distributions  * synchronization primitive is required (in fact, the exclaves security model
46*2c2f96dcSApple OSS Distributions  * explicitly forbids this).
47*2c2f96dcSApple OSS Distributions  * Instead, an epoch is passed which provides an ordering and hence a means to
48*2c2f96dcSApple OSS Distributions  * detect out-of-order WAITs/WAKEs.
49*2c2f96dcSApple OSS Distributions  *
50*2c2f96dcSApple OSS Distributions  * An epoch is a counter value. The epoch is incremented before calling WAKE
51*2c2f96dcSApple OSS Distributions  * (for example when releasing a lock). Each ID maps to an associated counter.
52*2c2f96dcSApple OSS Distributions  * Counters may be shared by multiple IDs. To avoid blocking when an owner has
53*2c2f96dcSApple OSS Distributions  * already released its resource, the epoch is checked for freshness. A stale
54*2c2f96dcSApple OSS Distributions  * epoch causes WAIT to immediately return without blocking. Too much sharing of
55*2c2f96dcSApple OSS Distributions  * counters can cause waiters to return when they could have blocked.
56*2c2f96dcSApple OSS Distributions  *
57*2c2f96dcSApple OSS Distributions  * There are two major constraints for callers of these APIs:
58*2c2f96dcSApple OSS Distributions  *
59*2c2f96dcSApple OSS Distributions  * 1. The kernel's idea of the owning thread must be kept up-to-date
60*2c2f96dcSApple OSS Distributions  *
61*2c2f96dcSApple OSS Distributions  * - On WAIT, the owner becomes the thread described by 'owner'.
62*2c2f96dcSApple OSS Distributions  * - On WAKE, the owner is the woken thread (iff it's not the last waiter)
63*2c2f96dcSApple OSS Distributions  *
64*2c2f96dcSApple OSS Distributions  * If the owning thread doesn't call back into WAIT or WAKE again it may run
65*2c2f96dcSApple OSS Distributions  * with elevated privileges when it shouldn't.
66*2c2f96dcSApple OSS Distributions  *
67*2c2f96dcSApple OSS Distributions  * 2. WAITs which result in a thread blocking must be woken with WAKE
68*2c2f96dcSApple OSS Distributions  * This one is somewhat obvious. The only way for a thread blocked in WAIT to
69*2c2f96dcSApple OSS Distributions  * come back is to be woken with a WAKE. Pre-posted wakes (wakes when there is
70*2c2f96dcSApple OSS Distributions  * no waiter) or stale waits (out of date epoch) return immediately.
71*2c2f96dcSApple OSS Distributions  *
72*2c2f96dcSApple OSS Distributions  */
73*2c2f96dcSApple OSS Distributions 
74*2c2f96dcSApple OSS Distributions __BEGIN_DECLS
75*2c2f96dcSApple OSS Distributions 
76*2c2f96dcSApple OSS Distributions struct ht;
77*2c2f96dcSApple OSS Distributions 
78*2c2f96dcSApple OSS Distributions /*
79*2c2f96dcSApple OSS Distributions  * @struct esync_queue_ht
80*2c2f96dcSApple OSS Distributions  *
81*2c2f96dcSApple OSS Distributions  * @abstract Identifies the epoch sync space of synchronization objects
82*2c2f96dcSApple OSS Distributions  * associated with "queues".
83*2c2f96dcSApple OSS Distributions  */
84*2c2f96dcSApple OSS Distributions extern struct ht esync_queue_ht;
85*2c2f96dcSApple OSS Distributions 
86*2c2f96dcSApple OSS Distributions /*
87*2c2f96dcSApple OSS Distributions  * @struct esync_thread_ht
88*2c2f96dcSApple OSS Distributions  *
89*2c2f96dcSApple OSS Distributions  * @abstract Identifies the epoch sync space of synchronization objects
90*2c2f96dcSApple OSS Distributions  * associated with "threads".
91*2c2f96dcSApple OSS Distributions  */
92*2c2f96dcSApple OSS Distributions extern struct ht esync_thread_ht;
93*2c2f96dcSApple OSS Distributions 
94*2c2f96dcSApple OSS Distributions /*!
95*2c2f96dcSApple OSS Distributions  * @enum esync_policy_t
96*2c2f96dcSApple OSS Distributions  *
97*2c2f96dcSApple OSS Distributions  * @abstract Constants defining the policy associated with a synchronization
98*2c2f96dcSApple OSS Distributions  * object.
99*2c2f96dcSApple OSS Distributions  *
100*2c2f96dcSApple OSS Distributions  * @constant ESYNC_POLICY_NONE
101*2c2f96dcSApple OSS Distributions  * Unspecified.
102*2c2f96dcSApple OSS Distributions  *
103*2c2f96dcSApple OSS Distributions  * @constant ESYNC_POLICY_USER
104*2c2f96dcSApple OSS Distributions  * User.
105*2c2f96dcSApple OSS Distributions  *
106*2c2f96dcSApple OSS Distributions  * @constant ESYNC_POLICY_KERNEL
107*2c2f96dcSApple OSS Distributions  * Kernel.
108*2c2f96dcSApple OSS Distributions  */
109*2c2f96dcSApple OSS Distributions typedef enum __enum_closed {
110*2c2f96dcSApple OSS Distributions 	ESYNC_POLICY_NONE                = 0,
111*2c2f96dcSApple OSS Distributions 	ESYNC_POLICY_USER                = 1,
112*2c2f96dcSApple OSS Distributions 	ESYNC_POLICY_KERNEL              = 2,
113*2c2f96dcSApple OSS Distributions } esync_policy_t;
114*2c2f96dcSApple OSS Distributions 
115*2c2f96dcSApple OSS Distributions /*!
116*2c2f96dcSApple OSS Distributions  * @function esync_wait
117*2c2f96dcSApple OSS Distributions  *
118*2c2f96dcSApple OSS Distributions  * @abstract
119*2c2f96dcSApple OSS Distributions  * Wait on a turnstile associated with the specified id
120*2c2f96dcSApple OSS Distributions  *
121*2c2f96dcSApple OSS Distributions  * @param ns
122*2c2f96dcSApple OSS Distributions  * Namespace in which 'id' lives
123*2c2f96dcSApple OSS Distributions  *
124*2c2f96dcSApple OSS Distributions  * @param id
125*2c2f96dcSApple OSS Distributions  * Synchronization object identifier
126*2c2f96dcSApple OSS Distributions  *
127*2c2f96dcSApple OSS Distributions  * @param epoch
128*2c2f96dcSApple OSS Distributions  * Latest epoch of the synchronization object
129*2c2f96dcSApple OSS Distributions  *
130*2c2f96dcSApple OSS Distributions  * @param owner_ctid
131*2c2f96dcSApple OSS Distributions  * Owner of the synchronization object
132*2c2f96dcSApple OSS Distributions  *
133*2c2f96dcSApple OSS Distributions  * @param interruptible
134*2c2f96dcSApple OSS Distributions  * Interruptible flag
135*2c2f96dcSApple OSS Distributions  *
136*2c2f96dcSApple OSS Distributions  * @param policy
137*2c2f96dcSApple OSS Distributions  * A user or kernel synchronization object
138*2c2f96dcSApple OSS Distributions  *
139*2c2f96dcSApple OSS Distributions  * @return
140*2c2f96dcSApple OSS Distributions  * Result of blocking call (or THREAD_NOT_WAITING for pre-posted waits)
141*2c2f96dcSApple OSS Distributions  */
142*2c2f96dcSApple OSS Distributions extern wait_result_t esync_wait(struct ht *ns, uint64_t id, uint64_t epoch,
143*2c2f96dcSApple OSS Distributions     os_atomic(uint64_t) * counter, ctid_t owner_ctid, esync_policy_t policy,
144*2c2f96dcSApple OSS Distributions     wait_interrupt_t interruptible);
145*2c2f96dcSApple OSS Distributions 
146*2c2f96dcSApple OSS Distributions /*!
147*2c2f96dcSApple OSS Distributions  * @enum esync_wake_mode_t
148*2c2f96dcSApple OSS Distributions  *
149*2c2f96dcSApple OSS Distributions  * @abstract Constants defining modes for esync_wake
150*2c2f96dcSApple OSS Distributions  *
151*2c2f96dcSApple OSS Distributions  * @constant ESYNC_WAKE_ONE
152*2c2f96dcSApple OSS Distributions  * Wake a single waiter
153*2c2f96dcSApple OSS Distributions  *
154*2c2f96dcSApple OSS Distributions  * @constant ESYNC_WAKE_ALL
155*2c2f96dcSApple OSS Distributions  * Wake all waiters
156*2c2f96dcSApple OSS Distributions  *
157*2c2f96dcSApple OSS Distributions  * @constant ESYNC_WAKE_ONE_WITH_OWNER
158*2c2f96dcSApple OSS Distributions  * Wake a single owner and identify the new owner
159*2c2f96dcSApple OSS Distributions  *
160*2c2f96dcSApple OSS Distributions  * @constant ESYNC_WAKE_THREAD
161*2c2f96dcSApple OSS Distributions  * Wake the specified thread. There is no new owner.
162*2c2f96dcSApple OSS Distributions  */
163*2c2f96dcSApple OSS Distributions typedef enum __enum_closed {
164*2c2f96dcSApple OSS Distributions 	ESYNC_WAKE_ONE            = 1,
165*2c2f96dcSApple OSS Distributions 	ESYNC_WAKE_ALL            = 2,
166*2c2f96dcSApple OSS Distributions 	ESYNC_WAKE_ONE_WITH_OWNER = 3,
167*2c2f96dcSApple OSS Distributions 	ESYNC_WAKE_THREAD         = 4,
168*2c2f96dcSApple OSS Distributions } esync_wake_mode_t;
169*2c2f96dcSApple OSS Distributions 
170*2c2f96dcSApple OSS Distributions /*!
171*2c2f96dcSApple OSS Distributions  * @function esync_wake
172*2c2f96dcSApple OSS Distributions  *
173*2c2f96dcSApple OSS Distributions  * @abstract
174*2c2f96dcSApple OSS Distributions  * Wake one or more threads which have blocked on the specified id in esync_wait
175*2c2f96dcSApple OSS Distributions  *
176*2c2f96dcSApple OSS Distributions  * @param ns
177*2c2f96dcSApple OSS Distributions  * Namespace in which 'id' lives
178*2c2f96dcSApple OSS Distributions  *
179*2c2f96dcSApple OSS Distributions  * @param id
180*2c2f96dcSApple OSS Distributions  * Synchronization object identifier
181*2c2f96dcSApple OSS Distributions  *
182*2c2f96dcSApple OSS Distributions  * @param epoch
183*2c2f96dcSApple OSS Distributions  * Latest epoch of the synchronization object
184*2c2f96dcSApple OSS Distributions  *
185*2c2f96dcSApple OSS Distributions  * @param mode
186*2c2f96dcSApple OSS Distributions  * Type of wake to perform. All, one or one with specified owner (new
187*2c2f96dcSApple OSS Distributions  * inheritor).
188*2c2f96dcSApple OSS Distributions  *
189*2c2f96dcSApple OSS Distributions  * @param ctid
190*2c2f96dcSApple OSS Distributions  * Thread identifier. Can identifier the new owner (ESYNC_WAKE_ONE_WITH_OWNER)
191*2c2f96dcSApple OSS Distributions  * or the thread to be woken (ESYNC_WAKE_THREAD).
192*2c2f96dcSApple OSS Distributions  *
193*2c2f96dcSApple OSS Distributions  * @return
194*2c2f96dcSApple OSS Distributions  * KERN_SUCCESS or KERN_NOT_WAITING if no thread was woken
195*2c2f96dcSApple OSS Distributions  */
196*2c2f96dcSApple OSS Distributions extern kern_return_t esync_wake(struct ht *ns, uint64_t id, uint64_t epoch,
197*2c2f96dcSApple OSS Distributions     os_atomic(uint64_t) * counter, esync_wake_mode_t mode,
198*2c2f96dcSApple OSS Distributions     ctid_t ctid);
199*2c2f96dcSApple OSS Distributions 
200*2c2f96dcSApple OSS Distributions __END_DECLS
201