1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "thread.h"
18
19 #include "android-base/logging.h"
20 #include "base/locks.h"
21 #include "base/mutex.h"
22 #include "common_runtime_test.h"
23 #include "thread-current-inl.h"
24 #include "thread-inl.h"
25
26 namespace art HIDDEN {
27
28 class ThreadTest : public CommonRuntimeTest {};
29
30 // Ensure that basic list operations on ThreadExitFlags work. These are rarely
31 // exercised in practice, since normally only one flag is registered at a time.
32
TEST_F(ThreadTest,ThreadExitFlagTest)33 TEST_F(ThreadTest, ThreadExitFlagTest) {
34 Thread* self = Thread::Current();
35 ThreadExitFlag tefs[3];
36 {
37 MutexLock mu(self, *Locks::thread_list_lock_);
38 self->NotifyOnThreadExit(&tefs[2]);
39 ASSERT_TRUE(self->IsRegistered(&tefs[2]));
40 ASSERT_FALSE(tefs[2].HasExited());
41 ASSERT_FALSE(self->IsRegistered(&tefs[1]));
42 self->NotifyOnThreadExit(&tefs[1]);
43 self->NotifyOnThreadExit(&tefs[0]);
44 ASSERT_TRUE(self->IsRegistered(&tefs[0]));
45 ASSERT_TRUE(self->IsRegistered(&tefs[1]));
46 ASSERT_TRUE(self->IsRegistered(&tefs[2]));
47 self->UnregisterThreadExitFlag(&tefs[1]);
48 ASSERT_TRUE(self->IsRegistered(&tefs[0]));
49 ASSERT_FALSE(self->IsRegistered(&tefs[1]));
50 ASSERT_TRUE(self->IsRegistered(&tefs[2]));
51 self->UnregisterThreadExitFlag(&tefs[2]);
52 ASSERT_TRUE(self->IsRegistered(&tefs[0]));
53 ASSERT_FALSE(self->IsRegistered(&tefs[1]));
54 ASSERT_FALSE(self->IsRegistered(&tefs[2]));
55 }
56 Thread::DCheckUnregisteredEverywhere(&tefs[1], &tefs[2]);
57 {
58 MutexLock mu(self, *Locks::thread_list_lock_);
59 self->UnregisterThreadExitFlag(&tefs[0]);
60 ASSERT_FALSE(self->IsRegistered(&tefs[0]));
61 ASSERT_FALSE(self->IsRegistered(&tefs[1]));
62 ASSERT_FALSE(self->IsRegistered(&tefs[2]));
63 }
64 Thread::DCheckUnregisteredEverywhere(&tefs[0], &tefs[2]);
65 }
66
TEST_F(ThreadTest,ThreadExitSignalTest)67 TEST_F(ThreadTest, ThreadExitSignalTest) {
68 Thread* self = Thread::Current();
69 ThreadExitFlag tefs[3];
70 {
71 MutexLock mu(self, *Locks::thread_list_lock_);
72 self->NotifyOnThreadExit(&tefs[2]);
73 ASSERT_TRUE(self->IsRegistered(&tefs[2]));
74 ASSERT_FALSE(self->IsRegistered(&tefs[1]));
75 self->NotifyOnThreadExit(&tefs[1]);
76 ASSERT_TRUE(self->IsRegistered(&tefs[1]));
77 self->SignalExitFlags();
78 ASSERT_TRUE(tefs[1].HasExited());
79 ASSERT_TRUE(tefs[2].HasExited());
80 }
81 Thread::DCheckUnregisteredEverywhere(&tefs[1], &tefs[2]);
82 {
83 MutexLock mu(self, *Locks::thread_list_lock_);
84 self->NotifyOnThreadExit(&tefs[0]);
85 tefs[2].~ThreadExitFlag(); // Destroy and reinitialize.
86 new (&tefs[2]) ThreadExitFlag();
87 self->NotifyOnThreadExit(&tefs[2]);
88 ASSERT_FALSE(tefs[0].HasExited());
89 ASSERT_TRUE(tefs[1].HasExited());
90 ASSERT_FALSE(tefs[2].HasExited());
91 self->SignalExitFlags();
92 ASSERT_TRUE(tefs[0].HasExited());
93 ASSERT_TRUE(tefs[1].HasExited());
94 ASSERT_TRUE(tefs[2].HasExited());
95 }
96 Thread::DCheckUnregisteredEverywhere(&tefs[0], &tefs[2]);
97 }
98
99 } // namespace art
100