1 /* 2 * Copyright (c) 2020 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 #ifndef _KERN_TICKET_LOCK_H_ 30 #define _KERN_TICKET_LOCK_H_ 31 32 #ifndef __ASSEMBLER__ 33 #include <kern/lock_types.h> 34 #include <kern/lock_group.h> 35 #endif /* __ASSEMBLER__ */ 36 37 /* 38 * TODO <rdar://problem/72157773>. We do not need to make 39 * the header available only to KERNEL_PRIVATE. 40 */ 41 #if KERNEL_PRIVATE 42 #ifndef __ASSEMBLER__ 43 44 __BEGIN_DECLS 45 46 #ifdef MACH_KERNEL_PRIVATE 47 48 /*! 49 * @typedef hw_lck_ticket_t 50 * 51 * @discussion 52 * This type describes the low level type for a ticket lock. 53 * @c lck_ticket_t provides a higher level abstraction 54 * that also provides thread ownership information. 55 * 56 * This lock is meant to be exactly 32bits to be able to replace 57 * hw_lock_bit_t locks when needed. 58 * 59 * This lower level interface supports an @c *_allow_invalid() 60 * to implement advanced memory reclamation schemes using sequestering. 61 * 62 * @c hw_lck_ticket_invalidate() must be used on locks 63 * that will be used this way: in addition to make subsequent calls to 64 * @c hw_lck_ticket_lock_allow_invalid() to fail, it allows for 65 * @c hw_lck_ticket_destroy() to synchronize with callers to 66 * @c hw_lck_ticket_lock_allow_invalid() who successfully reserved 67 * a ticket but will fail, ensuring the memory can't be freed too early. 68 * 69 * @note: 70 * At the moment, this construct only supports up to 255 CPUs. 71 * Supporting more CPUs requires losing the `lck_type` field, 72 * and burning the low bit of the cticket/nticket 73 * for the "invalidation" feature. 74 */ 75 typedef union { 76 struct { 77 uint8_t lck_type; 78 uint8_t lck_valid; 79 union { 80 struct { 81 uint8_t cticket; 82 uint8_t nticket; 83 }; 84 uint16_t tcurnext; 85 }; 86 }; 87 uint32_t lck_value; 88 } hw_lck_ticket_t; 89 90 /*! 91 * @typedef lck_ticket_t 92 * 93 * @discussion 94 * A higher level construct than hw_lck_ticket_t in 2 words 95 * like other kernel locks, which admits thread ownership information. 96 */ 97 typedef struct { 98 union { 99 uintptr_t lck_owner __kernel_data_semantics; 100 uintptr_t lck_tag __kernel_data_semantics; 101 }; 102 hw_lck_ticket_t tu; 103 } lck_ticket_t; 104 105 #define LCK_TICKET_TYPE 0x44 106 #define LCK_TICKET_TAG_DESTROYED 0xdead 107 108 #pragma GCC visibility push(hidden) 109 110 void hw_lck_ticket_init(hw_lck_ticket_t * tlock LCK_GRP_ARG(lck_grp_t *grp)); 111 void hw_lck_ticket_init_locked(hw_lck_ticket_t * tlock LCK_GRP_ARG(lck_grp_t *grp)); 112 void hw_lck_ticket_destroy(hw_lck_ticket_t * tlock, bool keep_type LCK_GRP_ARG(lck_grp_t *grp)); 113 114 bool hw_lck_ticket_held(hw_lck_ticket_t *tlock) __result_use_check; 115 void hw_lck_ticket_lock(hw_lck_ticket_t * tlock LCK_GRP_ARG(lck_grp_t *grp)); 116 hw_lock_status_t hw_lck_ticket_lock_to(hw_lck_ticket_t * tlock, uint64_t timeout, 117 hw_lock_timeout_handler_t handler LCK_GRP_ARG(lck_grp_t *grp)); 118 int hw_lck_ticket_lock_try(hw_lck_ticket_t * tlock LCK_GRP_ARG(lck_grp_t *grp)); 119 void hw_lck_ticket_unlock(hw_lck_ticket_t *tlock); 120 121 hw_lock_status_t hw_lck_ticket_lock_allow_invalid(hw_lck_ticket_t * tlock, 122 uint64_t timeout, hw_lock_timeout_handler_t handler LCK_GRP_ARG(lck_grp_t *grp)); 123 void hw_lck_ticket_invalidate(hw_lck_ticket_t *tlock); 124 125 #if !LOCK_STATS 126 #define hw_lck_ticket_init(lck, grp) hw_lck_ticket_init(lck) 127 #define hw_lck_ticket_init_locked(lck, grp) hw_lck_ticket_init_locked(lck) 128 #define hw_lck_ticket_destroy(lck, kt, grp) hw_lck_ticket_destroy(lck,kt) 129 #define hw_lck_ticket_lock(lck, grp) hw_lck_ticket_lock(lck) 130 #define hw_lck_ticket_lock_to(lck, to, cb, grp) hw_lck_ticket_lock_to(lck, to, cb) 131 #define hw_lck_ticket_lock_try(lck, grp) hw_lck_ticket_lock_try(lck) 132 #define hw_lck_ticket_lock_allow_invalid(lck, to, cb, grp) \ 133 hw_lck_ticket_lock_allow_invalid(lck, to, cb) 134 #endif /* !LOCK_STATS */ 135 136 #pragma GCC visibility pop 137 #else /* MACH_KERNEL_PRIVATE */ 138 139 typedef struct { 140 uintptr_t opaque1 __kernel_data_semantics; 141 uint32_t opaque2; 142 } lck_ticket_t; 143 144 #endif /* MACH_KERNEL_PRIVATE */ 145 146 void lck_ticket_init(lck_ticket_t *tlock, lck_grp_t *grp); 147 void lck_ticket_destroy(lck_ticket_t *tlock, lck_grp_t *grp); 148 void lck_ticket_lock(lck_ticket_t *tlock, lck_grp_t *grp); 149 void lck_ticket_unlock(lck_ticket_t *tlock); 150 void lck_ticket_assert_owned(lck_ticket_t *tlock); 151 #if MACH_ASSERT 152 #define LCK_TICKET_ASSERT_OWNED(tlock) lck_ticket_assert_owned(tlock) 153 #else 154 #define LCK_TICKET_ASSERT_OWNED(tlock) (void)(tlock) 155 #endif 156 157 #if XNU_KERNEL_PRIVATE 158 int lck_ticket_lock_try(lck_ticket_t *tlock, lck_grp_t *grp) __result_use_check; 159 bool kdp_lck_ticket_is_acquired(lck_ticket_t *lck) __result_use_check; 160 #endif 161 162 __END_DECLS 163 164 #endif /* __ASSEMBLER__ */ 165 166 #define HW_LCK_TICKET_LOCK_INCREMENT 0x01000000 167 #define HW_LCK_TICKET_LOCK_VALID_BIT 8 168 169 #else /* KERNEL_PRIVATE */ 170 #error header not supported 171 #endif /* KERNEL_PRIVATE */ 172 173 #endif /* _KERN_TICKET_LOCK_H_ */ 174