1 | /* |
2 | * Copyright (c) 2018-2021 Apple Computer, 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 | #ifndef _KERN_LOCK_GROUP_H |
29 | #define _KERN_LOCK_GROUP_H |
30 | |
31 | #include <kern/queue.h> |
32 | #include <kern/lock_types.h> |
33 | #if XNU_KERNEL_PRIVATE |
34 | #include <kern/startup.h> |
35 | #include <os/refcnt.h> |
36 | #endif /* XNU_KERNEL_PRIVATE */ |
37 | |
38 | __BEGIN_DECLS |
39 | |
40 | /*! |
41 | * @typedef lck_grp_t |
42 | * |
43 | * @abstract |
44 | * The opaque type of a lock group. |
45 | * |
46 | * @discussion |
47 | * A lock group is used to denote a set of locks that serve |
48 | * a similar purpose, and hold an equivalent "rank" in the lock hierarchy. |
49 | * |
50 | * This structure can then provide some statistics and anchor checks |
51 | * in development kernels for an entire family of locks. |
52 | */ |
53 | typedef struct _lck_grp_ lck_grp_t; |
54 | #define LCK_GRP_NULL ((lck_grp_t *)NULL) |
55 | |
56 | /*! |
57 | * @typedef lck_grp_attr_t |
58 | * |
59 | * @abstract |
60 | * The opaque type for attributes to a group. |
61 | * |
62 | * @discussion |
63 | * A lock group attribute is meant to configure |
64 | * a group, as a group configuration becomes |
65 | * immutable once made. |
66 | */ |
67 | typedef struct _lck_grp_attr_ lck_grp_attr_t; |
68 | #define LCK_GRP_ATTR_NULL ((lck_grp_attr_t *)NULL) |
69 | |
70 | extern lck_grp_attr_t *lck_grp_attr_alloc_init( |
71 | void); |
72 | |
73 | extern void lck_grp_attr_setdefault( |
74 | lck_grp_attr_t *attr); |
75 | |
76 | extern void lck_grp_attr_setstat( |
77 | lck_grp_attr_t *attr); |
78 | |
79 | extern void lck_grp_attr_free( |
80 | lck_grp_attr_t *attr); |
81 | |
82 | extern lck_grp_t *lck_grp_alloc_init( |
83 | const char *grp_name, |
84 | lck_grp_attr_t *attr); |
85 | |
86 | extern void lck_grp_free( |
87 | lck_grp_t *grp); |
88 | |
89 | #if XNU_KERNEL_PRIVATE |
90 | #pragma GCC visibility push(hidden) |
91 | |
92 | /* |
93 | * Arguments wrapped in LCK_GRP_ARG() will be elided |
94 | * when LOCK_STATS is not set. |
95 | * |
96 | * Arguments wrapped with LCK_GRP_PROBEARG() will be |
97 | * NULL when LOCK_STATS is not set |
98 | */ |
99 | #if LOCK_STATS |
100 | #if !CONFIG_DTRACE |
101 | #error invalid configuration: LOCK_STATS needs dtrace |
102 | #endif |
103 | #define LCK_GRP_ARG(expr) , expr |
104 | #define LCK_GRP_PROBEARG(grp) grp |
105 | #define LCK_GRP_USE_ARG 1 |
106 | #else |
107 | #define LCK_GRP_ARG(expr) |
108 | #define LCK_GRP_PROBEARG(grp) LCK_GRP_NULL |
109 | #define LCK_GRP_USE_ARG 0 |
110 | #endif /* LOCK_STATS */ |
111 | |
112 | __enum_decl(lck_debug_feature_t, uint32_t, { |
113 | LCK_DEBUG_LOCKSTAT, |
114 | LCK_DEBUG_LOCKPROF, |
115 | |
116 | LCK_DEBUG_MAX, |
117 | }); |
118 | |
119 | extern uint32_t LcksOpts; |
120 | |
121 | extern struct lck_debug_state { |
122 | uint32_t lds_value; |
123 | long lds_counts[LCK_DEBUG_MAX]; |
124 | } lck_debug_state; |
125 | |
126 | __options_decl(lck_grp_options_t, uint32_t, { |
127 | LCK_GRP_ATTR_NONE = 0x00000000, |
128 | |
129 | #if MACH_KERNEL_PRIVATE |
130 | LCK_GRP_ATTR_ID_MASK = 0x0000ffff, |
131 | LCK_GRP_ATTR_STAT = 0x00010000, /* enable non time stats */ |
132 | LCK_GRP_ATTR_TIME_STAT = 0x00020000, /* enable time stats */ |
133 | LCK_GRP_ATTR_DEBUG = 0x00040000, /* profile locks of this group */ |
134 | LCK_GRP_ATTR_ALLOCATED = 0x80000000, |
135 | #endif |
136 | }); |
137 | |
138 | #if CONFIG_DTRACE |
139 | typedef struct _lck_grp_stat_ { |
140 | uint64_t lgs_count; |
141 | uint32_t lgs_enablings; |
142 | /* |
143 | * Protected by dtrace_lock |
144 | */ |
145 | uint32_t lgs_probeid; |
146 | uint64_t lgs_limit; |
147 | } lck_grp_stat_t; |
148 | |
149 | typedef struct _lck_grp_stats_ { |
150 | lck_grp_stat_t lgss_spin_held; |
151 | lck_grp_stat_t lgss_spin_miss; |
152 | lck_grp_stat_t lgss_spin_spin; |
153 | |
154 | lck_grp_stat_t lgss_ticket_held; |
155 | lck_grp_stat_t lgss_ticket_miss; |
156 | lck_grp_stat_t lgss_ticket_spin; |
157 | |
158 | lck_grp_stat_t lgss_mtx_held; |
159 | lck_grp_stat_t lgss_mtx_direct_wait; |
160 | lck_grp_stat_t lgss_mtx_miss; |
161 | lck_grp_stat_t lgss_mtx_wait; |
162 | } lck_grp_stats_t; |
163 | #endif /* CONFIG_DTRACE */ |
164 | |
165 | #define LCK_GRP_MAX_NAME 64 |
166 | |
167 | struct _lck_grp_ { |
168 | os_ref_atomic_t lck_grp_refcnt; |
169 | uint32_t lck_grp_attr_id; |
170 | uint32_t lck_grp_spincnt; |
171 | uint32_t lck_grp_ticketcnt; |
172 | uint32_t lck_grp_mtxcnt; |
173 | uint32_t lck_grp_rwcnt; |
174 | char lck_grp_name[LCK_GRP_MAX_NAME]; |
175 | #if CONFIG_DTRACE |
176 | lck_grp_stats_t lck_grp_stats; |
177 | #endif /* CONFIG_DTRACE */ |
178 | }; |
179 | |
180 | struct _lck_grp_attr_ { |
181 | lck_grp_options_t grp_attr_val; |
182 | }; |
183 | |
184 | struct lck_grp_spec { |
185 | lck_grp_t *grp; |
186 | char grp_name[LCK_GRP_MAX_NAME]; |
187 | lck_grp_options_t grp_flags; |
188 | }; |
189 | |
190 | /* |
191 | * Auto-initializing lock group declarations |
192 | * ----------------------------------------- |
193 | * |
194 | * Use LCK_GRP_DECLARE to declare an automatically initialized group. |
195 | */ |
196 | #define LCK_GRP_DECLARE_ATTR(var, name, flags) \ |
197 | __PLACE_IN_SECTION("__DATA,__lock_grp") lck_grp_t var; \ |
198 | static __startup_data struct lck_grp_spec \ |
199 | __startup_lck_grp_spec_ ## var = { &var, name, flags }; \ |
200 | STARTUP_ARG(LOCKS, STARTUP_RANK_SECOND, lck_grp_startup_init, \ |
201 | &__startup_lck_grp_spec_ ## var) |
202 | |
203 | #define LCK_GRP_DECLARE(var, name) \ |
204 | LCK_GRP_DECLARE_ATTR(var, name, LCK_GRP_ATTR_NONE); |
205 | |
206 | extern bool lck_grp_has_stats( |
207 | lck_grp_t *grp); |
208 | |
209 | extern void lck_grp_startup_init( |
210 | struct lck_grp_spec *spec); |
211 | |
212 | extern void lck_grp_init( |
213 | lck_grp_t *grp, |
214 | const char* grp_name, |
215 | lck_grp_attr_t *attr); |
216 | |
217 | extern lck_grp_t *lck_grp_init_flags( |
218 | lck_grp_t *grp, |
219 | const char* grp_name, |
220 | lck_grp_options_t grp_flags); |
221 | |
222 | extern lck_grp_t *lck_grp_resolve( |
223 | uint32_t grp_attr_id) __pure2; |
224 | |
225 | extern void lck_grp_assert_id( |
226 | lck_grp_t *grp, |
227 | uint32_t grp_attr_id); |
228 | #if DEBUG || DEVELOPMENT |
229 | #define LCK_GRP_ASSERT_ID(...) lck_grp_assert_id(__VA_ARGS__) |
230 | #else |
231 | #define LCK_GRP_ASSERT_ID(...) ((void)0) |
232 | #endif |
233 | |
234 | extern void lck_grp_reference( |
235 | lck_grp_t *grp, |
236 | uint32_t *cnt); |
237 | |
238 | extern void lck_grp_deallocate( |
239 | lck_grp_t *grp, |
240 | uint32_t *cnt); |
241 | |
242 | extern void lck_grp_foreach( |
243 | bool (^block)(lck_grp_t *)); |
244 | |
245 | |
246 | extern void lck_grp_enable_feature( |
247 | lck_debug_feature_t feat); |
248 | |
249 | extern void lck_grp_disable_feature( |
250 | lck_debug_feature_t feat); |
251 | |
252 | __pure2 |
253 | static inline uint32_t |
254 | lck_opts_get(void) |
255 | { |
256 | return LcksOpts; |
257 | } |
258 | |
259 | #pragma GCC visibility pop |
260 | |
261 | |
262 | #endif /* XNU_KERNEL_PRIVATE */ |
263 | |
264 | __END_DECLS |
265 | |
266 | #endif /* _KERN_LOCK_GROUP_H */ |
267 | |