public:
std::unique_ptr<Monitor> monitor_;
jobject object_;
jobject watchdog_object_; // One exception test is for waiting on another Thread's lock. This is used to race-free & // loop-free pass
Thread* thread_;
std::unique_ptr<Barrier> barrier_;
std::unique_ptr<Barrier> complete_barrier_; bool completed_;
};
// Check that an exception can be thrown correctly. // This test is potentially racy, but the timeout is long enough that it should work.
monitor_test_->thread_ = self; // Pass the Thread.
obj->MonitorEnter(self); // Lock the object. This should transition
LockWord lock_after = obj->GetLockWord(false); // it to thinLocked.
LockWord::LockState new_state = lock_after.GetState();
// Cannot use ASSERT only, as analysis thinks we'll keep holding the mutex. if (LockWord::LockState::kThinLocked != new_state) {
obj->MonitorExit(self); // To appease analysis.
ASSERT_EQ(LockWord::LockState::kThinLocked, new_state); // To fail the test. return;
}
// Force a fat lock by running identity hashcode to fill up lock word.
obj->IdentityHashCode();
LockWord lock_after2 = obj->GetLockWord(false);
LockWord::LockState new_state2 = lock_after2.GetState();
// Cannot use ASSERT only, as analysis thinks we'll keep holding the mutex. if (LockWord::LockState::kFatLocked != new_state2) {
obj->MonitorExit(self); // To appease analysis.
ASSERT_EQ(LockWord::LockState::kFatLocked, new_state2); // To fail the test. return;
}
{ // Need to drop the mutator lock to use the barrier.
ScopedThreadSuspension sts(self, ThreadState::kSuspended);
monitor_test_->barrier_->Wait(self); // Let the other thread know we're done.
}
// Give the other task a chance to do its thing.
NanoSleep(initial_sleep_ * 1000 * 1000);
// Now try to Wait on the Monitor.
Monitor::Wait(self, obj.Get(), millis_, 0, true, ThreadState::kTimedWaiting);
// Check the exception status against what we expect.
EXPECT_EQ(expected_, self->IsExceptionPending()); if (expected_) {
self->ClearException();
}
{ // Need to drop the mutator lock to use the barrier.
ScopedThreadSuspension sts(self, ThreadState::kSuspended);
monitor_test_->complete_barrier_->Wait(self); // Wait for test completion.
}
obj->MonitorExit(self); // Release the object. Appeases analysis.
}
// Create the barrier used to synchronize.
test->barrier_ = std::make_unique<Barrier>(2);
test->complete_barrier_ = std::make_unique<Barrier>(3);
test->completed_ = false;
// Our job: Fill the heap, then try Wait.
{
VariableSizedHandleScope vhs(soa.Self());
test->FillHeap(soa.Self(), class_linker, &vhs);
// Now release everything.
}
// Need to drop the mutator lock to allow barriers.
ScopedThreadSuspension sts(soa.Self(), ThreadState::kNative);
std::unique_ptr<ThreadPool> thread_pool(ThreadPool::Create(pool_name, 3));
thread_pool->AddTask(self, new CreateTask(test, create_sleep, c_millis, c_expected)); if (interrupt) {
thread_pool->AddTask(self, new InterruptTask(test, use_sleep, static_cast<uint64_t>(u_millis)));
} else {
thread_pool->AddTask(self, new UseTask(test, use_sleep, u_millis, u_expected));
}
thread_pool->AddTask(self, new WatchdogTask(test));
thread_pool->StartWorkers(self);
// Wait on completion barrier.
test->complete_barrier_->Wait(self);
test->completed_ = true;
// Wake the watchdog.
{
ScopedObjectAccess soa2(self);
watchdog_obj->MonitorEnter(self); // Lock the object.
watchdog_obj->NotifyAll(self); // Wake up waiting parties.
watchdog_obj->MonitorExit(self); // Release the lock.
}
thread_pool->StopWorkers(self);
}
// First test: throwing an exception when trying to wait in Monitor with another thread.
TEST_F(MonitorTest, CheckExceptionsWait1) { // Make the CreateTask wait 10ms, the UseTask wait 10ms. // => The use task will get the lock first and get to self == owner check. // This will lead to OOM and monitor error messages in the log.
ScopedLogSeverity sls(LogSeverity::FATAL);
CommonWaitSetup(this, class_linker_, 10, 50, false, false, 2, 50, true, "Monitor test thread pool 1");
}
// Second test: throwing an exception for invalid wait time.
TEST_F(MonitorTest, CheckExceptionsWait2) { // Make the CreateTask wait 0ms, the UseTask wait 10ms. // => The create task will get the lock first and get to ms >= 0 // This will lead to OOM and monitor error messages in the log.
ScopedLogSeverity sls(LogSeverity::FATAL);
CommonWaitSetup(this, class_linker_, 0, -1, true, false, 10, 50, true, "Monitor test thread pool 2");
}
// Third test: throwing an interrupted-exception.
TEST_F(MonitorTest, CheckExceptionsWait3) { // Make the CreateTask wait 0ms, then Wait for a long time. Make the InterruptTask wait 10ms, // after which it will interrupt the create task and then wait another 10ms. // => The create task will get to the interrupted-exception throw. // This will lead to OOM and monitor error messages in the log.
ScopedLogSeverity sls(LogSeverity::FATAL);
CommonWaitSetup(this, class_linker_, 0, 500, true, true, 10, 50, true, "Monitor test thread pool 3");
}
class TryLockTask : public Task { public: explicit TryLockTask(jobject obj) : obj_(obj) {}
void Run(Thread* self) override {
ScopedObjectAccess soa(self);
StackHandleScope<1u> hs(self);
Handle<mirror::Object> obj = hs.NewHandle(soa.Decode<mirror::Object>(obj_)); // Lock is held by other thread, try lock should fail.
ObjectTryLock<mirror::Object> lock(self, obj);
EXPECT_FALSE(lock.Acquired());
}
void Finalize() override { deletethis;
}
private:
jobject obj_;
};
// Test trylock in deadlock scenarios.
TEST_F(MonitorTest, TestTryLock) {
ScopedLogSeverity sls(LogSeverity::FATAL);
Thread* const self = Thread::Current();
std::unique_ptr<ThreadPool> thread_pool(ThreadPool::Create("the pool", 2));
ScopedObjectAccess soa(self);
StackHandleScope<1> hs(self);
Handle<mirror::Object> obj1(
hs.NewHandle<mirror::Object>(mirror::String::AllocFromModifiedUtf8(self, "hello, world!")));
jobject g_obj1 = soa.Vm()->AddGlobalRef(self, obj1.Get());
ASSERT_TRUE(g_obj1 != nullptr);
{
ObjectLock<mirror::Object> lock1(self, obj1);
{
ObjectTryLock<mirror::Object> trylock(self, obj1);
EXPECT_TRUE(trylock.Acquired());
} // Test failure case.
thread_pool->AddTask(self, new TryLockTask(g_obj1));
thread_pool->StartWorkers(self);
ScopedThreadSuspension sts(self, ThreadState::kSuspended);
thread_pool->Wait(Thread::Current(), /*do_work=*/false, /*may_hold_locks=*/false);
} // Test that the trylock actually locks the object.
{
ObjectTryLock<mirror::Object> trylock(self, obj1);
EXPECT_TRUE(trylock.Acquired());
obj1->Notify(self); // Since we hold the lock there should be no monitor state exeception.
self->AssertNoPendingException();
}
thread_pool->StopWorkers(self);
}
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.