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