• 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 #include <gtest/gtest.h>
16 #include <thread>
17 #include <cstring>
18 #include <cstdio>
19 #include <fstream>
20 #include <algorithm>
21 #include <sched.h>
22 #include <unistd.h>
23 #include <sys/syscall.h>
24 #include <sys/resource.h>
25 #include "c/thread.h"
26 #include "sync/perf_counter.h"
27 #include "sync/wait_queue.h"
28 
29 #define private public
30 #include "eu/cpu_worker.h"
31 #undef private
32 #include "../common.h"
33 
34 using namespace testing;
35 #ifdef HWTEST_TESTING_EXT_ENABLE
36 using namespace testing::ext;
37 #endif
38 using namespace ffrt;
39 #ifdef APP_USE_ARM
40 static const size_t WORKER_STACK_SIZE = 131072;
41 #else
42 static const size_t WORKER_STACK_SIZE = 10 * 1024 * 1024;
43 #endif
44 
45 class CpuWorkerTest : public testing::Test {
46 protected:
SetUpTestCase()47     static void SetUpTestCase()
48     {
49     }
50 
TearDownTestCase()51     static void TearDownTestCase()
52     {
53     }
54 
SetUp()55     void SetUp() override
56     {
57     }
58 
TearDown()59     void TearDown() override
60     {
61     }
62 
MockStart(void * arg)63     static void* MockStart(void* arg)
64     {
65         int* inc = reinterpret_cast<int*>(arg);
66         (*inc) += 1;
67         return nullptr;
68     }
69 };
70 
71 static int g_counter = 0;
SimpleThdFunc(void *)72 int SimpleThdFunc(void *)
73 {
74     g_counter++;
75     return 0;
76 }
77 
TempFunc(void *)78 static void* TempFunc(void *)
79 {
80     ++g_counter;
81     return nullptr;
82 }
83 
WorkerIdleAction(CPUWorker * thread)84 WorkerAction WorkerIdleAction(CPUWorker *thread)
85 {
86     return WorkerAction::RETRY;
87 }
88  /* a flag used to stall main thread till the worker is done. This prevents UAF */
89 std::atomic<bool> workerDone = false;
WorkerRetired(CPUWorker * thread)90 void WorkerRetired(CPUWorker* thread)
91 {
92     thread->SetExited();
93     thread->Detach();
94     /* worker is done, set flag to true */
95     workerDone = true;
96 }
WaitForWorker()97 void WaitForWorker()
98 {
99     /* Stall till worker is done to prevent UAF */
100     while (!workerDone) {
101         // spin till the worker is done
102     }
103 }
104 
WorkerPrepare(CPUWorker * thread)105 void WorkerPrepare(CPUWorker* thread)
106 {
107 }
108 
109 #ifdef FFRT_WORKERS_DYNAMIC_SCALING
IsBlockAwareInit()110 bool IsBlockAwareInit()
111 {
112     return true;
113 }
114 #endif
115 
116 HWTEST_F(CpuWorkerTest, WorkerStatusTest, TestSize.Level0)
117 {
118     CpuWorkerOps ops;
119     ops.WorkerIdleAction = WorkerIdleAction;
120     ops.WorkerRetired = WorkerRetired;
121     ops.WorkerPrepare = WorkerPrepare;
122 #ifdef FFRT_WORKERS_DYNAMIC_SCALING
123     ops.IsBlockAwareInit = IsBlockAwareInit;
124 #endif
125     workerDone = false;
126     auto worker = std::make_unique<CPUWorker>(QoS(6), std::move(ops), 1024);
127     WorkerStatus status = worker->GetWorkerState();
128     EXPECT_EQ(WorkerStatus::EXECUTING, status);
129     worker->SetExited();
130     WaitForWorker();
131 }
132 
133 HWTEST_F(CpuWorkerTest, SetWorkerStatusTest, TestSize.Level0)
134 {
135     CpuWorkerOps ops;
136     ops.WorkerIdleAction = WorkerIdleAction;
137     ops.WorkerRetired = WorkerRetired;
138     ops.WorkerPrepare = WorkerPrepare;
139 #ifdef FFRT_WORKERS_DYNAMIC_SCALING
140     ops.IsBlockAwareInit = IsBlockAwareInit;
141 #endif
142     workerDone = false;
143     auto worker = std::make_unique<CPUWorker>(QoS(6), std::move(ops), 1024);
144     worker->SetWorkerState(WorkerStatus::SLEEPING);
145     EXPECT_EQ(WorkerStatus::SLEEPING, worker->state);
146     worker->SetExited();
147     WaitForWorker();
148 }
149 
150 HWTEST_F(CpuWorkerTest, ExitedTest, TestSize.Level0)
151 {
152     CpuWorkerOps ops;
153     ops.WorkerIdleAction = WorkerIdleAction;
154     ops.WorkerRetired = WorkerRetired;
155     ops.WorkerPrepare = WorkerPrepare;
156 #ifdef FFRT_WORKERS_DYNAMIC_SCALING
157     ops.IsBlockAwareInit = IsBlockAwareInit;
158 #endif
159     workerDone = false;
160     auto worker = std::make_unique<CPUWorker>(QoS(6), std::move(ops), 1024);
161     bool ret = worker->Exited();
162     EXPECT_FALSE(ret);
163     worker->SetExited();
164     WaitForWorker();
165 }
166 
167 HWTEST_F(CpuWorkerTest, SetExitedTest, TestSize.Level0)
168 {
169     CpuWorkerOps ops;
170     ops.WorkerIdleAction = WorkerIdleAction;
171     ops.WorkerRetired = WorkerRetired;
172     ops.WorkerPrepare = WorkerPrepare;
173 #ifdef FFRT_WORKERS_DYNAMIC_SCALING
174     ops.IsBlockAwareInit = IsBlockAwareInit;
175 #endif
176     workerDone = false;
177     auto worker = std::make_unique<CPUWorker>(QoS(6), std::move(ops), 1024);
178     worker->SetExited();
179     EXPECT_TRUE(worker->exited.load());
180     WaitForWorker();
181 }
182 
183 HWTEST_F(CpuWorkerTest, GetQosTest, TestSize.Level0)
184 {
185     CpuWorkerOps ops;
186     ops.WorkerIdleAction = WorkerIdleAction;
187     ops.WorkerRetired = WorkerRetired;
188     ops.WorkerPrepare = WorkerPrepare;
189 #ifdef FFRT_WORKERS_DYNAMIC_SCALING
190     ops.IsBlockAwareInit = IsBlockAwareInit;
191 #endif
192     workerDone = false;
193     auto qos = QoS(6);
194     auto worker = std::make_unique<CPUWorker>(qos, std::move(ops), 1024);
195     EXPECT_EQ(worker->GetQos(), qos);
196     worker->SetExited();
197     WaitForWorker();
198 }
199