1 /*
2 * Copyright (c) 2020-2021 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 #ifndef _GNU_SOURCE
17 #define _GNU_SOURCE
18 #endif
19
20 #include "utils.h"
21 #include <gtest/gtest.h>
22 #include "log.h"
23
24 // init rand seed at startup
Initialize(void)25 __attribute__((constructor)) static void Initialize(void)
26 {
27 LOGD("srand(time(0)) is called.");
28 srand(time(nullptr));
29 }
30
CheckValueClose(double target,double actual,double accuracy)31 int CheckValueClose(double target, double actual, double accuracy)
32 {
33 double diff = actual - target;
34 double pct;
35 if (diff < 0) {
36 diff = -diff;
37 }
38 if(actual == 0) {
39 return 0;
40 }else {
41 pct = diff / actual;
42 }
43 LOGD("diff=%f, pct=%f\n", diff, pct);
44 return (pct <= accuracy);
45 }
46
47 const int SYS_US_PER_MS = 1000;
Msleep(int msec)48 void Msleep(int msec)
49 {
50 usleep(msec * SYS_US_PER_MS);
51 }
52
KeepRun(int msec)53 int KeepRun(int msec)
54 {
55 struct timespec time1 = { 0, 0 };
56 struct timespec time2 = { 0, 0 };
57 clock_gettime(CLOCK_MONOTONIC, &time1);
58 LOGD("KeepRun start : tv_sec=%ld, tv_nsec=%ld\n", time1.tv_sec, time1.tv_nsec);
59 int loop = 0;
60 int runned = 0;
61 while (runned < msec) {
62 ++loop;
63 clock_gettime(CLOCK_MONOTONIC, &time2);
64 runned = (time2.tv_sec - time1.tv_sec) * 1000 + (time2.tv_nsec - time1.tv_nsec) / 1000000;
65 }
66 LOGD("KeepRun end : tv_sec=%ld, tv_nsec=%ld\n", time2.tv_sec, time2.tv_nsec);
67 return loop;
68 }
69
70 // check process state use 'waitpid'
CheckProcStatus(pid_t pid,int * code,int flag)71 int CheckProcStatus(pid_t pid, int *code, int flag)
72 {
73 int status;
74 int rt = waitpid(pid, &status, flag);
75 errno = 0;
76 if (rt == -1) {
77 LOGE("waitpid return -1, errno=%d:%s\n", errno, strerror(errno));
78 return -1;
79 } else if (rt == 0) {
80 return 0;
81 } else if (rt != pid) { // waitpid return error
82 if (errno) {
83 LOGE("waitpid return error, rt=%d, errno=%d:%s\n", rt, errno, strerror(errno));
84 } else {
85 LOGE("waitpid return error, errno is not set(no more info)\n");
86 }
87 return -2;
88 }
89 if (code == nullptr) {
90 return -1;
91 }
92
93 if (WIFEXITED(status)) {
94 *code = WEXITSTATUS(status);
95 return 1;
96 } else if (WIFSIGNALED(status)) {
97 *code = WTERMSIG(status);
98 return 2;
99 } else if (WIFSTOPPED(status)) {
100 *code = WSTOPSIG(status);
101 return 3;
102 }
103 return 4;
104 }
105
106 // start a elf, only check if execve success or not
StartElf(const char * fname,char * const argv[],char * const envp[])107 static int StartElf(const char *fname, char * const argv[], char * const envp[])
108 {
109 int pid = fork();
110 if (pid == -1) {
111 LOGE("ERROR: Fork Error, errno=%d, err=%s\n", errno, strerror(errno));
112 return -1;
113 } else if (pid == 0) { // child
114 errno = 0;
115 int rt = execve(fname, argv, envp);
116 if (rt == -1) {
117 LOGE("ERROR: execve return -1, errno=%d, err=%s\n", errno, strerror(errno));
118 exit(EXECVE_RETURN_ERROR);
119 }
120 LOGE("ERROR: execve should never return on success. rt=%d, errno=%d, err=%s\n", rt, errno, strerror(errno));
121 exit(EXECVE_RETURN_OK);
122 }
123 return pid;
124 }
125
RunElf(const char * fname,char * const argv[],char * const envp[],int timeoutSec)126 int RunElf(const char *fname, char * const argv[], char * const envp[], int timeoutSec)
127 {
128 int isTimeout = 0;
129 int exitCode;
130 sigset_t set;
131 sigemptyset(&set);
132 sigaddset(&set, SIGCHLD);
133
134 int pid = StartElf(fname, argv, envp);
135 if (pid == -1) { // fork error
136 return -1;
137 }
138
139 if (timeoutSec > 0) {
140 struct timespec time1 = { timeoutSec, 0 };
141 if (sigtimedwait(&set, nullptr, &time1) == -1) {
142 if (errno == EAGAIN) {
143 isTimeout = 1;
144 } else {
145 LOGE("ERROR: sigtimedwait FAIL: %s\n", strerror(errno));
146 return -1;
147 }
148 if (kill(pid, SIGKILL) == -1) {
149 LOGE("ERROR: kill child FAIL: %s\n", strerror(errno));
150 return -1;
151 }
152 }
153 // else: sigtimedwait return ok, child has exited already, nothing else to do
154 }
155 int rt = CheckProcStatus(pid, &exitCode, 0);
156 if ((rt <= 0) || (exitCode == EXECVE_RETURN_OK) || (exitCode == EXECVE_RETURN_ERROR)) {
157 return -1;
158 }
159 if (isTimeout) {
160 LOGE("ERROR: child execute timed out!\n");
161 return -2;
162 }
163 return exitCode;
164 }
165
StartExecveError(const char * fname,char * const argv[],char * const envp[])166 int StartExecveError(const char *fname, char * const argv[], char * const envp[])
167 {
168 pid_t pid = fork();
169 if (pid == -1) {
170 LOGE("ERROR: Fork Error, errno=%d, err=%s\n", errno, strerror(errno));
171 return -1;
172 } else if (pid == 0) { // child
173 int rt = execve(fname, argv, envp);
174 if (rt == -1) {
175 LOG("ERROR: execve return -1, errno=%d, err=%s\n", errno, strerror(errno));
176 exit(errno);
177 }
178 LOGE("ERROR: execve should never return on success. rt=%d, errno=%d, err=%s\n", rt, errno, strerror(errno));
179 exit(EXECVE_RETURN_OK);
180 }
181 // parent
182 Msleep(30);
183 int exitCode;
184 int procStat = CheckProcStatus(pid, &exitCode);
185 LOG("procStat=%d, exitCode=%d\n", procStat, exitCode);
186 if (procStat != 1) {
187 return -3;
188 } else if (exitCode == EXECVE_RETURN_OK) {
189 return -2;
190 } else {
191 return exitCode;
192 }
193 }
194
195 // Get a pid number that currently not exist
196 // by creat a child process and exit.
GetNonExistPid()197 pid_t GetNonExistPid()
198 {
199 pid_t pid = fork();
200 if (pid < 0) {
201 LOG("fork error, wait 5 seconds than try angain...");
202 sleep(5);
203 pid = fork();
204 if (pid < 0) {
205 LOG("still fork error!");
206 return -1;
207 }
208 }
209 if (pid > 0) { // parent
210 Msleep(20);
211 if (waitpid(pid, nullptr, 0) != pid) {
212 LOG("waitpid failed, errno = %d", errno);
213 return -1;
214 }
215 } else { // child
216 exit(0);
217 }
218 return pid;
219 }
220
221 // return n: 0 < n <= max
GetRandom(uint32_t max)222 uint32_t GetRandom(uint32_t max)
223 {
224 if (max == 0 || max == 1) {
225 return 1;
226 }
227 return (rand() % max) + 1;
228 }
229
230 // get cur-time plus ms
GetDelayedTime(struct timespec * ts,unsigned int ms)231 void GetDelayedTime(struct timespec *ts, unsigned int ms)
232 {
233 const unsigned int nsecPerSec = 1000000000;
234 unsigned int setTimeNs = ms * 1000000;
235 struct timespec tsNow = { 0 };
236 clock_gettime(CLOCK_REALTIME, &tsNow);
237 ts->tv_sec = tsNow.tv_sec + (tsNow.tv_nsec + setTimeNs) / nsecPerSec;
238 ts->tv_nsec = (tsNow.tv_nsec + setTimeNs) % nsecPerSec;
239 }
240
241 // calculate time difference, in ms
GetTimeDiff(struct timespec ts1,struct timespec ts2)242 int GetTimeDiff(struct timespec ts1, struct timespec ts2)
243 {
244 const unsigned int nsecPerSec = 1000000000;
245 int ms = (ts1.tv_sec - ts2.tv_sec) * nsecPerSec + (ts1.tv_nsec - ts2.tv_nsec);
246 ms = ms / 1000000;
247 return ms;
248 }
249
GetCpuCount(void)250 int GetCpuCount(void)
251 {
252 cpu_set_t cpuset;
253
254 CPU_ZERO(&cpuset);
255 int temp = sched_getaffinity(getpid(), sizeof(cpu_set_t), &cpuset);
256 if (temp != 0) {
257 printf("%s %d Error : %d\n", __FUNCTION__, __LINE__, temp);
258 }
259
260 return CPU_COUNT(&cpuset);
261 }
262
FixCurProcessToOneCpu(int cpuIndex,cpu_set_t * pOldMask)263 int FixCurProcessToOneCpu(int cpuIndex, cpu_set_t *pOldMask)
264 {
265 int ret;
266 cpu_set_t setMask;
267 CPU_ZERO(pOldMask);
268 ret = sched_getaffinity(0, sizeof(cpu_set_t), pOldMask);
269 if (ret != 0) {
270 LOG("sched_getaffinity failed, ret = %d", ret);
271 return -1;
272 }
273 if (CPU_ISSET(0, pOldMask)) {
274 LOG("before affinity cpu is 0");
275 }
276 if (CPU_ISSET(1, pOldMask)) {
277 LOG("before affinity cpu is 1");
278 }
279 CPU_ZERO(&setMask);
280 CPU_SET(cpuIndex, &setMask);
281 LOG("fix cpu to %d", cpuIndex);
282 ret = sched_setaffinity(0, sizeof(setMask), &setMask);
283 if (ret != 0) {
284 LOG("sched_setaffinity failed, ret = %d", ret);
285 return -1;
286 }
287 return 0;
288 }