xref: /aosp_15_r20/external/jemalloc_new/include/jemalloc/internal/witness.h (revision 1208bc7e437ced7eb82efac44ba17e3beba411da)
1*1208bc7eSAndroid Build Coastguard Worker #ifndef JEMALLOC_INTERNAL_WITNESS_H
2*1208bc7eSAndroid Build Coastguard Worker #define JEMALLOC_INTERNAL_WITNESS_H
3*1208bc7eSAndroid Build Coastguard Worker 
4*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/ql.h"
5*1208bc7eSAndroid Build Coastguard Worker 
6*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
7*1208bc7eSAndroid Build Coastguard Worker /* LOCK RANKS */
8*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
9*1208bc7eSAndroid Build Coastguard Worker 
10*1208bc7eSAndroid Build Coastguard Worker /*
11*1208bc7eSAndroid Build Coastguard Worker  * Witnesses with rank WITNESS_RANK_OMIT are completely ignored by the witness
12*1208bc7eSAndroid Build Coastguard Worker  * machinery.
13*1208bc7eSAndroid Build Coastguard Worker  */
14*1208bc7eSAndroid Build Coastguard Worker 
15*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_OMIT		0U
16*1208bc7eSAndroid Build Coastguard Worker 
17*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_MIN		1U
18*1208bc7eSAndroid Build Coastguard Worker 
19*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_INIT		1U
20*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_CTL		1U
21*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_TCACHES		2U
22*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_ARENAS		3U
23*1208bc7eSAndroid Build Coastguard Worker 
24*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_BACKGROUND_THREAD_GLOBAL	4U
25*1208bc7eSAndroid Build Coastguard Worker 
26*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_PROF_DUMP		5U
27*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_PROF_BT2GCTX	6U
28*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_PROF_TDATAS	7U
29*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_PROF_TDATA		8U
30*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_PROF_GCTX		9U
31*1208bc7eSAndroid Build Coastguard Worker 
32*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_BACKGROUND_THREAD	10U
33*1208bc7eSAndroid Build Coastguard Worker 
34*1208bc7eSAndroid Build Coastguard Worker /*
35*1208bc7eSAndroid Build Coastguard Worker  * Used as an argument to witness_assert_depth_to_rank() in order to validate
36*1208bc7eSAndroid Build Coastguard Worker  * depth excluding non-core locks with lower ranks.  Since the rank argument to
37*1208bc7eSAndroid Build Coastguard Worker  * witness_assert_depth_to_rank() is inclusive rather than exclusive, this
38*1208bc7eSAndroid Build Coastguard Worker  * definition can have the same value as the minimally ranked core lock.
39*1208bc7eSAndroid Build Coastguard Worker  */
40*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_CORE		11U
41*1208bc7eSAndroid Build Coastguard Worker 
42*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_DECAY		11U
43*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_TCACHE_QL		12U
44*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_EXTENT_GROW	13U
45*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_EXTENTS		14U
46*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_EXTENT_AVAIL	15U
47*1208bc7eSAndroid Build Coastguard Worker 
48*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_EXTENT_POOL	16U
49*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_RTREE		17U
50*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_BASE		18U
51*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_ARENA_LARGE	19U
52*1208bc7eSAndroid Build Coastguard Worker 
53*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_LEAF		0xffffffffU
54*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_BIN		WITNESS_RANK_LEAF
55*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_ARENA_STATS	WITNESS_RANK_LEAF
56*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_DSS		WITNESS_RANK_LEAF
57*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_PROF_ACTIVE	WITNESS_RANK_LEAF
58*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_PROF_ACCUM		WITNESS_RANK_LEAF
59*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_PROF_DUMP_SEQ	WITNESS_RANK_LEAF
60*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_PROF_GDUMP		WITNESS_RANK_LEAF
61*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_PROF_NEXT_THR_UID	WITNESS_RANK_LEAF
62*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_RANK_PROF_THREAD_ACTIVE_INIT	WITNESS_RANK_LEAF
63*1208bc7eSAndroid Build Coastguard Worker 
64*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
65*1208bc7eSAndroid Build Coastguard Worker /* PER-WITNESS DATA */
66*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
67*1208bc7eSAndroid Build Coastguard Worker #if defined(JEMALLOC_DEBUG)
68*1208bc7eSAndroid Build Coastguard Worker #  define WITNESS_INITIALIZER(name, rank) {name, rank, NULL, NULL, {NULL, NULL}}
69*1208bc7eSAndroid Build Coastguard Worker #else
70*1208bc7eSAndroid Build Coastguard Worker #  define WITNESS_INITIALIZER(name, rank)
71*1208bc7eSAndroid Build Coastguard Worker #endif
72*1208bc7eSAndroid Build Coastguard Worker 
73*1208bc7eSAndroid Build Coastguard Worker typedef struct witness_s witness_t;
74*1208bc7eSAndroid Build Coastguard Worker typedef unsigned witness_rank_t;
75*1208bc7eSAndroid Build Coastguard Worker typedef ql_head(witness_t) witness_list_t;
76*1208bc7eSAndroid Build Coastguard Worker typedef int witness_comp_t (const witness_t *, void *, const witness_t *,
77*1208bc7eSAndroid Build Coastguard Worker     void *);
78*1208bc7eSAndroid Build Coastguard Worker 
79*1208bc7eSAndroid Build Coastguard Worker struct witness_s {
80*1208bc7eSAndroid Build Coastguard Worker 	/* Name, used for printing lock order reversal messages. */
81*1208bc7eSAndroid Build Coastguard Worker 	const char		*name;
82*1208bc7eSAndroid Build Coastguard Worker 
83*1208bc7eSAndroid Build Coastguard Worker 	/*
84*1208bc7eSAndroid Build Coastguard Worker 	 * Witness rank, where 0 is lowest and UINT_MAX is highest.  Witnesses
85*1208bc7eSAndroid Build Coastguard Worker 	 * must be acquired in order of increasing rank.
86*1208bc7eSAndroid Build Coastguard Worker 	 */
87*1208bc7eSAndroid Build Coastguard Worker 	witness_rank_t		rank;
88*1208bc7eSAndroid Build Coastguard Worker 
89*1208bc7eSAndroid Build Coastguard Worker 	/*
90*1208bc7eSAndroid Build Coastguard Worker 	 * If two witnesses are of equal rank and they have the samp comp
91*1208bc7eSAndroid Build Coastguard Worker 	 * function pointer, it is called as a last attempt to differentiate
92*1208bc7eSAndroid Build Coastguard Worker 	 * between witnesses of equal rank.
93*1208bc7eSAndroid Build Coastguard Worker 	 */
94*1208bc7eSAndroid Build Coastguard Worker 	witness_comp_t		*comp;
95*1208bc7eSAndroid Build Coastguard Worker 
96*1208bc7eSAndroid Build Coastguard Worker 	/* Opaque data, passed to comp(). */
97*1208bc7eSAndroid Build Coastguard Worker 	void			*opaque;
98*1208bc7eSAndroid Build Coastguard Worker 
99*1208bc7eSAndroid Build Coastguard Worker 	/* Linkage for thread's currently owned locks. */
100*1208bc7eSAndroid Build Coastguard Worker 	ql_elm(witness_t)	link;
101*1208bc7eSAndroid Build Coastguard Worker };
102*1208bc7eSAndroid Build Coastguard Worker 
103*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
104*1208bc7eSAndroid Build Coastguard Worker /* PER-THREAD DATA */
105*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
106*1208bc7eSAndroid Build Coastguard Worker typedef struct witness_tsd_s witness_tsd_t;
107*1208bc7eSAndroid Build Coastguard Worker struct witness_tsd_s {
108*1208bc7eSAndroid Build Coastguard Worker 	witness_list_t witnesses;
109*1208bc7eSAndroid Build Coastguard Worker 	bool forking;
110*1208bc7eSAndroid Build Coastguard Worker };
111*1208bc7eSAndroid Build Coastguard Worker 
112*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_TSD_INITIALIZER { ql_head_initializer(witnesses), false }
113*1208bc7eSAndroid Build Coastguard Worker #define WITNESS_TSDN_NULL ((witness_tsdn_t *)0)
114*1208bc7eSAndroid Build Coastguard Worker 
115*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
116*1208bc7eSAndroid Build Coastguard Worker /* (PER-THREAD) NULLABILITY HELPERS */
117*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
118*1208bc7eSAndroid Build Coastguard Worker typedef struct witness_tsdn_s witness_tsdn_t;
119*1208bc7eSAndroid Build Coastguard Worker struct witness_tsdn_s {
120*1208bc7eSAndroid Build Coastguard Worker 	witness_tsd_t witness_tsd;
121*1208bc7eSAndroid Build Coastguard Worker };
122*1208bc7eSAndroid Build Coastguard Worker 
123*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE witness_tsdn_t *
witness_tsd_tsdn(witness_tsd_t * witness_tsd)124*1208bc7eSAndroid Build Coastguard Worker witness_tsd_tsdn(witness_tsd_t *witness_tsd) {
125*1208bc7eSAndroid Build Coastguard Worker 	return (witness_tsdn_t *)witness_tsd;
126*1208bc7eSAndroid Build Coastguard Worker }
127*1208bc7eSAndroid Build Coastguard Worker 
128*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE bool
witness_tsdn_null(witness_tsdn_t * witness_tsdn)129*1208bc7eSAndroid Build Coastguard Worker witness_tsdn_null(witness_tsdn_t *witness_tsdn) {
130*1208bc7eSAndroid Build Coastguard Worker 	return witness_tsdn == NULL;
131*1208bc7eSAndroid Build Coastguard Worker }
132*1208bc7eSAndroid Build Coastguard Worker 
133*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE witness_tsd_t *
witness_tsdn_tsd(witness_tsdn_t * witness_tsdn)134*1208bc7eSAndroid Build Coastguard Worker witness_tsdn_tsd(witness_tsdn_t *witness_tsdn) {
135*1208bc7eSAndroid Build Coastguard Worker 	assert(!witness_tsdn_null(witness_tsdn));
136*1208bc7eSAndroid Build Coastguard Worker 	return &witness_tsdn->witness_tsd;
137*1208bc7eSAndroid Build Coastguard Worker }
138*1208bc7eSAndroid Build Coastguard Worker 
139*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
140*1208bc7eSAndroid Build Coastguard Worker /* API */
141*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
142*1208bc7eSAndroid Build Coastguard Worker void witness_init(witness_t *witness, const char *name, witness_rank_t rank,
143*1208bc7eSAndroid Build Coastguard Worker     witness_comp_t *comp, void *opaque);
144*1208bc7eSAndroid Build Coastguard Worker 
145*1208bc7eSAndroid Build Coastguard Worker typedef void (witness_lock_error_t)(const witness_list_t *, const witness_t *);
146*1208bc7eSAndroid Build Coastguard Worker extern witness_lock_error_t *JET_MUTABLE witness_lock_error;
147*1208bc7eSAndroid Build Coastguard Worker 
148*1208bc7eSAndroid Build Coastguard Worker typedef void (witness_owner_error_t)(const witness_t *);
149*1208bc7eSAndroid Build Coastguard Worker extern witness_owner_error_t *JET_MUTABLE witness_owner_error;
150*1208bc7eSAndroid Build Coastguard Worker 
151*1208bc7eSAndroid Build Coastguard Worker typedef void (witness_not_owner_error_t)(const witness_t *);
152*1208bc7eSAndroid Build Coastguard Worker extern witness_not_owner_error_t *JET_MUTABLE witness_not_owner_error;
153*1208bc7eSAndroid Build Coastguard Worker 
154*1208bc7eSAndroid Build Coastguard Worker typedef void (witness_depth_error_t)(const witness_list_t *,
155*1208bc7eSAndroid Build Coastguard Worker     witness_rank_t rank_inclusive, unsigned depth);
156*1208bc7eSAndroid Build Coastguard Worker extern witness_depth_error_t *JET_MUTABLE witness_depth_error;
157*1208bc7eSAndroid Build Coastguard Worker 
158*1208bc7eSAndroid Build Coastguard Worker void witnesses_cleanup(witness_tsd_t *witness_tsd);
159*1208bc7eSAndroid Build Coastguard Worker void witness_prefork(witness_tsd_t *witness_tsd);
160*1208bc7eSAndroid Build Coastguard Worker void witness_postfork_parent(witness_tsd_t *witness_tsd);
161*1208bc7eSAndroid Build Coastguard Worker void witness_postfork_child(witness_tsd_t *witness_tsd);
162*1208bc7eSAndroid Build Coastguard Worker 
163*1208bc7eSAndroid Build Coastguard Worker /* Helper, not intended for direct use. */
164*1208bc7eSAndroid Build Coastguard Worker static inline bool
witness_owner(witness_tsd_t * witness_tsd,const witness_t * witness)165*1208bc7eSAndroid Build Coastguard Worker witness_owner(witness_tsd_t *witness_tsd, const witness_t *witness) {
166*1208bc7eSAndroid Build Coastguard Worker 	witness_list_t *witnesses;
167*1208bc7eSAndroid Build Coastguard Worker 	witness_t *w;
168*1208bc7eSAndroid Build Coastguard Worker 
169*1208bc7eSAndroid Build Coastguard Worker 	cassert(config_debug);
170*1208bc7eSAndroid Build Coastguard Worker 
171*1208bc7eSAndroid Build Coastguard Worker 	witnesses = &witness_tsd->witnesses;
172*1208bc7eSAndroid Build Coastguard Worker 	ql_foreach(w, witnesses, link) {
173*1208bc7eSAndroid Build Coastguard Worker 		if (w == witness) {
174*1208bc7eSAndroid Build Coastguard Worker 			return true;
175*1208bc7eSAndroid Build Coastguard Worker 		}
176*1208bc7eSAndroid Build Coastguard Worker 	}
177*1208bc7eSAndroid Build Coastguard Worker 
178*1208bc7eSAndroid Build Coastguard Worker 	return false;
179*1208bc7eSAndroid Build Coastguard Worker }
180*1208bc7eSAndroid Build Coastguard Worker 
181*1208bc7eSAndroid Build Coastguard Worker static inline void
witness_assert_owner(witness_tsdn_t * witness_tsdn,const witness_t * witness)182*1208bc7eSAndroid Build Coastguard Worker witness_assert_owner(witness_tsdn_t *witness_tsdn, const witness_t *witness) {
183*1208bc7eSAndroid Build Coastguard Worker 	witness_tsd_t *witness_tsd;
184*1208bc7eSAndroid Build Coastguard Worker 
185*1208bc7eSAndroid Build Coastguard Worker 	if (!config_debug) {
186*1208bc7eSAndroid Build Coastguard Worker 		return;
187*1208bc7eSAndroid Build Coastguard Worker 	}
188*1208bc7eSAndroid Build Coastguard Worker 
189*1208bc7eSAndroid Build Coastguard Worker 	if (witness_tsdn_null(witness_tsdn)) {
190*1208bc7eSAndroid Build Coastguard Worker 		return;
191*1208bc7eSAndroid Build Coastguard Worker 	}
192*1208bc7eSAndroid Build Coastguard Worker 	witness_tsd = witness_tsdn_tsd(witness_tsdn);
193*1208bc7eSAndroid Build Coastguard Worker 	if (witness->rank == WITNESS_RANK_OMIT) {
194*1208bc7eSAndroid Build Coastguard Worker 		return;
195*1208bc7eSAndroid Build Coastguard Worker 	}
196*1208bc7eSAndroid Build Coastguard Worker 
197*1208bc7eSAndroid Build Coastguard Worker 	if (witness_owner(witness_tsd, witness)) {
198*1208bc7eSAndroid Build Coastguard Worker 		return;
199*1208bc7eSAndroid Build Coastguard Worker 	}
200*1208bc7eSAndroid Build Coastguard Worker 	witness_owner_error(witness);
201*1208bc7eSAndroid Build Coastguard Worker }
202*1208bc7eSAndroid Build Coastguard Worker 
203*1208bc7eSAndroid Build Coastguard Worker static inline void
witness_assert_not_owner(witness_tsdn_t * witness_tsdn,const witness_t * witness)204*1208bc7eSAndroid Build Coastguard Worker witness_assert_not_owner(witness_tsdn_t *witness_tsdn,
205*1208bc7eSAndroid Build Coastguard Worker     const witness_t *witness) {
206*1208bc7eSAndroid Build Coastguard Worker 	witness_tsd_t *witness_tsd;
207*1208bc7eSAndroid Build Coastguard Worker 	witness_list_t *witnesses;
208*1208bc7eSAndroid Build Coastguard Worker 	witness_t *w;
209*1208bc7eSAndroid Build Coastguard Worker 
210*1208bc7eSAndroid Build Coastguard Worker 	if (!config_debug) {
211*1208bc7eSAndroid Build Coastguard Worker 		return;
212*1208bc7eSAndroid Build Coastguard Worker 	}
213*1208bc7eSAndroid Build Coastguard Worker 
214*1208bc7eSAndroid Build Coastguard Worker 	if (witness_tsdn_null(witness_tsdn)) {
215*1208bc7eSAndroid Build Coastguard Worker 		return;
216*1208bc7eSAndroid Build Coastguard Worker 	}
217*1208bc7eSAndroid Build Coastguard Worker 	witness_tsd = witness_tsdn_tsd(witness_tsdn);
218*1208bc7eSAndroid Build Coastguard Worker 	if (witness->rank == WITNESS_RANK_OMIT) {
219*1208bc7eSAndroid Build Coastguard Worker 		return;
220*1208bc7eSAndroid Build Coastguard Worker 	}
221*1208bc7eSAndroid Build Coastguard Worker 
222*1208bc7eSAndroid Build Coastguard Worker 	witnesses = &witness_tsd->witnesses;
223*1208bc7eSAndroid Build Coastguard Worker 	ql_foreach(w, witnesses, link) {
224*1208bc7eSAndroid Build Coastguard Worker 		if (w == witness) {
225*1208bc7eSAndroid Build Coastguard Worker 			witness_not_owner_error(witness);
226*1208bc7eSAndroid Build Coastguard Worker 		}
227*1208bc7eSAndroid Build Coastguard Worker 	}
228*1208bc7eSAndroid Build Coastguard Worker }
229*1208bc7eSAndroid Build Coastguard Worker 
230*1208bc7eSAndroid Build Coastguard Worker static inline void
witness_assert_depth_to_rank(witness_tsdn_t * witness_tsdn,witness_rank_t rank_inclusive,unsigned depth)231*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(witness_tsdn_t *witness_tsdn,
232*1208bc7eSAndroid Build Coastguard Worker     witness_rank_t rank_inclusive, unsigned depth) {
233*1208bc7eSAndroid Build Coastguard Worker 	witness_tsd_t *witness_tsd;
234*1208bc7eSAndroid Build Coastguard Worker 	unsigned d;
235*1208bc7eSAndroid Build Coastguard Worker 	witness_list_t *witnesses;
236*1208bc7eSAndroid Build Coastguard Worker 	witness_t *w;
237*1208bc7eSAndroid Build Coastguard Worker 
238*1208bc7eSAndroid Build Coastguard Worker 	if (!config_debug) {
239*1208bc7eSAndroid Build Coastguard Worker 		return;
240*1208bc7eSAndroid Build Coastguard Worker 	}
241*1208bc7eSAndroid Build Coastguard Worker 
242*1208bc7eSAndroid Build Coastguard Worker 	if (witness_tsdn_null(witness_tsdn)) {
243*1208bc7eSAndroid Build Coastguard Worker 		return;
244*1208bc7eSAndroid Build Coastguard Worker 	}
245*1208bc7eSAndroid Build Coastguard Worker 	witness_tsd = witness_tsdn_tsd(witness_tsdn);
246*1208bc7eSAndroid Build Coastguard Worker 
247*1208bc7eSAndroid Build Coastguard Worker 	d = 0;
248*1208bc7eSAndroid Build Coastguard Worker 	witnesses = &witness_tsd->witnesses;
249*1208bc7eSAndroid Build Coastguard Worker 	w = ql_last(witnesses, link);
250*1208bc7eSAndroid Build Coastguard Worker 	if (w != NULL) {
251*1208bc7eSAndroid Build Coastguard Worker 		ql_reverse_foreach(w, witnesses, link) {
252*1208bc7eSAndroid Build Coastguard Worker 			if (w->rank < rank_inclusive) {
253*1208bc7eSAndroid Build Coastguard Worker 				break;
254*1208bc7eSAndroid Build Coastguard Worker 			}
255*1208bc7eSAndroid Build Coastguard Worker 			d++;
256*1208bc7eSAndroid Build Coastguard Worker 		}
257*1208bc7eSAndroid Build Coastguard Worker 	}
258*1208bc7eSAndroid Build Coastguard Worker 	if (d != depth) {
259*1208bc7eSAndroid Build Coastguard Worker 		witness_depth_error(witnesses, rank_inclusive, depth);
260*1208bc7eSAndroid Build Coastguard Worker 	}
261*1208bc7eSAndroid Build Coastguard Worker }
262*1208bc7eSAndroid Build Coastguard Worker 
263*1208bc7eSAndroid Build Coastguard Worker static inline void
witness_assert_depth(witness_tsdn_t * witness_tsdn,unsigned depth)264*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth(witness_tsdn_t *witness_tsdn, unsigned depth) {
265*1208bc7eSAndroid Build Coastguard Worker 	witness_assert_depth_to_rank(witness_tsdn, WITNESS_RANK_MIN, depth);
266*1208bc7eSAndroid Build Coastguard Worker }
267*1208bc7eSAndroid Build Coastguard Worker 
268*1208bc7eSAndroid Build Coastguard Worker static inline void
witness_assert_lockless(witness_tsdn_t * witness_tsdn)269*1208bc7eSAndroid Build Coastguard Worker witness_assert_lockless(witness_tsdn_t *witness_tsdn) {
270*1208bc7eSAndroid Build Coastguard Worker 	witness_assert_depth(witness_tsdn, 0);
271*1208bc7eSAndroid Build Coastguard Worker }
272*1208bc7eSAndroid Build Coastguard Worker 
273*1208bc7eSAndroid Build Coastguard Worker static inline void
witness_lock(witness_tsdn_t * witness_tsdn,witness_t * witness)274*1208bc7eSAndroid Build Coastguard Worker witness_lock(witness_tsdn_t *witness_tsdn, witness_t *witness) {
275*1208bc7eSAndroid Build Coastguard Worker 	witness_tsd_t *witness_tsd;
276*1208bc7eSAndroid Build Coastguard Worker 	witness_list_t *witnesses;
277*1208bc7eSAndroid Build Coastguard Worker 	witness_t *w;
278*1208bc7eSAndroid Build Coastguard Worker 
279*1208bc7eSAndroid Build Coastguard Worker 	if (!config_debug) {
280*1208bc7eSAndroid Build Coastguard Worker 		return;
281*1208bc7eSAndroid Build Coastguard Worker 	}
282*1208bc7eSAndroid Build Coastguard Worker 
283*1208bc7eSAndroid Build Coastguard Worker 	if (witness_tsdn_null(witness_tsdn)) {
284*1208bc7eSAndroid Build Coastguard Worker 		return;
285*1208bc7eSAndroid Build Coastguard Worker 	}
286*1208bc7eSAndroid Build Coastguard Worker 	witness_tsd = witness_tsdn_tsd(witness_tsdn);
287*1208bc7eSAndroid Build Coastguard Worker 	if (witness->rank == WITNESS_RANK_OMIT) {
288*1208bc7eSAndroid Build Coastguard Worker 		return;
289*1208bc7eSAndroid Build Coastguard Worker 	}
290*1208bc7eSAndroid Build Coastguard Worker 
291*1208bc7eSAndroid Build Coastguard Worker 	witness_assert_not_owner(witness_tsdn, witness);
292*1208bc7eSAndroid Build Coastguard Worker 
293*1208bc7eSAndroid Build Coastguard Worker 	witnesses = &witness_tsd->witnesses;
294*1208bc7eSAndroid Build Coastguard Worker 	w = ql_last(witnesses, link);
295*1208bc7eSAndroid Build Coastguard Worker 	if (w == NULL) {
296*1208bc7eSAndroid Build Coastguard Worker 		/* No other locks; do nothing. */
297*1208bc7eSAndroid Build Coastguard Worker 	} else if (witness_tsd->forking && w->rank <= witness->rank) {
298*1208bc7eSAndroid Build Coastguard Worker 		/* Forking, and relaxed ranking satisfied. */
299*1208bc7eSAndroid Build Coastguard Worker 	} else if (w->rank > witness->rank) {
300*1208bc7eSAndroid Build Coastguard Worker 		/* Not forking, rank order reversal. */
301*1208bc7eSAndroid Build Coastguard Worker 		witness_lock_error(witnesses, witness);
302*1208bc7eSAndroid Build Coastguard Worker 	} else if (w->rank == witness->rank && (w->comp == NULL || w->comp !=
303*1208bc7eSAndroid Build Coastguard Worker 	    witness->comp || w->comp(w, w->opaque, witness, witness->opaque) >
304*1208bc7eSAndroid Build Coastguard Worker 	    0)) {
305*1208bc7eSAndroid Build Coastguard Worker 		/*
306*1208bc7eSAndroid Build Coastguard Worker 		 * Missing/incompatible comparison function, or comparison
307*1208bc7eSAndroid Build Coastguard Worker 		 * function indicates rank order reversal.
308*1208bc7eSAndroid Build Coastguard Worker 		 */
309*1208bc7eSAndroid Build Coastguard Worker 		witness_lock_error(witnesses, witness);
310*1208bc7eSAndroid Build Coastguard Worker 	}
311*1208bc7eSAndroid Build Coastguard Worker 
312*1208bc7eSAndroid Build Coastguard Worker 	ql_elm_new(witness, link);
313*1208bc7eSAndroid Build Coastguard Worker 	ql_tail_insert(witnesses, witness, link);
314*1208bc7eSAndroid Build Coastguard Worker }
315*1208bc7eSAndroid Build Coastguard Worker 
316*1208bc7eSAndroid Build Coastguard Worker static inline void
witness_unlock(witness_tsdn_t * witness_tsdn,witness_t * witness)317*1208bc7eSAndroid Build Coastguard Worker witness_unlock(witness_tsdn_t *witness_tsdn, witness_t *witness) {
318*1208bc7eSAndroid Build Coastguard Worker 	witness_tsd_t *witness_tsd;
319*1208bc7eSAndroid Build Coastguard Worker 	witness_list_t *witnesses;
320*1208bc7eSAndroid Build Coastguard Worker 
321*1208bc7eSAndroid Build Coastguard Worker 	if (!config_debug) {
322*1208bc7eSAndroid Build Coastguard Worker 		return;
323*1208bc7eSAndroid Build Coastguard Worker 	}
324*1208bc7eSAndroid Build Coastguard Worker 
325*1208bc7eSAndroid Build Coastguard Worker 	if (witness_tsdn_null(witness_tsdn)) {
326*1208bc7eSAndroid Build Coastguard Worker 		return;
327*1208bc7eSAndroid Build Coastguard Worker 	}
328*1208bc7eSAndroid Build Coastguard Worker 	witness_tsd = witness_tsdn_tsd(witness_tsdn);
329*1208bc7eSAndroid Build Coastguard Worker 	if (witness->rank == WITNESS_RANK_OMIT) {
330*1208bc7eSAndroid Build Coastguard Worker 		return;
331*1208bc7eSAndroid Build Coastguard Worker 	}
332*1208bc7eSAndroid Build Coastguard Worker 
333*1208bc7eSAndroid Build Coastguard Worker 	/*
334*1208bc7eSAndroid Build Coastguard Worker 	 * Check whether owner before removal, rather than relying on
335*1208bc7eSAndroid Build Coastguard Worker 	 * witness_assert_owner() to abort, so that unit tests can test this
336*1208bc7eSAndroid Build Coastguard Worker 	 * function's failure mode without causing undefined behavior.
337*1208bc7eSAndroid Build Coastguard Worker 	 */
338*1208bc7eSAndroid Build Coastguard Worker 	if (witness_owner(witness_tsd, witness)) {
339*1208bc7eSAndroid Build Coastguard Worker 		witnesses = &witness_tsd->witnesses;
340*1208bc7eSAndroid Build Coastguard Worker 		ql_remove(witnesses, witness, link);
341*1208bc7eSAndroid Build Coastguard Worker 	} else {
342*1208bc7eSAndroid Build Coastguard Worker 		witness_assert_owner(witness_tsdn, witness);
343*1208bc7eSAndroid Build Coastguard Worker 	}
344*1208bc7eSAndroid Build Coastguard Worker }
345*1208bc7eSAndroid Build Coastguard Worker 
346*1208bc7eSAndroid Build Coastguard Worker #endif /* JEMALLOC_INTERNAL_WITNESS_H */
347