// The standard ASSERT macros don't play correctly with thread-safety analysis, in that they // apparently do not always execute the rest of the function, and can thus result in function // returns with different lock states. They should only be used when no locks are held. // // In other contexts, we replace assertions by macros that record failures as we go, but only // reporting them at the end. We invoke CHECK_DEFERRED_FAILURE_STATE only when no locks are held. #define DECLARE_DEFERRED_FAILURE_STATE \ int fail_line = 0; \ constchar* fail_cond = nullptr; #define DEFERRED_ASSERT_TRUE(p) \ if (!(p) && fail_line == 0) { \
fail_line = __LINE__; \
fail_cond = #p; \
} #define DEFERRED_ASSERT_FALSE(p) DEFERRED_ASSERT_TRUE(!p) #define CHECK_DEFERRED_FAILURE_STATE CHECK_EQ(fail_line, 0) << fail_cond
namespace art HIDDEN {
class MutexTest : public CommonRuntimeTest { protected:
MutexTest() {
use_boot_image_ = true; // Make the Runtime creation cheaper.
}
};
// TODO: The use of Assert...Held() here is not optimal, since that tells the thread checker // to assume it is held, which is not great in a test, and it actually performs the dynamic // check only in debug builds, which is also not great in a test. Use ASSERT_TRUE(...Is...Held()) // or DEFERRED_ASSERT_TRUE(...Is...Held()) instead, as we've started to do below.
// This test is single-threaded, so we also know _who_ should hold the lock. if (expected_depth == 0) {
mu.AssertNotHeld(Thread::Current());
} else {
mu.AssertHeld(Thread::Current());
}
}
};
TEST_F(MutexTest, LockUnlock) { // TODO: Remove `Mutex` dependency on `Runtime` or at least make sure it works // without a `Runtime` with reasonable defaults (and without dumping stack for timeout).
ASSERT_TRUE(Runtime::Current() != nullptr);
Mutex mu("test mutex");
MutexTester::AssertDepth(mu, 0U);
mu.Lock(Thread::Current());
MutexTester::AssertDepth(mu, 1U);
mu.Unlock(Thread::Current());
MutexTester::AssertDepth(mu, 0U);
}
// TODO: NO_THREAD_SAFETY_ANALYSIS because ASSERT_TRUE is not yet DEFERRED. staticvoid TryLockUnlockTest() NO_THREAD_SAFETY_ANALYSIS {
Mutex mu("test mutex");
MutexTester::AssertDepth(mu, 0U);
ASSERT_TRUE(mu.TryLock(Thread::Current()));
MutexTester::AssertDepth(mu, 1U);
mu.Unlock(Thread::Current());
MutexTester::AssertDepth(mu, 0U);
}
// Recursive lock acquisition is not supported by our current thread-safety annotations, which do // not mention REENTRANT_CAPABILITY. This may not be worth fixing, since reentrant Mutexes should // probably be deprecated. staticvoid RecursiveLockWaitTest() NO_THREAD_SAFETY_ANALYSIS {
DECLARE_DEFERRED_FAILURE_STATE;
RecursiveLockWait state;
state.mu.Lock(Thread::Current());
state.mu.Lock(Thread::Current());
// This ensures we don't hang when waiting on a recursively locked mutex, // which is not supported with bare pthread_mutex_t.
TEST_F(MutexTest, RecursiveLockWait) {
RecursiveLockWaitTest();
}
// This is technically not guaranteed, but it should always succeed. We try to keep the control // flow in the failure case simple enough so that thread-safety analysis can understand it. if (!mu.ExclusiveTryLock(Thread::Current())) {
abort();
}
DEFERRED_ASSERT_TRUE(mu.IsSharedHeld(Thread::Current()));
DEFERRED_ASSERT_TRUE(mu.IsExclusiveHeld(Thread::Current()));
mu.ExclusiveUnlock(Thread::Current());
ASSERT_FALSE(mu.IsExclusiveHeld(Thread::Current()));
ASSERT_FALSE(mu.IsSharedHeld(Thread::Current()));
CHECK_DEFERRED_FAILURE_STATE;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.