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