• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 <condition_variable>
17 
18 #include "ecmascript/napi/include/dfx_jsnapi.h"
19 #include "ecmascript/napi/include/jsnapi.h"
20 #include "ecmascript/tests/test_helper.h"
21 
22 namespace panda::test {
23 using namespace panda;
24 using namespace panda::ecmascript;
25 using FunctionCallbackInfo = Local<JSValueRef>(*)(JsiRuntimeCallInfo *);
26 std::condition_variable g_semaphore;
27 
28 class ThreadTerminationTest : public testing::Test {
29 public:
SetUpTestCase()30     static void SetUpTestCase()
31     {
32         GTEST_LOG_(INFO) << "SetUpTestCase";
33     }
34 
TearDownTestCase()35     static void TearDownTestCase()
36     {
37         GTEST_LOG_(INFO) << "TearDownCase";
38     }
39 
SetUp()40     void SetUp() override
41     {
42         TestHelper::CreateEcmaVMWithScope(vm_, thread_, scope_);
43     }
44 
TearDown()45     void TearDown() override
46     {
47         TestHelper::DestroyEcmaVMWithScope(vm_, scope_);
48     }
49 
50     static Local<JSValueRef> TerminateThread(JsiRuntimeCallInfo *runtimeCallInfo);
51     static Local<JSValueRef> Fail(JsiRuntimeCallInfo *runtimeCallInfo);
52     static Local<JSValueRef> Signal(JsiRuntimeCallInfo *runtimeCallInfo);
53 
RegisterGlobalTemplate(const EcmaVM * vm,FunctionCallbackInfo terminate,FunctionCallbackInfo fail,FunctionCallbackInfo signal)54     static void RegisterGlobalTemplate(const EcmaVM *vm, FunctionCallbackInfo terminate, FunctionCallbackInfo fail,
55                                        FunctionCallbackInfo signal)
56     {
57         [[maybe_unused]] EcmaHandleScope handleScope(vm->GetJSThread());
58         Local<ObjectRef> globalObj = JSNApi::GetGlobalObject(vm);
59         globalObj->Set(vm, StringRef::NewFromUtf8(vm, "terminate"), FunctionRef::New(
60             const_cast<panda::EcmaVM*>(vm), terminate));
61         globalObj->Set(vm, StringRef::NewFromUtf8(vm, "fail"), FunctionRef::New(
62             const_cast<panda::EcmaVM*>(vm), fail));
63         globalObj->Set(vm, StringRef::NewFromUtf8(vm, "signal"), FunctionRef::New(
64             const_cast<panda::EcmaVM*>(vm), Signal));
65     }
66 
67 protected:
68     EcmaVM *vm_ {nullptr};
69     JSThread *thread_ = {nullptr};
70     EcmaHandleScope *scope_ {nullptr};
71 };
72 
73 class TerminatorThread {
74 public:
TerminatorThread(EcmaVM * vm)75     explicit TerminatorThread(EcmaVM *vm) : vm_(vm) {}
76     ~TerminatorThread() = default;
77 
Run()78     void Run()
79     {
80         thread_ = std::thread([this]() {
81             std::unique_lock<std::mutex> lock(mutex_);
82             g_semaphore.wait(lock);
83             DFXJSNApi::TerminateExecution(vm_);
84         });
85     }
86 
RunWithSleep()87     void RunWithSleep()
88     {
89         thread_ = std::thread([this]() {
90             usleep(1000000); // 1000000 : 1s for loop to execute
91             DFXJSNApi::TerminateExecution(vm_);
92         });
93     }
94 
Join()95     void Join()
96     {
97         thread_.join();
98     }
99 
100 private:
101     EcmaVM *vm_ {nullptr};
102     std::mutex mutex_;
103     std::thread thread_;
104 };
105 
TerminateThread(JsiRuntimeCallInfo * runtimeCallInfo)106 Local<JSValueRef> ThreadTerminationTest::TerminateThread(JsiRuntimeCallInfo *runtimeCallInfo)
107 {
108     EcmaVM *vm = runtimeCallInfo->GetVM();
109     DFXJSNApi::TerminateExecution(vm);
110     return JSValueRef::Undefined(vm);
111 }
112 
Fail(JsiRuntimeCallInfo * runtimeCallInfo)113 Local<JSValueRef> ThreadTerminationTest::Fail([[maybe_unused]]JsiRuntimeCallInfo *runtimeCallInfo)
114 {
115     UNREACHABLE();
116 }
117 
Signal(JsiRuntimeCallInfo * runtimeCallInfo)118 Local<JSValueRef> ThreadTerminationTest::Signal(JsiRuntimeCallInfo *runtimeCallInfo)
119 {
120     EcmaVM *vm = runtimeCallInfo->GetVM();
121     g_semaphore.notify_one();
122     return JSValueRef::Undefined(vm);
123 }
124 
HWTEST_F_L0(ThreadTerminationTest,TerminateFromThreadItself)125 HWTEST_F_L0(ThreadTerminationTest, TerminateFromThreadItself)
126 {
127     JSThread *thread = vm_->GetAssociatedJSThread();
128     auto* factory = vm_->GetFactory();
129     JSHandle<GlobalEnv> globalEnv = factory->NewGlobalEnv();
130     SaveAndSwitchEnv(thread, globalEnv);
131     JSNApi::EnableUserUncaughtErrorHandler(vm_);
132     RegisterGlobalTemplate(vm_, TerminateThread, Fail, Signal);
133     TryCatch tryCatch(vm_);
134     std::string baseFileName = MODULE_ABC_PATH "termination_1.abc";
135     JSNApi::Execute(vm_, baseFileName, "termination_1");
136     EXPECT_TRUE(tryCatch.HasCaught());
137 }
138 
HWTEST_F_L0(ThreadTerminationTest,TerminateFromOtherThread)139 HWTEST_F_L0(ThreadTerminationTest, TerminateFromOtherThread)
140 {
141     JSThread *thread = vm_->GetAssociatedJSThread();
142     auto* factory = vm_->GetFactory();
143     JSHandle<GlobalEnv> globalEnv = factory->NewGlobalEnv();
144     SaveAndSwitchEnv(thread, globalEnv);
145     TerminatorThread terminatorThread(vm_);
146     terminatorThread.Run();
147     JSNApi::EnableUserUncaughtErrorHandler(vm_);
148     RegisterGlobalTemplate(vm_, TerminateThread, Fail, Signal);
149     TryCatch tryCatch(vm_);
150     std::string baseFileName = MODULE_ABC_PATH "termination_2.abc";
151     JSNApi::Execute(vm_, baseFileName, "termination_2");
152     EXPECT_TRUE(tryCatch.HasCaught());
153     terminatorThread.Join();
154 }
155 
HWTEST_F_L0(ThreadTerminationTest,TerminateFromOtherThreadWithoutCall)156 HWTEST_F_L0(ThreadTerminationTest, TerminateFromOtherThreadWithoutCall)
157 {
158     JSThread *thread = vm_->GetAssociatedJSThread();
159     auto* factory = vm_->GetFactory();
160     JSHandle<GlobalEnv> globalEnv = factory->NewGlobalEnv();
161     SaveAndSwitchEnv(thread, globalEnv);
162     TerminatorThread terminatorThread(vm_);
163     terminatorThread.RunWithSleep();
164     JSNApi::EnableUserUncaughtErrorHandler(vm_);
165     RegisterGlobalTemplate(vm_, TerminateThread, Fail, Signal);
166     TryCatch tryCatch(vm_);
167     std::string baseFileName = MODULE_ABC_PATH "termination_3.abc";
168     JSNApi::Execute(vm_, baseFileName, "termination_3");
169     EXPECT_TRUE(tryCatch.HasCaught());
170     terminatorThread.Join();
171 }
172 
HWTEST_F_L0(ThreadTerminationTest,TerminateClearArrayJoinStack)173 HWTEST_F_L0(ThreadTerminationTest, TerminateClearArrayJoinStack)
174 {
175     JSThread *thread = vm_->GetAssociatedJSThread();
176     auto* factory = vm_->GetFactory();
177     JSHandle<GlobalEnv> globalEnv = factory->NewGlobalEnv();
178     SaveAndSwitchEnv(thread, globalEnv);
179     JSNApi::EnableUserUncaughtErrorHandler(vm_);
180     RegisterGlobalTemplate(vm_, TerminateThread, Fail, Signal);
181     TryCatch tryCatch(vm_);
182     std::string baseFileName = MODULE_ABC_PATH "termination_4.abc";
183     JSNApi::Execute(vm_, baseFileName, "termination_4");
184     EXPECT_TRUE(tryCatch.HasCaught());
185 }
186 
HWTEST_F_L0(ThreadTerminationTest,TerminateInMicroTask)187 HWTEST_F_L0(ThreadTerminationTest, TerminateInMicroTask)
188 {
189     JSThread *thread = vm_->GetAssociatedJSThread();
190     auto* factory = vm_->GetFactory();
191     JSHandle<GlobalEnv> globalEnv = factory->NewGlobalEnv();
192     SaveAndSwitchEnv(thread, globalEnv);
193     JSNApi::EnableUserUncaughtErrorHandler(vm_);
194     RegisterGlobalTemplate(vm_, TerminateThread, Fail, Signal);
195     TryCatch tryCatch(vm_);
196     std::string baseFileName = MODULE_ABC_PATH "termination_5.abc";
197     JSNApi::Execute(vm_, baseFileName, "termination_5");
198 }
199 
HWTEST_F_L0(ThreadTerminationTest,TerminateWithoutExecutingMicroTask)200 HWTEST_F_L0(ThreadTerminationTest, TerminateWithoutExecutingMicroTask)
201 {
202     JSThread *thread = vm_->GetAssociatedJSThread();
203     auto* factory = vm_->GetFactory();
204     JSHandle<GlobalEnv> globalEnv = factory->NewGlobalEnv();
205     SaveAndSwitchEnv(thread, globalEnv);
206     JSNApi::EnableUserUncaughtErrorHandler(vm_);
207     RegisterGlobalTemplate(vm_, TerminateThread, Fail, Signal);
208     TryCatch tryCatch(vm_);
209     std::string baseFileName = MODULE_ABC_PATH "termination_6.abc";
210     JSNApi::Execute(vm_, baseFileName, "termination_6");
211     EXPECT_TRUE(tryCatch.HasCaught());
212 }
213 } // namespace panda::test
214