xref: /xnu-8019.80.24/osfmk/kern/ticket_lock.h (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
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