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