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