Refactor witness_unlock() to fix undefined test behavior.

This resolves #396.
This commit is contained in:
Jason Evans 2016-10-31 11:45:41 -07:00
parent 6c80321aed
commit 6a834d94bb
2 changed files with 29 additions and 11 deletions

View File

@ -530,6 +530,7 @@ witness_lock
witness_lock_error witness_lock_error
witness_lockless_error witness_lockless_error
witness_not_owner_error witness_not_owner_error
witness_owner
witness_owner_error witness_owner_error
witness_postfork_child witness_postfork_child
witness_postfork_parent witness_postfork_parent

View File

@ -112,6 +112,7 @@ void witness_postfork_child(tsd_t *tsd);
#ifdef JEMALLOC_H_INLINES #ifdef JEMALLOC_H_INLINES
#ifndef JEMALLOC_ENABLE_INLINE #ifndef JEMALLOC_ENABLE_INLINE
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_lockless(tsdn_t *tsdn); void witness_assert_lockless(tsdn_t *tsdn);
@ -120,12 +121,25 @@ void witness_unlock(tsdn_t *tsdn, witness_t *witness);
#endif #endif
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_)) #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_))
JEMALLOC_INLINE bool
witness_owner(tsd_t *tsd, const witness_t *witness)
{
witness_list_t *witnesses;
witness_t *w;
witnesses = tsd_witnessesp_get(tsd);
ql_foreach(w, witnesses, link) {
if (w == witness)
return (true);
}
return (false);
}
JEMALLOC_INLINE void JEMALLOC_INLINE void
witness_assert_owner(tsdn_t *tsdn, const witness_t *witness) witness_assert_owner(tsdn_t *tsdn, const witness_t *witness)
{ {
tsd_t *tsd; tsd_t *tsd;
witness_list_t *witnesses;
witness_t *w;
if (!config_debug) if (!config_debug)
return; return;
@ -136,11 +150,8 @@ witness_assert_owner(tsdn_t *tsdn, const witness_t *witness)
if (witness->rank == WITNESS_RANK_OMIT) if (witness->rank == WITNESS_RANK_OMIT)
return; return;
witnesses = tsd_witnessesp_get(tsd); if (witness_owner(tsd, witness))
ql_foreach(w, witnesses, link) {
if (w == witness)
return; return;
}
witness_owner_error(witness); witness_owner_error(witness);
} }
@ -243,10 +254,16 @@ witness_unlock(tsdn_t *tsdn, witness_t *witness)
if (witness->rank == WITNESS_RANK_OMIT) if (witness->rank == WITNESS_RANK_OMIT)
return; return;
witness_assert_owner(tsdn, witness); /*
* Check whether owner before removal, rather than relying on
* witness_assert_owner() to abort, so that unit tests can test this
* function's failure mode without causing undefined behavior.
*/
if (witness_owner(tsd, witness)) {
witnesses = tsd_witnessesp_get(tsd); witnesses = tsd_witnessesp_get(tsd);
ql_remove(witnesses, witness, link); ql_remove(witnesses, witness, link);
} else
witness_assert_owner(tsdn, witness);
} }
#endif #endif