xref: /xnu-12377.61.12/osfmk/kern/lock_group.h (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
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