1*aca3beaaSApple OSS Distributions /*
2*aca3beaaSApple OSS Distributions * Copyright (c) 2000-2021 Apple Inc. All rights reserved.
3*aca3beaaSApple OSS Distributions *
4*aca3beaaSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*aca3beaaSApple OSS Distributions *
6*aca3beaaSApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*aca3beaaSApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*aca3beaaSApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*aca3beaaSApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*aca3beaaSApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*aca3beaaSApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*aca3beaaSApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*aca3beaaSApple OSS Distributions * terms of an Apple operating system software license agreement.
14*aca3beaaSApple OSS Distributions *
15*aca3beaaSApple OSS Distributions * Please obtain a copy of the License at
16*aca3beaaSApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*aca3beaaSApple OSS Distributions *
18*aca3beaaSApple OSS Distributions * The Original Code and all software distributed under the License are
19*aca3beaaSApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*aca3beaaSApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*aca3beaaSApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*aca3beaaSApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*aca3beaaSApple OSS Distributions * Please see the License for the specific language governing rights and
24*aca3beaaSApple OSS Distributions * limitations under the License.
25*aca3beaaSApple OSS Distributions *
26*aca3beaaSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*aca3beaaSApple OSS Distributions */
28*aca3beaaSApple OSS Distributions /*
29*aca3beaaSApple OSS Distributions * @OSF_COPYRIGHT@
30*aca3beaaSApple OSS Distributions */
31*aca3beaaSApple OSS Distributions /*
32*aca3beaaSApple OSS Distributions * Mach Operating System
33*aca3beaaSApple OSS Distributions * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34*aca3beaaSApple OSS Distributions * All Rights Reserved.
35*aca3beaaSApple OSS Distributions *
36*aca3beaaSApple OSS Distributions * Permission to use, copy, modify and distribute this software and its
37*aca3beaaSApple OSS Distributions * documentation is hereby granted, provided that both the copyright
38*aca3beaaSApple OSS Distributions * notice and this permission notice appear in all copies of the
39*aca3beaaSApple OSS Distributions * software, derivative works or modified versions, and any portions
40*aca3beaaSApple OSS Distributions * thereof, and that both notices appear in supporting documentation.
41*aca3beaaSApple OSS Distributions *
42*aca3beaaSApple OSS Distributions * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43*aca3beaaSApple OSS Distributions * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44*aca3beaaSApple OSS Distributions * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45*aca3beaaSApple OSS Distributions *
46*aca3beaaSApple OSS Distributions * Carnegie Mellon requests users of this software to return to
47*aca3beaaSApple OSS Distributions *
48*aca3beaaSApple OSS Distributions * Software Distribution Coordinator or [email protected]
49*aca3beaaSApple OSS Distributions * School of Computer Science
50*aca3beaaSApple OSS Distributions * Carnegie Mellon University
51*aca3beaaSApple OSS Distributions * Pittsburgh PA 15213-3890
52*aca3beaaSApple OSS Distributions *
53*aca3beaaSApple OSS Distributions * any improvements or extensions that they make and grant Carnegie Mellon
54*aca3beaaSApple OSS Distributions * the rights to redistribute these changes.
55*aca3beaaSApple OSS Distributions */
56*aca3beaaSApple OSS Distributions
57*aca3beaaSApple OSS Distributions #define LOCK_PRIVATE 1
58*aca3beaaSApple OSS Distributions
59*aca3beaaSApple OSS Distributions #include <mach_ldebug.h>
60*aca3beaaSApple OSS Distributions #include <debug.h>
61*aca3beaaSApple OSS Distributions
62*aca3beaaSApple OSS Distributions #include <mach/mach_host_server.h>
63*aca3beaaSApple OSS Distributions #include <mach_debug/lockgroup_info.h>
64*aca3beaaSApple OSS Distributions
65*aca3beaaSApple OSS Distributions #if __x86_64__
66*aca3beaaSApple OSS Distributions #include <i386/tsc.h>
67*aca3beaaSApple OSS Distributions #endif
68*aca3beaaSApple OSS Distributions
69*aca3beaaSApple OSS Distributions #include <kern/compact_id.h>
70*aca3beaaSApple OSS Distributions #include <kern/kalloc.h>
71*aca3beaaSApple OSS Distributions #include <kern/lock_stat.h>
72*aca3beaaSApple OSS Distributions #include <kern/locks.h>
73*aca3beaaSApple OSS Distributions
74*aca3beaaSApple OSS Distributions #include <os/atomic_private.h>
75*aca3beaaSApple OSS Distributions
76*aca3beaaSApple OSS Distributions static KALLOC_TYPE_DEFINE(KT_LCK_GRP_ATTR, lck_grp_attr_t, KT_PRIV_ACCT);
77*aca3beaaSApple OSS Distributions static KALLOC_TYPE_DEFINE(KT_LCK_GRP, lck_grp_t, KT_PRIV_ACCT);
78*aca3beaaSApple OSS Distributions static KALLOC_TYPE_DEFINE(KT_LCK_ATTR, lck_attr_t, KT_PRIV_ACCT);
79*aca3beaaSApple OSS Distributions
80*aca3beaaSApple OSS Distributions SECURITY_READ_ONLY_LATE(lck_attr_t) lck_attr_default;
81*aca3beaaSApple OSS Distributions static SECURITY_READ_ONLY_LATE(lck_grp_attr_t) lck_grp_attr_default;
82*aca3beaaSApple OSS Distributions static lck_grp_t lck_grp_compat_grp;
83*aca3beaaSApple OSS Distributions COMPACT_ID_TABLE_DEFINE(static, lck_grp_table);
84*aca3beaaSApple OSS Distributions struct lck_debug_state lck_debug_state;
85*aca3beaaSApple OSS Distributions
86*aca3beaaSApple OSS Distributions #pragma mark lock group attributes
87*aca3beaaSApple OSS Distributions
88*aca3beaaSApple OSS Distributions lck_grp_attr_t *
lck_grp_attr_alloc_init(void)89*aca3beaaSApple OSS Distributions lck_grp_attr_alloc_init(void)
90*aca3beaaSApple OSS Distributions {
91*aca3beaaSApple OSS Distributions lck_grp_attr_t *attr;
92*aca3beaaSApple OSS Distributions
93*aca3beaaSApple OSS Distributions attr = zalloc(KT_LCK_GRP_ATTR);
94*aca3beaaSApple OSS Distributions lck_grp_attr_setdefault(attr);
95*aca3beaaSApple OSS Distributions return attr;
96*aca3beaaSApple OSS Distributions }
97*aca3beaaSApple OSS Distributions
98*aca3beaaSApple OSS Distributions void
lck_grp_attr_setdefault(lck_grp_attr_t * attr)99*aca3beaaSApple OSS Distributions lck_grp_attr_setdefault(lck_grp_attr_t *attr)
100*aca3beaaSApple OSS Distributions {
101*aca3beaaSApple OSS Distributions attr->grp_attr_val = lck_grp_attr_default.grp_attr_val;
102*aca3beaaSApple OSS Distributions }
103*aca3beaaSApple OSS Distributions
104*aca3beaaSApple OSS Distributions void
lck_grp_attr_setstat(lck_grp_attr_t * attr __unused)105*aca3beaaSApple OSS Distributions lck_grp_attr_setstat(lck_grp_attr_t *attr __unused)
106*aca3beaaSApple OSS Distributions {
107*aca3beaaSApple OSS Distributions attr->grp_attr_val |= LCK_GRP_ATTR_STAT;
108*aca3beaaSApple OSS Distributions }
109*aca3beaaSApple OSS Distributions
110*aca3beaaSApple OSS Distributions
111*aca3beaaSApple OSS Distributions void
lck_grp_attr_free(lck_grp_attr_t * attr)112*aca3beaaSApple OSS Distributions lck_grp_attr_free(lck_grp_attr_t *attr)
113*aca3beaaSApple OSS Distributions {
114*aca3beaaSApple OSS Distributions zfree(KT_LCK_GRP_ATTR, attr);
115*aca3beaaSApple OSS Distributions }
116*aca3beaaSApple OSS Distributions
117*aca3beaaSApple OSS Distributions #pragma mark lock groups
118*aca3beaaSApple OSS Distributions
119*aca3beaaSApple OSS Distributions __startup_func
120*aca3beaaSApple OSS Distributions static void
lck_group_init(void)121*aca3beaaSApple OSS Distributions lck_group_init(void)
122*aca3beaaSApple OSS Distributions {
123*aca3beaaSApple OSS Distributions if (LcksOpts & enaLkStat) {
124*aca3beaaSApple OSS Distributions lck_grp_attr_default.grp_attr_val |= LCK_GRP_ATTR_STAT;
125*aca3beaaSApple OSS Distributions }
126*aca3beaaSApple OSS Distributions if (LcksOpts & enaLkTimeStat) {
127*aca3beaaSApple OSS Distributions lck_grp_attr_default.grp_attr_val |= LCK_GRP_ATTR_TIME_STAT;
128*aca3beaaSApple OSS Distributions }
129*aca3beaaSApple OSS Distributions if (LcksOpts & enaLkDeb) {
130*aca3beaaSApple OSS Distributions lck_grp_attr_default.grp_attr_val |= LCK_GRP_ATTR_DEBUG;
131*aca3beaaSApple OSS Distributions }
132*aca3beaaSApple OSS Distributions
133*aca3beaaSApple OSS Distributions if (LcksOpts & enaLkDeb) {
134*aca3beaaSApple OSS Distributions lck_attr_default.lck_attr_val = LCK_ATTR_DEBUG;
135*aca3beaaSApple OSS Distributions } else {
136*aca3beaaSApple OSS Distributions lck_attr_default.lck_attr_val = LCK_ATTR_NONE;
137*aca3beaaSApple OSS Distributions }
138*aca3beaaSApple OSS Distributions
139*aca3beaaSApple OSS Distributions /*
140*aca3beaaSApple OSS Distributions * This is a little gross, this allows us to use the table before
141*aca3beaaSApple OSS Distributions * compact_table_init() is called on it, but we have a chicken
142*aca3beaaSApple OSS Distributions * and egg problem otherwise.
143*aca3beaaSApple OSS Distributions *
144*aca3beaaSApple OSS Distributions * compact_table_init() really only inits the ticket lock
145*aca3beaaSApple OSS Distributions * with the proper lock group
146*aca3beaaSApple OSS Distributions */
147*aca3beaaSApple OSS Distributions lck_grp_init(&lck_grp_compat_grp, "Compatibility APIs",
148*aca3beaaSApple OSS Distributions &lck_grp_attr_default);
149*aca3beaaSApple OSS Distributions *compact_id_resolve(&lck_grp_table, 0) = LCK_GRP_NULL;
150*aca3beaaSApple OSS Distributions }
151*aca3beaaSApple OSS Distributions STARTUP(LOCKS, STARTUP_RANK_FIRST, lck_group_init);
152*aca3beaaSApple OSS Distributions
153*aca3beaaSApple OSS Distributions __startup_func
154*aca3beaaSApple OSS Distributions void
lck_grp_startup_init(struct lck_grp_spec * sp)155*aca3beaaSApple OSS Distributions lck_grp_startup_init(struct lck_grp_spec *sp)
156*aca3beaaSApple OSS Distributions {
157*aca3beaaSApple OSS Distributions lck_grp_init_flags(sp->grp, sp->grp_name, sp->grp_flags |
158*aca3beaaSApple OSS Distributions lck_grp_attr_default.grp_attr_val);
159*aca3beaaSApple OSS Distributions }
160*aca3beaaSApple OSS Distributions
161*aca3beaaSApple OSS Distributions bool
lck_grp_has_stats(lck_grp_t * grp)162*aca3beaaSApple OSS Distributions lck_grp_has_stats(lck_grp_t *grp)
163*aca3beaaSApple OSS Distributions {
164*aca3beaaSApple OSS Distributions return grp->lck_grp_attr_id & LCK_GRP_ATTR_STAT;
165*aca3beaaSApple OSS Distributions }
166*aca3beaaSApple OSS Distributions
167*aca3beaaSApple OSS Distributions lck_grp_t *
lck_grp_alloc_init(const char * grp_name,lck_grp_attr_t * attr)168*aca3beaaSApple OSS Distributions lck_grp_alloc_init(const char *grp_name, lck_grp_attr_t *attr)
169*aca3beaaSApple OSS Distributions {
170*aca3beaaSApple OSS Distributions lck_grp_t *grp;
171*aca3beaaSApple OSS Distributions
172*aca3beaaSApple OSS Distributions if (attr == LCK_GRP_ATTR_NULL) {
173*aca3beaaSApple OSS Distributions attr = &lck_grp_attr_default;
174*aca3beaaSApple OSS Distributions }
175*aca3beaaSApple OSS Distributions grp = zalloc(KT_LCK_GRP);
176*aca3beaaSApple OSS Distributions lck_grp_init_flags(grp, grp_name,
177*aca3beaaSApple OSS Distributions attr->grp_attr_val | LCK_GRP_ATTR_ALLOCATED);
178*aca3beaaSApple OSS Distributions return grp;
179*aca3beaaSApple OSS Distributions }
180*aca3beaaSApple OSS Distributions
181*aca3beaaSApple OSS Distributions void
lck_grp_init(lck_grp_t * grp,const char * grp_name,lck_grp_attr_t * attr)182*aca3beaaSApple OSS Distributions lck_grp_init(lck_grp_t *grp, const char *grp_name, lck_grp_attr_t *attr)
183*aca3beaaSApple OSS Distributions {
184*aca3beaaSApple OSS Distributions if (attr == LCK_GRP_ATTR_NULL) {
185*aca3beaaSApple OSS Distributions attr = &lck_grp_attr_default;
186*aca3beaaSApple OSS Distributions }
187*aca3beaaSApple OSS Distributions lck_grp_init_flags(grp, grp_name, attr->grp_attr_val);
188*aca3beaaSApple OSS Distributions }
189*aca3beaaSApple OSS Distributions
190*aca3beaaSApple OSS Distributions lck_grp_t *
lck_grp_init_flags(lck_grp_t * grp,const char * grp_name,lck_grp_options_t flags)191*aca3beaaSApple OSS Distributions lck_grp_init_flags(lck_grp_t *grp, const char *grp_name, lck_grp_options_t flags)
192*aca3beaaSApple OSS Distributions {
193*aca3beaaSApple OSS Distributions bzero(grp, sizeof(lck_grp_t));
194*aca3beaaSApple OSS Distributions os_ref_init_raw(&grp->lck_grp_refcnt, NULL);
195*aca3beaaSApple OSS Distributions (void)strlcpy(grp->lck_grp_name, grp_name, LCK_GRP_MAX_NAME);
196*aca3beaaSApple OSS Distributions
197*aca3beaaSApple OSS Distributions #if CONFIG_DTRACE
198*aca3beaaSApple OSS Distributions lck_grp_stats_t *stats = &grp->lck_grp_stats;
199*aca3beaaSApple OSS Distributions
200*aca3beaaSApple OSS Distributions if (flags & LCK_GRP_ATTR_STAT) {
201*aca3beaaSApple OSS Distributions lck_grp_stat_enable(&stats->lgss_spin_held);
202*aca3beaaSApple OSS Distributions lck_grp_stat_enable(&stats->lgss_spin_miss);
203*aca3beaaSApple OSS Distributions
204*aca3beaaSApple OSS Distributions lck_grp_stat_enable(&stats->lgss_ticket_held);
205*aca3beaaSApple OSS Distributions lck_grp_stat_enable(&stats->lgss_ticket_miss);
206*aca3beaaSApple OSS Distributions
207*aca3beaaSApple OSS Distributions lck_grp_stat_enable(&stats->lgss_mtx_held);
208*aca3beaaSApple OSS Distributions lck_grp_stat_enable(&stats->lgss_mtx_direct_wait);
209*aca3beaaSApple OSS Distributions lck_grp_stat_enable(&stats->lgss_mtx_miss);
210*aca3beaaSApple OSS Distributions lck_grp_stat_enable(&stats->lgss_mtx_wait);
211*aca3beaaSApple OSS Distributions }
212*aca3beaaSApple OSS Distributions if (flags & LCK_GRP_ATTR_TIME_STAT) {
213*aca3beaaSApple OSS Distributions lck_grp_stat_enable(&stats->lgss_spin_spin);
214*aca3beaaSApple OSS Distributions lck_grp_stat_enable(&stats->lgss_ticket_spin);
215*aca3beaaSApple OSS Distributions }
216*aca3beaaSApple OSS Distributions #endif /* CONFIG_DTRACE */
217*aca3beaaSApple OSS Distributions
218*aca3beaaSApple OSS Distributions /* must be last as it publishes the group */
219*aca3beaaSApple OSS Distributions if (startup_phase > STARTUP_SUB_LOCKS) {
220*aca3beaaSApple OSS Distributions compact_id_table_lock(&lck_grp_table);
221*aca3beaaSApple OSS Distributions }
222*aca3beaaSApple OSS Distributions flags |= compact_id_get_locked(&lck_grp_table, LCK_GRP_ATTR_ID_MASK, grp);
223*aca3beaaSApple OSS Distributions grp->lck_grp_attr_id = flags;
224*aca3beaaSApple OSS Distributions if (startup_phase > STARTUP_SUB_LOCKS) {
225*aca3beaaSApple OSS Distributions compact_id_table_unlock(&lck_grp_table);
226*aca3beaaSApple OSS Distributions }
227*aca3beaaSApple OSS Distributions
228*aca3beaaSApple OSS Distributions return grp;
229*aca3beaaSApple OSS Distributions }
230*aca3beaaSApple OSS Distributions
231*aca3beaaSApple OSS Distributions lck_grp_t *
lck_grp_resolve(uint32_t grp_attr_id)232*aca3beaaSApple OSS Distributions lck_grp_resolve(uint32_t grp_attr_id)
233*aca3beaaSApple OSS Distributions {
234*aca3beaaSApple OSS Distributions grp_attr_id &= LCK_GRP_ATTR_ID_MASK;
235*aca3beaaSApple OSS Distributions return *compact_id_resolve(&lck_grp_table, grp_attr_id);
236*aca3beaaSApple OSS Distributions }
237*aca3beaaSApple OSS Distributions
238*aca3beaaSApple OSS Distributions __abortlike
239*aca3beaaSApple OSS Distributions static void
__lck_grp_assert_id_panic(lck_grp_t * grp,uint32_t grp_attr_id)240*aca3beaaSApple OSS Distributions __lck_grp_assert_id_panic(lck_grp_t *grp, uint32_t grp_attr_id)
241*aca3beaaSApple OSS Distributions {
242*aca3beaaSApple OSS Distributions panic("lck_grp_t %p has ID %d, but %d was expected", grp,
243*aca3beaaSApple OSS Distributions grp->lck_grp_attr_id & LCK_GRP_ATTR_ID_MASK,
244*aca3beaaSApple OSS Distributions grp_attr_id & LCK_GRP_ATTR_ID_MASK);
245*aca3beaaSApple OSS Distributions }
246*aca3beaaSApple OSS Distributions
247*aca3beaaSApple OSS Distributions __attribute__((always_inline))
248*aca3beaaSApple OSS Distributions void
lck_grp_assert_id(lck_grp_t * grp,uint32_t grp_attr_id)249*aca3beaaSApple OSS Distributions lck_grp_assert_id(lck_grp_t *grp, uint32_t grp_attr_id)
250*aca3beaaSApple OSS Distributions {
251*aca3beaaSApple OSS Distributions if ((grp->lck_grp_attr_id ^ grp_attr_id) & LCK_GRP_ATTR_ID_MASK) {
252*aca3beaaSApple OSS Distributions __lck_grp_assert_id_panic(grp, grp_attr_id);
253*aca3beaaSApple OSS Distributions }
254*aca3beaaSApple OSS Distributions }
255*aca3beaaSApple OSS Distributions
256*aca3beaaSApple OSS Distributions static void
lck_grp_destroy(lck_grp_t * grp)257*aca3beaaSApple OSS Distributions lck_grp_destroy(lck_grp_t *grp)
258*aca3beaaSApple OSS Distributions {
259*aca3beaaSApple OSS Distributions compact_id_put(&lck_grp_table,
260*aca3beaaSApple OSS Distributions grp->lck_grp_attr_id & LCK_GRP_ATTR_ID_MASK);
261*aca3beaaSApple OSS Distributions zfree(KT_LCK_GRP, grp);
262*aca3beaaSApple OSS Distributions }
263*aca3beaaSApple OSS Distributions
264*aca3beaaSApple OSS Distributions void
lck_grp_free(lck_grp_t * grp)265*aca3beaaSApple OSS Distributions lck_grp_free(lck_grp_t *grp)
266*aca3beaaSApple OSS Distributions {
267*aca3beaaSApple OSS Distributions lck_grp_deallocate(grp, NULL);
268*aca3beaaSApple OSS Distributions }
269*aca3beaaSApple OSS Distributions
270*aca3beaaSApple OSS Distributions void
lck_grp_reference(lck_grp_t * grp,uint32_t * cnt)271*aca3beaaSApple OSS Distributions lck_grp_reference(lck_grp_t *grp, uint32_t *cnt)
272*aca3beaaSApple OSS Distributions {
273*aca3beaaSApple OSS Distributions if (cnt) {
274*aca3beaaSApple OSS Distributions os_atomic_inc(cnt, relaxed);
275*aca3beaaSApple OSS Distributions }
276*aca3beaaSApple OSS Distributions if (grp->lck_grp_attr_id & LCK_GRP_ATTR_ALLOCATED) {
277*aca3beaaSApple OSS Distributions os_ref_retain_raw(&grp->lck_grp_refcnt, NULL);
278*aca3beaaSApple OSS Distributions }
279*aca3beaaSApple OSS Distributions }
280*aca3beaaSApple OSS Distributions
281*aca3beaaSApple OSS Distributions void
lck_grp_deallocate(lck_grp_t * grp,uint32_t * cnt)282*aca3beaaSApple OSS Distributions lck_grp_deallocate(lck_grp_t *grp, uint32_t *cnt)
283*aca3beaaSApple OSS Distributions {
284*aca3beaaSApple OSS Distributions if (cnt) {
285*aca3beaaSApple OSS Distributions os_atomic_dec(cnt, relaxed);
286*aca3beaaSApple OSS Distributions }
287*aca3beaaSApple OSS Distributions if ((grp->lck_grp_attr_id & LCK_GRP_ATTR_ALLOCATED) &&
288*aca3beaaSApple OSS Distributions os_ref_release_raw(&grp->lck_grp_refcnt, 0) == 0) {
289*aca3beaaSApple OSS Distributions lck_grp_destroy(grp);
290*aca3beaaSApple OSS Distributions }
291*aca3beaaSApple OSS Distributions }
292*aca3beaaSApple OSS Distributions
293*aca3beaaSApple OSS Distributions void
294*aca3beaaSApple OSS Distributions lck_grp_foreach(bool (^block)(lck_grp_t *))
295*aca3beaaSApple OSS Distributions {
296*aca3beaaSApple OSS Distributions compact_id_for_each(&lck_grp_table, 64, (bool (^)(void *))block);
297*aca3beaaSApple OSS Distributions }
298*aca3beaaSApple OSS Distributions
299*aca3beaaSApple OSS Distributions void
lck_grp_enable_feature(lck_debug_feature_t feat)300*aca3beaaSApple OSS Distributions lck_grp_enable_feature(lck_debug_feature_t feat)
301*aca3beaaSApple OSS Distributions {
302*aca3beaaSApple OSS Distributions uint32_t bit = 1u << feat;
303*aca3beaaSApple OSS Distributions
304*aca3beaaSApple OSS Distributions compact_id_table_lock(&lck_grp_table);
305*aca3beaaSApple OSS Distributions if (lck_debug_state.lds_counts[feat]++ == 0) {
306*aca3beaaSApple OSS Distributions os_atomic_or(&lck_debug_state.lds_value, bit, relaxed);
307*aca3beaaSApple OSS Distributions }
308*aca3beaaSApple OSS Distributions compact_id_table_unlock(&lck_grp_table);
309*aca3beaaSApple OSS Distributions }
310*aca3beaaSApple OSS Distributions
311*aca3beaaSApple OSS Distributions void
lck_grp_disable_feature(lck_debug_feature_t feat)312*aca3beaaSApple OSS Distributions lck_grp_disable_feature(lck_debug_feature_t feat)
313*aca3beaaSApple OSS Distributions {
314*aca3beaaSApple OSS Distributions uint32_t bit = 1u << feat;
315*aca3beaaSApple OSS Distributions long v;
316*aca3beaaSApple OSS Distributions
317*aca3beaaSApple OSS Distributions compact_id_table_lock(&lck_grp_table);
318*aca3beaaSApple OSS Distributions v = --lck_debug_state.lds_counts[feat];
319*aca3beaaSApple OSS Distributions if (v < 0) {
320*aca3beaaSApple OSS Distributions panic("lck_debug_state: feature %d imbalance", feat);
321*aca3beaaSApple OSS Distributions }
322*aca3beaaSApple OSS Distributions if (v == 0) {
323*aca3beaaSApple OSS Distributions os_atomic_andnot(&lck_debug_state.lds_value, bit, relaxed);
324*aca3beaaSApple OSS Distributions }
325*aca3beaaSApple OSS Distributions compact_id_table_unlock(&lck_grp_table);
326*aca3beaaSApple OSS Distributions }
327*aca3beaaSApple OSS Distributions
328*aca3beaaSApple OSS Distributions kern_return_t
host_lockgroup_info(host_t host,lockgroup_info_array_t * lockgroup_infop,mach_msg_type_number_t * lockgroup_infoCntp)329*aca3beaaSApple OSS Distributions host_lockgroup_info(
330*aca3beaaSApple OSS Distributions host_t host,
331*aca3beaaSApple OSS Distributions lockgroup_info_array_t *lockgroup_infop,
332*aca3beaaSApple OSS Distributions mach_msg_type_number_t *lockgroup_infoCntp)
333*aca3beaaSApple OSS Distributions {
334*aca3beaaSApple OSS Distributions lockgroup_info_t *info;
335*aca3beaaSApple OSS Distributions vm_offset_t addr;
336*aca3beaaSApple OSS Distributions vm_size_t size, used;
337*aca3beaaSApple OSS Distributions vm_size_t vmsize, vmused;
338*aca3beaaSApple OSS Distributions uint32_t needed;
339*aca3beaaSApple OSS Distributions __block uint32_t count = 0;
340*aca3beaaSApple OSS Distributions vm_map_copy_t copy;
341*aca3beaaSApple OSS Distributions kern_return_t kr;
342*aca3beaaSApple OSS Distributions
343*aca3beaaSApple OSS Distributions if (host == HOST_NULL) {
344*aca3beaaSApple OSS Distributions return KERN_INVALID_HOST;
345*aca3beaaSApple OSS Distributions }
346*aca3beaaSApple OSS Distributions
347*aca3beaaSApple OSS Distributions /*
348*aca3beaaSApple OSS Distributions * Give about 10% of slop here, lock groups are mostly allocated
349*aca3beaaSApple OSS Distributions * during boot or kext loads, and is extremely unlikely to grow
350*aca3beaaSApple OSS Distributions * rapidly.
351*aca3beaaSApple OSS Distributions */
352*aca3beaaSApple OSS Distributions needed = os_atomic_load(&lck_grp_table.cidt_count, relaxed);
353*aca3beaaSApple OSS Distributions needed += needed / 8;
354*aca3beaaSApple OSS Distributions size = needed * sizeof(lockgroup_info_t);
355*aca3beaaSApple OSS Distributions vmsize = vm_map_round_page(size, VM_MAP_PAGE_MASK(ipc_kernel_map));
356*aca3beaaSApple OSS Distributions kr = kmem_alloc(ipc_kernel_map, &addr, vmsize,
357*aca3beaaSApple OSS Distributions KMA_DATA | KMA_ZERO, VM_KERN_MEMORY_IPC);
358*aca3beaaSApple OSS Distributions if (kr != KERN_SUCCESS) {
359*aca3beaaSApple OSS Distributions return kr;
360*aca3beaaSApple OSS Distributions }
361*aca3beaaSApple OSS Distributions
362*aca3beaaSApple OSS Distributions info = (lockgroup_info_t *)addr;
363*aca3beaaSApple OSS Distributions
364*aca3beaaSApple OSS Distributions lck_grp_foreach(^bool (lck_grp_t *grp) {
365*aca3beaaSApple OSS Distributions info[count].lock_spin_cnt = grp->lck_grp_spincnt;
366*aca3beaaSApple OSS Distributions info[count].lock_rw_cnt = grp->lck_grp_rwcnt;
367*aca3beaaSApple OSS Distributions info[count].lock_mtx_cnt = grp->lck_grp_mtxcnt;
368*aca3beaaSApple OSS Distributions
369*aca3beaaSApple OSS Distributions #if CONFIG_DTRACE
370*aca3beaaSApple OSS Distributions info[count].lock_spin_held_cnt = grp->lck_grp_stats.lgss_spin_held.lgs_count;
371*aca3beaaSApple OSS Distributions info[count].lock_spin_miss_cnt = grp->lck_grp_stats.lgss_spin_miss.lgs_count;
372*aca3beaaSApple OSS Distributions
373*aca3beaaSApple OSS Distributions // Historically on x86, held was used for "direct wait" and util for "held"
374*aca3beaaSApple OSS Distributions info[count].lock_mtx_util_cnt = grp->lck_grp_stats.lgss_mtx_held.lgs_count;
375*aca3beaaSApple OSS Distributions info[count].lock_mtx_held_cnt = grp->lck_grp_stats.lgss_mtx_direct_wait.lgs_count;
376*aca3beaaSApple OSS Distributions info[count].lock_mtx_miss_cnt = grp->lck_grp_stats.lgss_mtx_miss.lgs_count;
377*aca3beaaSApple OSS Distributions info[count].lock_mtx_wait_cnt = grp->lck_grp_stats.lgss_mtx_wait.lgs_count;
378*aca3beaaSApple OSS Distributions #endif /* CONFIG_DTRACE */
379*aca3beaaSApple OSS Distributions
380*aca3beaaSApple OSS Distributions memcpy(info[count].lockgroup_name, grp->lck_grp_name, LOCKGROUP_MAX_NAME);
381*aca3beaaSApple OSS Distributions
382*aca3beaaSApple OSS Distributions return ++count >= needed ? false : true;
383*aca3beaaSApple OSS Distributions });
384*aca3beaaSApple OSS Distributions
385*aca3beaaSApple OSS Distributions /*
386*aca3beaaSApple OSS Distributions * We might have found less groups than `needed`
387*aca3beaaSApple OSS Distributions * get rid of the excess now:
388*aca3beaaSApple OSS Distributions * - [0, used) is what we want to return
389*aca3beaaSApple OSS Distributions * - [0, size) is what we allocated
390*aca3beaaSApple OSS Distributions */
391*aca3beaaSApple OSS Distributions used = count * sizeof(lockgroup_info_t);
392*aca3beaaSApple OSS Distributions vmused = vm_map_round_page(used, VM_MAP_PAGE_MASK(ipc_kernel_map));
393*aca3beaaSApple OSS Distributions
394*aca3beaaSApple OSS Distributions if (vmused < vmsize) {
395*aca3beaaSApple OSS Distributions kmem_free(ipc_kernel_map, addr + vmused, vmsize - vmused);
396*aca3beaaSApple OSS Distributions }
397*aca3beaaSApple OSS Distributions
398*aca3beaaSApple OSS Distributions kr = vm_map_unwire(ipc_kernel_map, addr, addr + vmused, FALSE);
399*aca3beaaSApple OSS Distributions assert(kr == KERN_SUCCESS);
400*aca3beaaSApple OSS Distributions
401*aca3beaaSApple OSS Distributions kr = vm_map_copyin(ipc_kernel_map, addr, used, TRUE, ©);
402*aca3beaaSApple OSS Distributions assert(kr == KERN_SUCCESS);
403*aca3beaaSApple OSS Distributions
404*aca3beaaSApple OSS Distributions *lockgroup_infop = (lockgroup_info_t *)copy;
405*aca3beaaSApple OSS Distributions *lockgroup_infoCntp = count;
406*aca3beaaSApple OSS Distributions
407*aca3beaaSApple OSS Distributions return KERN_SUCCESS;
408*aca3beaaSApple OSS Distributions }
409*aca3beaaSApple OSS Distributions
410*aca3beaaSApple OSS Distributions #pragma mark lock attributes
411*aca3beaaSApple OSS Distributions
412*aca3beaaSApple OSS Distributions __startup_func
413*aca3beaaSApple OSS Distributions void
lck_attr_startup_init(struct lck_attr_startup_spec * sp)414*aca3beaaSApple OSS Distributions lck_attr_startup_init(struct lck_attr_startup_spec *sp)
415*aca3beaaSApple OSS Distributions {
416*aca3beaaSApple OSS Distributions lck_attr_t *attr = sp->lck_attr;
417*aca3beaaSApple OSS Distributions lck_attr_setdefault(attr);
418*aca3beaaSApple OSS Distributions attr->lck_attr_val |= sp->lck_attr_set_flags;
419*aca3beaaSApple OSS Distributions attr->lck_attr_val &= ~sp->lck_attr_clear_flags;
420*aca3beaaSApple OSS Distributions }
421*aca3beaaSApple OSS Distributions
422*aca3beaaSApple OSS Distributions lck_attr_t *
lck_attr_alloc_init(void)423*aca3beaaSApple OSS Distributions lck_attr_alloc_init(void)
424*aca3beaaSApple OSS Distributions {
425*aca3beaaSApple OSS Distributions lck_attr_t *attr;
426*aca3beaaSApple OSS Distributions
427*aca3beaaSApple OSS Distributions attr = zalloc(KT_LCK_ATTR);
428*aca3beaaSApple OSS Distributions lck_attr_setdefault(attr);
429*aca3beaaSApple OSS Distributions return attr;
430*aca3beaaSApple OSS Distributions }
431*aca3beaaSApple OSS Distributions
432*aca3beaaSApple OSS Distributions
433*aca3beaaSApple OSS Distributions void
lck_attr_setdefault(lck_attr_t * attr)434*aca3beaaSApple OSS Distributions lck_attr_setdefault(lck_attr_t *attr)
435*aca3beaaSApple OSS Distributions {
436*aca3beaaSApple OSS Distributions attr->lck_attr_val = lck_attr_default.lck_attr_val;
437*aca3beaaSApple OSS Distributions }
438*aca3beaaSApple OSS Distributions
439*aca3beaaSApple OSS Distributions
440*aca3beaaSApple OSS Distributions void
lck_attr_setdebug(lck_attr_t * attr)441*aca3beaaSApple OSS Distributions lck_attr_setdebug(lck_attr_t *attr)
442*aca3beaaSApple OSS Distributions {
443*aca3beaaSApple OSS Distributions os_atomic_or(&attr->lck_attr_val, LCK_ATTR_DEBUG, relaxed);
444*aca3beaaSApple OSS Distributions }
445*aca3beaaSApple OSS Distributions
446*aca3beaaSApple OSS Distributions void
lck_attr_cleardebug(lck_attr_t * attr)447*aca3beaaSApple OSS Distributions lck_attr_cleardebug(lck_attr_t *attr)
448*aca3beaaSApple OSS Distributions {
449*aca3beaaSApple OSS Distributions os_atomic_andnot(&attr->lck_attr_val, LCK_ATTR_DEBUG, relaxed);
450*aca3beaaSApple OSS Distributions }
451*aca3beaaSApple OSS Distributions
452*aca3beaaSApple OSS Distributions void
lck_attr_rw_shared_priority(lck_attr_t * attr)453*aca3beaaSApple OSS Distributions lck_attr_rw_shared_priority(lck_attr_t *attr)
454*aca3beaaSApple OSS Distributions {
455*aca3beaaSApple OSS Distributions os_atomic_or(&attr->lck_attr_val, LCK_ATTR_RW_SHARED_PRIORITY, relaxed);
456*aca3beaaSApple OSS Distributions }
457*aca3beaaSApple OSS Distributions
458*aca3beaaSApple OSS Distributions
459*aca3beaaSApple OSS Distributions void
lck_attr_free(lck_attr_t * attr)460*aca3beaaSApple OSS Distributions lck_attr_free(lck_attr_t *attr)
461*aca3beaaSApple OSS Distributions {
462*aca3beaaSApple OSS Distributions zfree(KT_LCK_ATTR, attr);
463*aca3beaaSApple OSS Distributions }
464*aca3beaaSApple OSS Distributions
465*aca3beaaSApple OSS Distributions #pragma mark lock stat
466*aca3beaaSApple OSS Distributions #if CONFIG_DTRACE
467*aca3beaaSApple OSS Distributions
468*aca3beaaSApple OSS Distributions void
lck_grp_stat_enable(lck_grp_stat_t * stat)469*aca3beaaSApple OSS Distributions lck_grp_stat_enable(lck_grp_stat_t *stat)
470*aca3beaaSApple OSS Distributions {
471*aca3beaaSApple OSS Distributions /* callers ensure this is properly synchronized */
472*aca3beaaSApple OSS Distributions stat->lgs_enablings++;
473*aca3beaaSApple OSS Distributions }
474*aca3beaaSApple OSS Distributions
475*aca3beaaSApple OSS Distributions void
lck_grp_stat_disable(lck_grp_stat_t * stat)476*aca3beaaSApple OSS Distributions lck_grp_stat_disable(lck_grp_stat_t *stat)
477*aca3beaaSApple OSS Distributions {
478*aca3beaaSApple OSS Distributions stat->lgs_enablings--;
479*aca3beaaSApple OSS Distributions }
480*aca3beaaSApple OSS Distributions
481*aca3beaaSApple OSS Distributions bool
lck_grp_stat_enabled(lck_grp_stat_t * stat)482*aca3beaaSApple OSS Distributions lck_grp_stat_enabled(lck_grp_stat_t *stat)
483*aca3beaaSApple OSS Distributions {
484*aca3beaaSApple OSS Distributions return stat->lgs_enablings != 0;
485*aca3beaaSApple OSS Distributions }
486*aca3beaaSApple OSS Distributions
487*aca3beaaSApple OSS Distributions
488*aca3beaaSApple OSS Distributions __attribute__((always_inline))
489*aca3beaaSApple OSS Distributions void
lck_grp_stat_inc(lck_grp_t * grp,lck_grp_stat_t * stat,bool always)490*aca3beaaSApple OSS Distributions lck_grp_stat_inc(lck_grp_t *grp, lck_grp_stat_t *stat, bool always)
491*aca3beaaSApple OSS Distributions {
492*aca3beaaSApple OSS Distributions #pragma unused(grp)
493*aca3beaaSApple OSS Distributions if (always || lck_grp_stat_enabled(stat)) {
494*aca3beaaSApple OSS Distributions __unused uint64_t val = os_atomic_inc_orig(&stat->lgs_count, relaxed);
495*aca3beaaSApple OSS Distributions if (__improbable(stat->lgs_limit && (val % (stat->lgs_limit)) == 0)) {
496*aca3beaaSApple OSS Distributions lockprof_probe(grp, stat, val);
497*aca3beaaSApple OSS Distributions }
498*aca3beaaSApple OSS Distributions }
499*aca3beaaSApple OSS Distributions }
500*aca3beaaSApple OSS Distributions
501*aca3beaaSApple OSS Distributions #if LOCK_STATS
502*aca3beaaSApple OSS Distributions
503*aca3beaaSApple OSS Distributions static inline void
lck_grp_inc_time_stats(lck_grp_t * grp,lck_grp_stat_t * stat,uint64_t time)504*aca3beaaSApple OSS Distributions lck_grp_inc_time_stats(lck_grp_t *grp, lck_grp_stat_t *stat, uint64_t time)
505*aca3beaaSApple OSS Distributions {
506*aca3beaaSApple OSS Distributions if (lck_grp_stat_enabled(stat)) {
507*aca3beaaSApple OSS Distributions __unused uint64_t val = os_atomic_add_orig(&stat->lgs_count, time, relaxed);
508*aca3beaaSApple OSS Distributions if (__improbable(stat->lgs_limit)) {
509*aca3beaaSApple OSS Distributions while (__improbable(time > stat->lgs_limit)) {
510*aca3beaaSApple OSS Distributions time -= stat->lgs_limit;
511*aca3beaaSApple OSS Distributions lockprof_probe(grp, stat, val);
512*aca3beaaSApple OSS Distributions }
513*aca3beaaSApple OSS Distributions if (__improbable(((val % stat->lgs_limit) + time) > stat->lgs_limit)) {
514*aca3beaaSApple OSS Distributions lockprof_probe(grp, stat, val);
515*aca3beaaSApple OSS Distributions }
516*aca3beaaSApple OSS Distributions }
517*aca3beaaSApple OSS Distributions }
518*aca3beaaSApple OSS Distributions }
519*aca3beaaSApple OSS Distributions
520*aca3beaaSApple OSS Distributions void
__lck_grp_spin_update_held(lck_grp_t * grp)521*aca3beaaSApple OSS Distributions __lck_grp_spin_update_held(lck_grp_t *grp)
522*aca3beaaSApple OSS Distributions {
523*aca3beaaSApple OSS Distributions if (grp) {
524*aca3beaaSApple OSS Distributions lck_grp_stat_inc(grp, &grp->lck_grp_stats.lgss_spin_held, false);
525*aca3beaaSApple OSS Distributions }
526*aca3beaaSApple OSS Distributions }
527*aca3beaaSApple OSS Distributions
528*aca3beaaSApple OSS Distributions void
__lck_grp_spin_update_miss(lck_grp_t * grp)529*aca3beaaSApple OSS Distributions __lck_grp_spin_update_miss(lck_grp_t *grp)
530*aca3beaaSApple OSS Distributions {
531*aca3beaaSApple OSS Distributions if (grp) {
532*aca3beaaSApple OSS Distributions lck_grp_stat_inc(grp, &grp->lck_grp_stats.lgss_spin_miss, false);
533*aca3beaaSApple OSS Distributions }
534*aca3beaaSApple OSS Distributions }
535*aca3beaaSApple OSS Distributions
536*aca3beaaSApple OSS Distributions void
__lck_grp_spin_update_spin(lck_grp_t * grp,uint64_t time)537*aca3beaaSApple OSS Distributions __lck_grp_spin_update_spin(lck_grp_t *grp, uint64_t time)
538*aca3beaaSApple OSS Distributions {
539*aca3beaaSApple OSS Distributions if (grp) {
540*aca3beaaSApple OSS Distributions lck_grp_stat_t *stat = &grp->lck_grp_stats.lgss_spin_spin;
541*aca3beaaSApple OSS Distributions lck_grp_inc_time_stats(grp, stat, time);
542*aca3beaaSApple OSS Distributions }
543*aca3beaaSApple OSS Distributions }
544*aca3beaaSApple OSS Distributions
545*aca3beaaSApple OSS Distributions void
__lck_grp_ticket_update_held(lck_grp_t * grp)546*aca3beaaSApple OSS Distributions __lck_grp_ticket_update_held(lck_grp_t *grp)
547*aca3beaaSApple OSS Distributions {
548*aca3beaaSApple OSS Distributions if (grp) {
549*aca3beaaSApple OSS Distributions lck_grp_stat_inc(grp, &grp->lck_grp_stats.lgss_ticket_held, false);
550*aca3beaaSApple OSS Distributions }
551*aca3beaaSApple OSS Distributions }
552*aca3beaaSApple OSS Distributions
553*aca3beaaSApple OSS Distributions void
__lck_grp_ticket_update_miss(lck_grp_t * grp)554*aca3beaaSApple OSS Distributions __lck_grp_ticket_update_miss(lck_grp_t *grp)
555*aca3beaaSApple OSS Distributions {
556*aca3beaaSApple OSS Distributions if (grp) {
557*aca3beaaSApple OSS Distributions lck_grp_stat_inc(grp, &grp->lck_grp_stats.lgss_ticket_miss, false);
558*aca3beaaSApple OSS Distributions }
559*aca3beaaSApple OSS Distributions }
560*aca3beaaSApple OSS Distributions
561*aca3beaaSApple OSS Distributions void
__lck_grp_ticket_update_spin(lck_grp_t * grp,uint64_t time)562*aca3beaaSApple OSS Distributions __lck_grp_ticket_update_spin(lck_grp_t *grp, uint64_t time)
563*aca3beaaSApple OSS Distributions {
564*aca3beaaSApple OSS Distributions if (grp) {
565*aca3beaaSApple OSS Distributions lck_grp_stat_t *stat = &grp->lck_grp_stats.lgss_ticket_spin;
566*aca3beaaSApple OSS Distributions lck_grp_inc_time_stats(grp, stat, time);
567*aca3beaaSApple OSS Distributions }
568*aca3beaaSApple OSS Distributions }
569*aca3beaaSApple OSS Distributions
570*aca3beaaSApple OSS Distributions #endif /* LOCK_STATS */
571*aca3beaaSApple OSS Distributions
572*aca3beaaSApple OSS Distributions void
lck_mtx_time_stat_record(enum lockstat_probe_id pid,lck_mtx_t * mtx,uint32_t grp_attr_id,uint64_t start)573*aca3beaaSApple OSS Distributions lck_mtx_time_stat_record(
574*aca3beaaSApple OSS Distributions enum lockstat_probe_id pid,
575*aca3beaaSApple OSS Distributions lck_mtx_t *mtx,
576*aca3beaaSApple OSS Distributions uint32_t grp_attr_id,
577*aca3beaaSApple OSS Distributions uint64_t start)
578*aca3beaaSApple OSS Distributions {
579*aca3beaaSApple OSS Distributions uint32_t id = lockstat_probemap[pid];
580*aca3beaaSApple OSS Distributions
581*aca3beaaSApple OSS Distributions if (__improbable(start && id)) {
582*aca3beaaSApple OSS Distributions uint64_t delta = ml_get_timebase() - start;
583*aca3beaaSApple OSS Distributions lck_grp_t *grp = lck_grp_resolve(grp_attr_id);
584*aca3beaaSApple OSS Distributions
585*aca3beaaSApple OSS Distributions #if __x86_64__
586*aca3beaaSApple OSS Distributions delta = tmrCvt(delta, tscFCvtt2n);
587*aca3beaaSApple OSS Distributions #endif
588*aca3beaaSApple OSS Distributions dtrace_probe(id, (uintptr_t)mtx, delta, (uintptr_t)grp, 0, 0);
589*aca3beaaSApple OSS Distributions }
590*aca3beaaSApple OSS Distributions }
591*aca3beaaSApple OSS Distributions
592*aca3beaaSApple OSS Distributions #endif /* CONFIG_DTRACE */
593