diff options
Diffstat (limited to 'runtime/thread_test.cc')
-rw-r--r-- | runtime/thread_test.cc | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/runtime/thread_test.cc b/runtime/thread_test.cc new file mode 100644 index 0000000000..c4577bc250 --- /dev/null +++ b/runtime/thread_test.cc @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "thread.h" + +#include "android-base/logging.h" +#include "base/locks.h" +#include "base/mutex.h" +#include "common_runtime_test.h" +#include "thread-current-inl.h" +#include "thread-inl.h" + +namespace art { + +class ThreadTest : public CommonRuntimeTest {}; + +// Ensure that basic list operations on ThreadExitFlags work. These are rarely +// exercised in practice, since normally only one flag is registered at a time. + +TEST_F(ThreadTest, ThreadExitFlagTest) { + Thread* self = Thread::Current(); + ThreadExitFlag tefs[3]; + { + MutexLock mu(self, *Locks::thread_list_lock_); + self->NotifyOnThreadExit(&tefs[2]); + ASSERT_TRUE(self->IsRegistered(&tefs[2])); + ASSERT_FALSE(tefs[2].HasExited()); + ASSERT_FALSE(self->IsRegistered(&tefs[1])); + self->NotifyOnThreadExit(&tefs[1]); + self->NotifyOnThreadExit(&tefs[0]); + ASSERT_TRUE(self->IsRegistered(&tefs[0])); + ASSERT_TRUE(self->IsRegistered(&tefs[1])); + ASSERT_TRUE(self->IsRegistered(&tefs[2])); + self->UnregisterThreadExitFlag(&tefs[1]); + ASSERT_TRUE(self->IsRegistered(&tefs[0])); + ASSERT_FALSE(self->IsRegistered(&tefs[1])); + ASSERT_TRUE(self->IsRegistered(&tefs[2])); + self->UnregisterThreadExitFlag(&tefs[2]); + ASSERT_TRUE(self->IsRegistered(&tefs[0])); + ASSERT_FALSE(self->IsRegistered(&tefs[1])); + ASSERT_FALSE(self->IsRegistered(&tefs[2])); + } + Thread::DCheckUnregisteredEverywhere(&tefs[1], &tefs[2]); + { + MutexLock mu(self, *Locks::thread_list_lock_); + self->UnregisterThreadExitFlag(&tefs[0]); + ASSERT_FALSE(self->IsRegistered(&tefs[0])); + ASSERT_FALSE(self->IsRegistered(&tefs[1])); + ASSERT_FALSE(self->IsRegistered(&tefs[2])); + } + Thread::DCheckUnregisteredEverywhere(&tefs[0], &tefs[2]); +} + +TEST_F(ThreadTest, ThreadExitSignalTest) { + Thread* self = Thread::Current(); + ThreadExitFlag tefs[3]; + { + MutexLock mu(self, *Locks::thread_list_lock_); + self->NotifyOnThreadExit(&tefs[2]); + ASSERT_TRUE(self->IsRegistered(&tefs[2])); + ASSERT_FALSE(self->IsRegistered(&tefs[1])); + self->NotifyOnThreadExit(&tefs[1]); + ASSERT_TRUE(self->IsRegistered(&tefs[1])); + self->SignalExitFlags(); + ASSERT_TRUE(tefs[1].HasExited()); + ASSERT_TRUE(tefs[2].HasExited()); + } + Thread::DCheckUnregisteredEverywhere(&tefs[1], &tefs[2]); + { + MutexLock mu(self, *Locks::thread_list_lock_); + self->NotifyOnThreadExit(&tefs[0]); + tefs[2].~ThreadExitFlag(); // Destroy and reinitialize. + new (&tefs[2]) ThreadExitFlag(); + self->NotifyOnThreadExit(&tefs[2]); + ASSERT_FALSE(tefs[0].HasExited()); + ASSERT_TRUE(tefs[1].HasExited()); + ASSERT_FALSE(tefs[2].HasExited()); + self->SignalExitFlags(); + ASSERT_TRUE(tefs[0].HasExited()); + ASSERT_TRUE(tefs[1].HasExited()); + ASSERT_TRUE(tefs[2].HasExited()); + } + Thread::DCheckUnregisteredEverywhere(&tefs[0], &tefs[2]); +} + +} // namespace art |