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