1 /**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "gtest/gtest.h"
17 #include "runtime/include/runtime.h"
18
19 namespace panda::test {
20
21 class ThreadTest : public testing::Test {
22 public:
23 MTManagedThread *thread;
ThreadTest()24 ThreadTest()
25 {
26 RuntimeOptions options;
27 options.SetShouldLoadBootPandaFiles(false);
28 options.SetShouldInitializeIntrinsics(false);
29 /*
30 * gtest ASSERT_DEATH doesn't work with multiple threads:
31 * "In particular, death tests don't like having multiple threads in the parent process"
32 * turn off gc-thread & compiler-thread here, because we use a lot of ASSERT_DEATH and test can hang.
33 */
34 options.SetCompilerEnableJit(false);
35 options.SetGcType("epsilon");
36 Logger::InitializeStdLogging(Logger::Level::ERROR, 0);
37 Runtime::Create(options);
38 thread = MTManagedThread::GetCurrent();
39 }
40
~ThreadTest()41 ~ThreadTest() override
42 {
43 Runtime::Destroy();
44 }
45
AssertNative() const46 void AssertNative() const
47 {
48 ASSERT_TRUE(thread->IsInNativeCode());
49 ASSERT_FALSE(thread->IsManagedCode());
50 }
51
AssertManaged() const52 void AssertManaged() const
53 {
54 ASSERT_FALSE(thread->IsInNativeCode());
55 ASSERT_TRUE(thread->IsManagedCode());
56 }
57
BeginToStateAndEnd(MTManagedThread::ThreadState state) const58 void BeginToStateAndEnd(MTManagedThread::ThreadState state) const
59 {
60 if (state == MTManagedThread::ThreadState::NATIVE_CODE) {
61 thread->NativeCodeBegin();
62 AssertNative();
63 thread->NativeCodeEnd();
64 } else if (state == MTManagedThread::ThreadState::MANAGED_CODE) {
65 thread->ManagedCodeBegin();
66 AssertManaged();
67 thread->ManagedCodeEnd();
68 } else {
69 UNREACHABLE();
70 }
71 }
72 };
73
74 /**
75 * call stack:
76 *
77 * native #0
78 * managed #1
79 * native #2
80 * access #3
81 * access #4
82 *
83 */
TEST_F(ThreadTest,LegalThreadStatesTest)84 TEST_F(ThreadTest, LegalThreadStatesTest)
85 {
86 AssertNative();
87 thread->ManagedCodeBegin(); // #1
88 AssertManaged();
89 thread->NativeCodeBegin(); // #2
90 AssertNative();
91
92 thread->NativeCodeEnd(); // #2
93 AssertManaged();
94 thread->ManagedCodeEnd(); // #1
95 AssertNative();
96 }
97
TEST_F(ThreadTest,BeginForbiddenStatesFromNativeFrame)98 TEST_F(ThreadTest, BeginForbiddenStatesFromNativeFrame)
99 {
100 testing::FLAGS_gtest_death_test_style = "fast";
101
102 AssertNative();
103 #ifndef NDEBUG
104 ASSERT_DEATH(thread->NativeCodeBegin(), "last frame is: NATIVE_CODE");
105 #endif
106 AssertNative();
107 }
108
TEST_F(ThreadTest,BeginForbiddenStatesFromManagedFrame)109 TEST_F(ThreadTest, BeginForbiddenStatesFromManagedFrame)
110 {
111 testing::FLAGS_gtest_death_test_style = "fast";
112
113 AssertNative();
114 thread->ManagedCodeBegin();
115 AssertManaged();
116 #ifndef NDEBUG
117 ASSERT_DEATH(thread->ManagedCodeBegin(), "last frame is: MANAGED_CODE");
118 #endif
119 AssertManaged();
120 thread->ManagedCodeEnd();
121 AssertNative();
122 }
123
TEST_F(ThreadTest,EndNativeStateByOtherStates)124 TEST_F(ThreadTest, EndNativeStateByOtherStates)
125 {
126 testing::FLAGS_gtest_death_test_style = "fast";
127
128 AssertNative();
129
130 #ifndef NDEBUG
131 ASSERT_DEATH(thread->ManagedCodeEnd(), "last frame is: NATIVE_CODE");
132 ASSERT_DEATH(thread->ManagedCodeEnd(), "last frame is: NATIVE_CODE");
133 #endif
134 }
135
TEST_F(ThreadTest,EndManagedStateByOtherStates)136 TEST_F(ThreadTest, EndManagedStateByOtherStates)
137 {
138 testing::FLAGS_gtest_death_test_style = "fast";
139
140 AssertNative();
141 thread->ManagedCodeBegin();
142
143 #ifndef NDEBUG
144 ASSERT_DEATH(thread->NativeCodeEnd(), "last frame is: MANAGED_CODE");
145 #endif
146 thread->ManagedCodeEnd();
147 }
148
TEST_F(ThreadTest,TestAllConversions)149 TEST_F(ThreadTest, TestAllConversions)
150 {
151 testing::FLAGS_gtest_death_test_style = "fast";
152
153 // from NATIVE_CODE
154 AssertNative();
155 #ifndef NDEBUG
156 ASSERT_DEATH(BeginToStateAndEnd(MTManagedThread::ThreadState::NATIVE_CODE), "last frame is: NATIVE_CODE");
157 #endif
158 BeginToStateAndEnd(MTManagedThread::ThreadState::MANAGED_CODE);
159
160 // from MANAGED_CODE
161 thread->ManagedCodeBegin();
162 AssertManaged();
163
164 BeginToStateAndEnd(MTManagedThread::ThreadState::NATIVE_CODE);
165 #ifndef NDEBUG
166 ASSERT_DEATH(BeginToStateAndEnd(MTManagedThread::ThreadState::MANAGED_CODE), "last frame is: MANAGED_CODE");
167 #endif
168 thread->ManagedCodeEnd();
169 AssertNative();
170 }
171 } // namespace panda::test
172