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