Add witness_assert_depth[_to_rank]().

This makes it possible to make lock state assertions about precisely
which locks are held.
This commit is contained in:
Jason Evans 2017-01-21 15:12:03 -08:00
parent ace679ce74
commit d0e93ada51
6 changed files with 84 additions and 26 deletions

View File

@ -549,13 +549,15 @@ tsdn_fetch
tsdn_null tsdn_null
tsdn_rtree_ctx tsdn_rtree_ctx
tsdn_tsd tsdn_tsd
witness_assert_depth
witness_assert_depth_to_rank
witness_assert_lockless witness_assert_lockless
witness_assert_not_owner witness_assert_not_owner
witness_assert_owner witness_assert_owner
witness_depth_error
witness_init witness_init
witness_lock witness_lock
witness_lock_error witness_lock_error
witness_lockless_error
witness_not_owner_error witness_not_owner_error
witness_owner witness_owner
witness_owner_error witness_owner_error

View File

@ -23,10 +23,12 @@ extern witness_not_owner_error_t *witness_not_owner_error;
void witness_not_owner_error(const witness_t *witness); void witness_not_owner_error(const witness_t *witness);
#endif #endif
#ifdef JEMALLOC_JET #ifdef JEMALLOC_JET
typedef void (witness_lockless_error_t)(const witness_list_t *); typedef void (witness_depth_error_t)(const witness_list_t *,
extern witness_lockless_error_t *witness_lockless_error; witness_rank_t rank_inclusive, unsigned depth);
extern witness_depth_error_t *witness_depth_error;
#else #else
void witness_lockless_error(const witness_list_t *witnesses); void witness_depth_error(const witness_list_t *witnesses,
witness_rank_t rank_inclusive, unsigned depth);
#endif #endif
void witnesses_cleanup(tsd_t *tsd); void witnesses_cleanup(tsd_t *tsd);

View File

@ -5,6 +5,9 @@
bool witness_owner(tsd_t *tsd, const witness_t *witness); bool witness_owner(tsd_t *tsd, const witness_t *witness);
void witness_assert_owner(tsdn_t *tsdn, const witness_t *witness); void witness_assert_owner(tsdn_t *tsdn, const witness_t *witness);
void witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness); void witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness);
void witness_assert_depth_to_rank(tsdn_t *tsdn, witness_rank_t rank_inclusive,
unsigned depth);
void witness_assert_depth(tsdn_t *tsdn, unsigned depth);
void witness_assert_lockless(tsdn_t *tsdn); void witness_assert_lockless(tsdn_t *tsdn);
void witness_lock(tsdn_t *tsdn, witness_t *witness); void witness_lock(tsdn_t *tsdn, witness_t *witness);
void witness_unlock(tsdn_t *tsdn, witness_t *witness); void witness_unlock(tsdn_t *tsdn, witness_t *witness);
@ -78,8 +81,10 @@ witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness) {
} }
JEMALLOC_INLINE void JEMALLOC_INLINE void
witness_assert_lockless(tsdn_t *tsdn) { witness_assert_depth_to_rank(tsdn_t *tsdn, witness_rank_t rank_inclusive,
unsigned depth) {
tsd_t *tsd; tsd_t *tsd;
unsigned d;
witness_list_t *witnesses; witness_list_t *witnesses;
witness_t *w; witness_t *w;
@ -92,11 +97,30 @@ witness_assert_lockless(tsdn_t *tsdn) {
} }
tsd = tsdn_tsd(tsdn); tsd = tsdn_tsd(tsdn);
d = 0;
witnesses = tsd_witnessesp_get(tsd); witnesses = tsd_witnessesp_get(tsd);
w = ql_last(witnesses, link); w = ql_last(witnesses, link);
if (w != NULL) { if (w != NULL) {
witness_lockless_error(witnesses); ql_reverse_foreach(w, witnesses, link) {
if (w->rank < rank_inclusive) {
break;
} }
d++;
}
}
if (d != depth) {
witness_depth_error(witnesses, rank_inclusive, depth);
}
}
JEMALLOC_INLINE void
witness_assert_depth(tsdn_t *tsdn, unsigned depth) {
witness_assert_depth_to_rank(tsdn, WITNESS_RANK_MIN, depth);
}
JEMALLOC_INLINE void
witness_assert_lockless(tsdn_t *tsdn) {
witness_assert_depth(tsdn, 0);
} }
JEMALLOC_INLINE void JEMALLOC_INLINE void

View File

@ -13,6 +13,8 @@ typedef int witness_comp_t (const witness_t *, void *, const witness_t *,
*/ */
#define WITNESS_RANK_OMIT 0U #define WITNESS_RANK_OMIT 0U
#define WITNESS_RANK_MIN 1U
#define WITNESS_RANK_INIT 1U #define WITNESS_RANK_INIT 1U
#define WITNESS_RANK_CTL 1U #define WITNESS_RANK_CTL 1U
#define WITNESS_RANK_ARENAS 2U #define WITNESS_RANK_ARENAS 2U

View File

@ -65,14 +65,16 @@ witness_not_owner_error_t *witness_not_owner_error =
#endif #endif
#ifdef JEMALLOC_JET #ifdef JEMALLOC_JET
#undef witness_lockless_error #undef witness_depth_error
#define witness_lockless_error JEMALLOC_N(n_witness_lockless_error) #define witness_depth_error JEMALLOC_N(n_witness_depth_error)
#endif #endif
void void
witness_lockless_error(const witness_list_t *witnesses) { witness_depth_error(const witness_list_t *witnesses,
witness_rank_t rank_inclusive, unsigned depth) {
witness_t *w; witness_t *w;
malloc_printf("<jemalloc>: Should not own any locks:"); malloc_printf("<jemalloc>: Should own %u lock%s of rank >= %u:", depth,
(depth != 1) ? "s" : "", rank_inclusive);
ql_foreach(w, witnesses, link) { ql_foreach(w, witnesses, link) {
malloc_printf(" %s(%u)", w->name, w->rank); malloc_printf(" %s(%u)", w->name, w->rank);
} }
@ -80,10 +82,9 @@ witness_lockless_error(const witness_list_t *witnesses) {
abort(); abort();
} }
#ifdef JEMALLOC_JET #ifdef JEMALLOC_JET
#undef witness_lockless_error #undef witness_depth_error
#define witness_lockless_error JEMALLOC_N(witness_lockless_error) #define witness_depth_error JEMALLOC_N(witness_depth_error)
witness_lockless_error_t *witness_lockless_error = witness_depth_error_t *witness_depth_error = JEMALLOC_N(n_witness_depth_error);
JEMALLOC_N(n_witness_lockless_error);
#endif #endif
void void

View File

@ -3,12 +3,12 @@
static witness_lock_error_t *witness_lock_error_orig; static witness_lock_error_t *witness_lock_error_orig;
static witness_owner_error_t *witness_owner_error_orig; static witness_owner_error_t *witness_owner_error_orig;
static witness_not_owner_error_t *witness_not_owner_error_orig; static witness_not_owner_error_t *witness_not_owner_error_orig;
static witness_lockless_error_t *witness_lockless_error_orig; static witness_depth_error_t *witness_depth_error_orig;
static bool saw_lock_error; static bool saw_lock_error;
static bool saw_owner_error; static bool saw_owner_error;
static bool saw_not_owner_error; static bool saw_not_owner_error;
static bool saw_lockless_error; static bool saw_depth_error;
static void static void
witness_lock_error_intercept(const witness_list_t *witnesses, witness_lock_error_intercept(const witness_list_t *witnesses,
@ -27,8 +27,9 @@ witness_not_owner_error_intercept(const witness_t *witness) {
} }
static void static void
witness_lockless_error_intercept(const witness_list_t *witnesses) { witness_depth_error_intercept(const witness_list_t *witnesses,
saw_lockless_error = true; witness_rank_t rank_inclusive, unsigned depth) {
saw_depth_error = true;
} }
static int static int
@ -61,21 +62,36 @@ TEST_BEGIN(test_witness) {
tsdn = tsdn_fetch(); tsdn = tsdn_fetch();
witness_assert_lockless(tsdn); witness_assert_lockless(tsdn);
witness_assert_depth(tsdn, 0);
witness_assert_depth_to_rank(tsdn, (witness_rank_t)1U, 0);
witness_init(&a, "a", 1, NULL, NULL); witness_init(&a, "a", 1, NULL, NULL);
witness_assert_not_owner(tsdn, &a); witness_assert_not_owner(tsdn, &a);
witness_lock(tsdn, &a); witness_lock(tsdn, &a);
witness_assert_owner(tsdn, &a); witness_assert_owner(tsdn, &a);
witness_assert_depth(tsdn, 1);
witness_assert_depth_to_rank(tsdn, (witness_rank_t)1U, 1);
witness_assert_depth_to_rank(tsdn, (witness_rank_t)2U, 0);
witness_init(&b, "b", 2, NULL, NULL); witness_init(&b, "b", 2, NULL, NULL);
witness_assert_not_owner(tsdn, &b); witness_assert_not_owner(tsdn, &b);
witness_lock(tsdn, &b); witness_lock(tsdn, &b);
witness_assert_owner(tsdn, &b); witness_assert_owner(tsdn, &b);
witness_assert_depth(tsdn, 2);
witness_assert_depth_to_rank(tsdn, (witness_rank_t)1U, 2);
witness_assert_depth_to_rank(tsdn, (witness_rank_t)2U, 1);
witness_assert_depth_to_rank(tsdn, (witness_rank_t)3U, 0);
witness_unlock(tsdn, &a); witness_unlock(tsdn, &a);
witness_assert_depth(tsdn, 1);
witness_assert_depth_to_rank(tsdn, (witness_rank_t)1U, 1);
witness_assert_depth_to_rank(tsdn, (witness_rank_t)2U, 1);
witness_assert_depth_to_rank(tsdn, (witness_rank_t)3U, 0);
witness_unlock(tsdn, &b); witness_unlock(tsdn, &b);
witness_assert_lockless(tsdn); witness_assert_lockless(tsdn);
witness_assert_depth(tsdn, 0);
witness_assert_depth_to_rank(tsdn, (witness_rank_t)1U, 0);
} }
TEST_END TEST_END
@ -93,12 +109,15 @@ TEST_BEGIN(test_witness_comp) {
witness_assert_not_owner(tsdn, &a); witness_assert_not_owner(tsdn, &a);
witness_lock(tsdn, &a); witness_lock(tsdn, &a);
witness_assert_owner(tsdn, &a); witness_assert_owner(tsdn, &a);
witness_assert_depth(tsdn, 1);
witness_init(&b, "b", 1, witness_comp, &b); witness_init(&b, "b", 1, witness_comp, &b);
witness_assert_not_owner(tsdn, &b); witness_assert_not_owner(tsdn, &b);
witness_lock(tsdn, &b); witness_lock(tsdn, &b);
witness_assert_owner(tsdn, &b); witness_assert_owner(tsdn, &b);
witness_assert_depth(tsdn, 2);
witness_unlock(tsdn, &b); witness_unlock(tsdn, &b);
witness_assert_depth(tsdn, 1);
witness_lock_error_orig = witness_lock_error; witness_lock_error_orig = witness_lock_error;
witness_lock_error = witness_lock_error_intercept; witness_lock_error = witness_lock_error_intercept;
@ -110,6 +129,7 @@ TEST_BEGIN(test_witness_comp) {
witness_lock(tsdn, &c); witness_lock(tsdn, &c);
assert_true(saw_lock_error, "Expected witness lock error"); assert_true(saw_lock_error, "Expected witness lock error");
witness_unlock(tsdn, &c); witness_unlock(tsdn, &c);
witness_assert_depth(tsdn, 1);
saw_lock_error = false; saw_lock_error = false;
@ -119,6 +139,7 @@ TEST_BEGIN(test_witness_comp) {
witness_lock(tsdn, &d); witness_lock(tsdn, &d);
assert_true(saw_lock_error, "Expected witness lock error"); assert_true(saw_lock_error, "Expected witness lock error");
witness_unlock(tsdn, &d); witness_unlock(tsdn, &d);
witness_assert_depth(tsdn, 1);
witness_unlock(tsdn, &a); witness_unlock(tsdn, &a);
@ -146,11 +167,13 @@ TEST_BEGIN(test_witness_reversal) {
witness_init(&b, "b", 2, NULL, NULL); witness_init(&b, "b", 2, NULL, NULL);
witness_lock(tsdn, &b); witness_lock(tsdn, &b);
witness_assert_depth(tsdn, 1);
assert_false(saw_lock_error, "Unexpected witness lock error"); assert_false(saw_lock_error, "Unexpected witness lock error");
witness_lock(tsdn, &a); witness_lock(tsdn, &a);
assert_true(saw_lock_error, "Expected witness lock error"); assert_true(saw_lock_error, "Expected witness lock error");
witness_unlock(tsdn, &a); witness_unlock(tsdn, &a);
witness_assert_depth(tsdn, 1);
witness_unlock(tsdn, &b); witness_unlock(tsdn, &b);
witness_assert_lockless(tsdn); witness_assert_lockless(tsdn);
@ -222,34 +245,38 @@ TEST_BEGIN(test_witness_unlock_not_owned) {
} }
TEST_END TEST_END
TEST_BEGIN(test_witness_lockful) { TEST_BEGIN(test_witness_depth) {
witness_t a; witness_t a;
tsdn_t *tsdn; tsdn_t *tsdn;
test_skip_if(!config_debug); test_skip_if(!config_debug);
witness_lockless_error_orig = witness_lockless_error; witness_depth_error_orig = witness_depth_error;
witness_lockless_error = witness_lockless_error_intercept; witness_depth_error = witness_depth_error_intercept;
saw_lockless_error = false; saw_depth_error = false;
tsdn = tsdn_fetch(); tsdn = tsdn_fetch();
witness_assert_lockless(tsdn); witness_assert_lockless(tsdn);
witness_assert_depth(tsdn, 0);
witness_init(&a, "a", 1, NULL, NULL); witness_init(&a, "a", 1, NULL, NULL);
assert_false(saw_lockless_error, "Unexpected lockless error"); assert_false(saw_depth_error, "Unexpected depth error");
witness_assert_lockless(tsdn); witness_assert_lockless(tsdn);
witness_assert_depth(tsdn, 0);
witness_lock(tsdn, &a); witness_lock(tsdn, &a);
witness_assert_lockless(tsdn); witness_assert_lockless(tsdn);
assert_true(saw_lockless_error, "Expected lockless error"); witness_assert_depth(tsdn, 0);
assert_true(saw_depth_error, "Expected depth error");
witness_unlock(tsdn, &a); witness_unlock(tsdn, &a);
witness_assert_lockless(tsdn); witness_assert_lockless(tsdn);
witness_assert_depth(tsdn, 0);
witness_lockless_error = witness_lockless_error_orig; witness_depth_error = witness_depth_error_orig;
} }
TEST_END TEST_END
@ -261,5 +288,5 @@ main(void) {
test_witness_reversal, test_witness_reversal,
test_witness_recursive, test_witness_recursive,
test_witness_unlock_not_owned, test_witness_unlock_not_owned,
test_witness_lockful); test_witness_depth);
} }