xref: /xnu-8792.61.2/osfmk/kern/lock_group.h (revision 42e220869062b56f8d7d0726fd4c88954f87902c)
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 #pragma GCC visibility pop
252 #endif /* XNU_KERNEL_PRIVATE */
253 
254 __END_DECLS
255 
256 #endif /* _KERN_LOCK_GROUP_H */
257