• 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     EcmaContext::MountContext(thread);
129     JSNApi::EnableUserUncaughtErrorHandler(vm_);
130     RegisterGlobalTemplate(vm_, TerminateThread, Fail, Signal);
131     TryCatch tryCatch(vm_);
132     std::string baseFileName = MODULE_ABC_PATH "termination_1.abc";
133     JSNApi::Execute(vm_, baseFileName, "termination_1");
134     EXPECT_TRUE(tryCatch.HasCaught());
135     EcmaContext::UnmountContext(thread);
136 }
137 
HWTEST_F_L0(ThreadTerminationTest,TerminateFromOtherThread)138 HWTEST_F_L0(ThreadTerminationTest, TerminateFromOtherThread)
139 {
140     JSThread *thread = vm_->GetAssociatedJSThread();
141     EcmaContext::MountContext(thread);
142     TerminatorThread terminatorThread(vm_);
143     terminatorThread.Run();
144     JSNApi::EnableUserUncaughtErrorHandler(vm_);
145     RegisterGlobalTemplate(vm_, TerminateThread, Fail, Signal);
146     TryCatch tryCatch(vm_);
147     std::string baseFileName = MODULE_ABC_PATH "termination_2.abc";
148     JSNApi::Execute(vm_, baseFileName, "termination_2");
149     EXPECT_TRUE(tryCatch.HasCaught());
150     terminatorThread.Join();
151     EcmaContext::UnmountContext(thread);
152 }
153 
HWTEST_F_L0(ThreadTerminationTest,TerminateFromOtherThreadWithoutCall)154 HWTEST_F_L0(ThreadTerminationTest, TerminateFromOtherThreadWithoutCall)
155 {
156     JSThread *thread = vm_->GetAssociatedJSThread();
157     EcmaContext::MountContext(thread);
158     TerminatorThread terminatorThread(vm_);
159     terminatorThread.RunWithSleep();
160     JSNApi::EnableUserUncaughtErrorHandler(vm_);
161     RegisterGlobalTemplate(vm_, TerminateThread, Fail, Signal);
162     TryCatch tryCatch(vm_);
163     std::string baseFileName = MODULE_ABC_PATH "termination_3.abc";
164     JSNApi::Execute(vm_, baseFileName, "termination_3");
165     EXPECT_TRUE(tryCatch.HasCaught());
166     terminatorThread.Join();
167     EcmaContext::UnmountContext(thread);
168 }
169 
HWTEST_F_L0(ThreadTerminationTest,TerminateClearArrayJoinStack)170 HWTEST_F_L0(ThreadTerminationTest, TerminateClearArrayJoinStack)
171 {
172     JSThread *thread = vm_->GetAssociatedJSThread();
173     EcmaContext::MountContext(thread);
174     JSNApi::EnableUserUncaughtErrorHandler(vm_);
175     RegisterGlobalTemplate(vm_, TerminateThread, Fail, Signal);
176     TryCatch tryCatch(vm_);
177     std::string baseFileName = MODULE_ABC_PATH "termination_4.abc";
178     JSNApi::Execute(vm_, baseFileName, "termination_4");
179     EXPECT_TRUE(tryCatch.HasCaught());
180     EcmaContext::UnmountContext(thread);
181 }
182 
HWTEST_F_L0(ThreadTerminationTest,TerminateInMicroTask)183 HWTEST_F_L0(ThreadTerminationTest, TerminateInMicroTask)
184 {
185     JSThread *thread = vm_->GetAssociatedJSThread();
186     EcmaContext::MountContext(thread);
187     JSNApi::EnableUserUncaughtErrorHandler(vm_);
188     RegisterGlobalTemplate(vm_, TerminateThread, Fail, Signal);
189     TryCatch tryCatch(vm_);
190     std::string baseFileName = MODULE_ABC_PATH "termination_5.abc";
191     JSNApi::Execute(vm_, baseFileName, "termination_5");
192     EcmaContext::UnmountContext(thread);
193 }
194 
HWTEST_F_L0(ThreadTerminationTest,TerminateWithoutExecutingMicroTask)195 HWTEST_F_L0(ThreadTerminationTest, TerminateWithoutExecutingMicroTask)
196 {
197     JSThread *thread = vm_->GetAssociatedJSThread();
198     EcmaContext::MountContext(thread);
199     JSNApi::EnableUserUncaughtErrorHandler(vm_);
200     RegisterGlobalTemplate(vm_, TerminateThread, Fail, Signal);
201     TryCatch tryCatch(vm_);
202     std::string baseFileName = MODULE_ABC_PATH "termination_6.abc";
203     JSNApi::Execute(vm_, baseFileName, "termination_6");
204     EXPECT_TRUE(tryCatch.HasCaught());
205     EcmaContext::UnmountContext(thread);
206 }
207 } // namespace panda::test
208