Home | History | Annotate | Download | only in internal
      1 /******************************************************************************/
      2 #ifdef JEMALLOC_H_TYPES
      3 
      4 typedef struct witness_s witness_t;
      5 typedef unsigned witness_rank_t;
      6 typedef ql_head(witness_t) witness_list_t;
      7 typedef int witness_comp_t (const witness_t *, const witness_t *);
      8 
      9 /*
     10  * Lock ranks.  Witnesses with rank WITNESS_RANK_OMIT are completely ignored by
     11  * the witness machinery.
     12  */
     13 #define	WITNESS_RANK_OMIT		0U
     14 
     15 #define	WITNESS_RANK_INIT		1U
     16 #define	WITNESS_RANK_CTL		1U
     17 #define WITNESS_RANK_TCACHES		2U
     18 #define	WITNESS_RANK_ARENAS		3U
     19 
     20 #define	WITNESS_RANK_PROF_DUMP		4U
     21 #define	WITNESS_RANK_PROF_BT2GCTX	5U
     22 #define	WITNESS_RANK_PROF_TDATAS	6U
     23 #define	WITNESS_RANK_PROF_TDATA		7U
     24 #define	WITNESS_RANK_PROF_GCTX		8U
     25 
     26 #define	WITNESS_RANK_ARENA		9U
     27 #define	WITNESS_RANK_ARENA_CHUNKS	10U
     28 #define	WITNESS_RANK_ARENA_NODE_CACHE	11U
     29 
     30 #define	WITNESS_RANK_BASE		12U
     31 
     32 #define	WITNESS_RANK_LEAF		0xffffffffU
     33 #define	WITNESS_RANK_ARENA_BIN		WITNESS_RANK_LEAF
     34 #define	WITNESS_RANK_ARENA_HUGE		WITNESS_RANK_LEAF
     35 #define	WITNESS_RANK_DSS		WITNESS_RANK_LEAF
     36 #define	WITNESS_RANK_PROF_ACTIVE	WITNESS_RANK_LEAF
     37 #define	WITNESS_RANK_PROF_DUMP_SEQ	WITNESS_RANK_LEAF
     38 #define	WITNESS_RANK_PROF_GDUMP		WITNESS_RANK_LEAF
     39 #define	WITNESS_RANK_PROF_NEXT_THR_UID	WITNESS_RANK_LEAF
     40 #define	WITNESS_RANK_PROF_THREAD_ACTIVE_INIT	WITNESS_RANK_LEAF
     41 
     42 #define	WITNESS_INITIALIZER(rank) {"initializer", rank, NULL, {NULL, NULL}}
     43 
     44 #endif /* JEMALLOC_H_TYPES */
     45 /******************************************************************************/
     46 #ifdef JEMALLOC_H_STRUCTS
     47 
     48 struct witness_s {
     49 	/* Name, used for printing lock order reversal messages. */
     50 	const char		*name;
     51 
     52 	/*
     53 	 * Witness rank, where 0 is lowest and UINT_MAX is highest.  Witnesses
     54 	 * must be acquired in order of increasing rank.
     55 	 */
     56 	witness_rank_t		rank;
     57 
     58 	/*
     59 	 * If two witnesses are of equal rank and they have the samp comp
     60 	 * function pointer, it is called as a last attempt to differentiate
     61 	 * between witnesses of equal rank.
     62 	 */
     63 	witness_comp_t		*comp;
     64 
     65 	/* Linkage for thread's currently owned locks. */
     66 	ql_elm(witness_t)	link;
     67 };
     68 
     69 #endif /* JEMALLOC_H_STRUCTS */
     70 /******************************************************************************/
     71 #ifdef JEMALLOC_H_EXTERNS
     72 
     73 void	witness_init(witness_t *witness, const char *name, witness_rank_t rank,
     74     witness_comp_t *comp);
     75 #ifdef JEMALLOC_JET
     76 typedef void (witness_lock_error_t)(const witness_list_t *, const witness_t *);
     77 extern witness_lock_error_t *witness_lock_error;
     78 #else
     79 void	witness_lock_error(const witness_list_t *witnesses,
     80     const witness_t *witness);
     81 #endif
     82 #ifdef JEMALLOC_JET
     83 typedef void (witness_owner_error_t)(const witness_t *);
     84 extern witness_owner_error_t *witness_owner_error;
     85 #else
     86 void	witness_owner_error(const witness_t *witness);
     87 #endif
     88 #ifdef JEMALLOC_JET
     89 typedef void (witness_not_owner_error_t)(const witness_t *);
     90 extern witness_not_owner_error_t *witness_not_owner_error;
     91 #else
     92 void	witness_not_owner_error(const witness_t *witness);
     93 #endif
     94 #ifdef JEMALLOC_JET
     95 typedef void (witness_lockless_error_t)(const witness_list_t *);
     96 extern witness_lockless_error_t *witness_lockless_error;
     97 #else
     98 void	witness_lockless_error(const witness_list_t *witnesses);
     99 #endif
    100 
    101 void	witnesses_cleanup(tsd_t *tsd);
    102 void	witness_fork_cleanup(tsd_t *tsd);
    103 void	witness_prefork(tsd_t *tsd);
    104 void	witness_postfork_parent(tsd_t *tsd);
    105 void	witness_postfork_child(tsd_t *tsd);
    106 
    107 #endif /* JEMALLOC_H_EXTERNS */
    108 /******************************************************************************/
    109 #ifdef JEMALLOC_H_INLINES
    110 
    111 #ifndef JEMALLOC_ENABLE_INLINE
    112 bool	witness_owner(tsd_t *tsd, const witness_t *witness);
    113 void	witness_assert_owner(tsdn_t *tsdn, const witness_t *witness);
    114 void	witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness);
    115 void	witness_assert_lockless(tsdn_t *tsdn);
    116 void	witness_lock(tsdn_t *tsdn, witness_t *witness);
    117 void	witness_unlock(tsdn_t *tsdn, witness_t *witness);
    118 #endif
    119 
    120 #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_))
    121 JEMALLOC_INLINE bool
    122 witness_owner(tsd_t *tsd, const witness_t *witness)
    123 {
    124 	witness_list_t *witnesses;
    125 	witness_t *w;
    126 
    127 	witnesses = tsd_witnessesp_get(tsd);
    128 	ql_foreach(w, witnesses, link) {
    129 		if (w == witness)
    130 			return (true);
    131 	}
    132 
    133 	return (false);
    134 }
    135 
    136 JEMALLOC_INLINE void
    137 witness_assert_owner(tsdn_t *tsdn, const witness_t *witness)
    138 {
    139 	tsd_t *tsd;
    140 
    141 	if (!config_debug)
    142 		return;
    143 
    144 	if (tsdn_null(tsdn))
    145 		return;
    146 	tsd = tsdn_tsd(tsdn);
    147 	if (witness->rank == WITNESS_RANK_OMIT)
    148 		return;
    149 
    150 	if (witness_owner(tsd, witness))
    151 		return;
    152 	witness_owner_error(witness);
    153 }
    154 
    155 JEMALLOC_INLINE void
    156 witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness)
    157 {
    158 	tsd_t *tsd;
    159 	witness_list_t *witnesses;
    160 	witness_t *w;
    161 
    162 	if (!config_debug)
    163 		return;
    164 
    165 	if (tsdn_null(tsdn))
    166 		return;
    167 	tsd = tsdn_tsd(tsdn);
    168 	if (witness->rank == WITNESS_RANK_OMIT)
    169 		return;
    170 
    171 	witnesses = tsd_witnessesp_get(tsd);
    172 	ql_foreach(w, witnesses, link) {
    173 		if (w == witness)
    174 			witness_not_owner_error(witness);
    175 	}
    176 }
    177 
    178 JEMALLOC_INLINE void
    179 witness_assert_lockless(tsdn_t *tsdn)
    180 {
    181 	tsd_t *tsd;
    182 	witness_list_t *witnesses;
    183 	witness_t *w;
    184 
    185 	if (!config_debug)
    186 		return;
    187 
    188 	if (tsdn_null(tsdn))
    189 		return;
    190 	tsd = tsdn_tsd(tsdn);
    191 
    192 	witnesses = tsd_witnessesp_get(tsd);
    193 	w = ql_last(witnesses, link);
    194 	if (w != NULL)
    195 		witness_lockless_error(witnesses);
    196 }
    197 
    198 JEMALLOC_INLINE void
    199 witness_lock(tsdn_t *tsdn, witness_t *witness)
    200 {
    201 	tsd_t *tsd;
    202 	witness_list_t *witnesses;
    203 	witness_t *w;
    204 
    205 	if (!config_debug)
    206 		return;
    207 
    208 	if (tsdn_null(tsdn))
    209 		return;
    210 	tsd = tsdn_tsd(tsdn);
    211 	if (witness->rank == WITNESS_RANK_OMIT)
    212 		return;
    213 
    214 	witness_assert_not_owner(tsdn, witness);
    215 
    216 	witnesses = tsd_witnessesp_get(tsd);
    217 	w = ql_last(witnesses, link);
    218 	if (w == NULL) {
    219 		/* No other locks; do nothing. */
    220 	} else if (tsd_witness_fork_get(tsd) && w->rank <= witness->rank) {
    221 		/* Forking, and relaxed ranking satisfied. */
    222 	} else if (w->rank > witness->rank) {
    223 		/* Not forking, rank order reversal. */
    224 		witness_lock_error(witnesses, witness);
    225 	} else if (w->rank == witness->rank && (w->comp == NULL || w->comp !=
    226 	    witness->comp || w->comp(w, witness) > 0)) {
    227 		/*
    228 		 * Missing/incompatible comparison function, or comparison
    229 		 * function indicates rank order reversal.
    230 		 */
    231 		witness_lock_error(witnesses, witness);
    232 	}
    233 
    234 	ql_elm_new(witness, link);
    235 	ql_tail_insert(witnesses, witness, link);
    236 }
    237 
    238 JEMALLOC_INLINE void
    239 witness_unlock(tsdn_t *tsdn, witness_t *witness)
    240 {
    241 	tsd_t *tsd;
    242 	witness_list_t *witnesses;
    243 
    244 	if (!config_debug)
    245 		return;
    246 
    247 	if (tsdn_null(tsdn))
    248 		return;
    249 	tsd = tsdn_tsd(tsdn);
    250 	if (witness->rank == WITNESS_RANK_OMIT)
    251 		return;
    252 
    253 	/*
    254 	 * Check whether owner before removal, rather than relying on
    255 	 * witness_assert_owner() to abort, so that unit tests can test this
    256 	 * function's failure mode without causing undefined behavior.
    257 	 */
    258 	if (witness_owner(tsd, witness)) {
    259 		witnesses = tsd_witnessesp_get(tsd);
    260 		ql_remove(witnesses, witness, link);
    261 	} else
    262 		witness_assert_owner(tsdn, witness);
    263 }
    264 #endif
    265 
    266 #endif /* JEMALLOC_H_INLINES */
    267 /******************************************************************************/
    268