• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 an 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, orig_mask;
131     sigemptyset(&set);
132     sigaddset(&set, SIGCHLD);
133 
134     if (sigprocmask(SIG_BLOCK, &set, &orig_mask) < 0) {
135         LOG("sigprocmask");
136     }
137     int pid = StartElf(fname, argv, envp);
138     if (pid == -1) { // fork error
139         return -1;
140     }
141 
142     if (timeoutSec > 0) {
143         struct timespec time1 = { timeoutSec, 0 };
144         if (sigtimedwait(&set, nullptr, &time1) == -1) {
145             if (errno == EAGAIN) {
146                 isTimeout = 1;
147             } else {
148                 LOGE("ERROR: sigtimedwait FAIL: %s\n", strerror(errno));
149                 return -1;
150             }
151             if (kill(pid, SIGKILL) == -1) {
152                 LOGE("ERROR: kill child FAIL: %s\n", strerror(errno));
153                 return -1;
154             }
155         }
156         // else: sigtimedwait return ok, child has exited already, nothing else to do
157     }
158     int rt = CheckProcStatus(pid, &exitCode, 0);
159     if ((rt <= 0) || (exitCode == EXECVE_RETURN_OK) || (exitCode == EXECVE_RETURN_ERROR)) {
160         return -1;
161     }
162     if (isTimeout) {
163         LOGE("ERROR: child execute timed out!\n");
164         return -2;
165     }
166     return exitCode;
167 }
168 
StartExecveError(const char * fname,char * const argv[],char * const envp[])169 int StartExecveError(const char *fname, char * const argv[], char * const envp[])
170 {
171     pid_t pid = fork();
172     if (pid == -1) {
173         LOGE("ERROR: Fork Error, errno=%d, err=%s\n", errno, strerror(errno));
174         return -1;
175     } else if (pid == 0) { // child
176         int rt = execve(fname, argv, envp);
177         if (rt == -1) {
178             LOG("ERROR: execve return -1, errno=%d, err=%s\n", errno, strerror(errno));
179             exit(errno);
180         }
181         LOGE("ERROR: execve should never return on success. rt=%d, errno=%d, err=%s\n", rt, errno, strerror(errno));
182         exit(EXECVE_RETURN_OK);
183     }
184     // parent
185     Msleep(30);
186     int exitCode;
187     int procStat = CheckProcStatus(pid, &exitCode);
188     LOG("procStat=%d, exitCode=%d\n", procStat, exitCode);
189     if (procStat != 1) {
190         return -3;
191     } else if (exitCode == EXECVE_RETURN_OK) {
192         return -2;
193     } else {
194         return exitCode;
195     }
196 }
197 
198 // Get a pid number that currently not exist
199 // by creat a child process and exit.
GetNonExistPid()200 pid_t GetNonExistPid()
201 {
202     pid_t pid = fork();
203     if (pid < 0) {
204         LOG("fork error, wait 5 seconds than try angain...");
205         sleep(5);
206         pid = fork();
207         if (pid < 0) {
208             LOG("still fork error!");
209             return -1;
210         }
211     }
212     if (pid > 0) { // parent
213         Msleep(20);
214         if (waitpid(pid, nullptr, 0) != pid) {
215             LOG("waitpid failed, errno = %d", errno);
216             return -1;
217         }
218     } else { // child
219         exit(0);
220     }
221     return pid;
222 }
223 
224 // return n: 0 < n <= max
GetRandom(uint32_t max)225 uint32_t GetRandom(uint32_t max)
226 {
227     if (max == 0 || max == 1) {
228         return 1;
229     }
230     return (rand() % max) + 1;
231 }
232 
233 // get cur-time plus ms
GetDelayedTime(struct timespec * ts,unsigned int ms)234 void GetDelayedTime(struct timespec *ts, unsigned int ms)
235 {
236     const unsigned int nsecPerSec = 1000000000;
237     unsigned int setTimeNs = ms * 1000000;
238     struct timespec tsNow = { 0 };
239     clock_gettime(CLOCK_REALTIME, &tsNow);
240     ts->tv_sec = tsNow.tv_sec + (tsNow.tv_nsec + setTimeNs) / nsecPerSec;
241     ts->tv_nsec = (tsNow.tv_nsec + setTimeNs) % nsecPerSec;
242 }
243 
244 // calculate time difference, in ms
GetTimeDiff(struct timespec ts1,struct timespec ts2)245 int GetTimeDiff(struct timespec ts1, struct timespec ts2)
246 {
247     const unsigned int nsecPerSec = 1000000000;
248     int ms = (ts1.tv_sec - ts2.tv_sec) * nsecPerSec + (ts1.tv_nsec - ts2.tv_nsec);
249     ms = ms / 1000000;
250     return ms;
251 }
252 
GetCpuCount(void)253 int GetCpuCount(void)
254 {
255     cpu_set_t cpuset;
256 
257     CPU_ZERO(&cpuset);
258     int temp = sched_getaffinity(getpid(), sizeof(cpu_set_t), &cpuset);
259     if (temp != 0) {
260         printf("%s %d Error : %d\n", __FUNCTION__, __LINE__, temp);
261     }
262 
263     return CPU_COUNT(&cpuset);
264 }
265 
FixCurProcessToOneCpu(int cpuIndex,cpu_set_t * pOldMask)266 int FixCurProcessToOneCpu(int cpuIndex, cpu_set_t *pOldMask)
267 {
268     int ret;
269     cpu_set_t setMask;
270     CPU_ZERO(pOldMask);
271     ret = sched_getaffinity(0, sizeof(cpu_set_t), pOldMask);
272     if (ret != 0) {
273         LOG("sched_getaffinity failed, ret = %d", ret);
274         return -1;
275     }
276     if (CPU_ISSET(0, pOldMask)) {
277         LOG("before affinity cpu is 0");
278     }
279     if (CPU_ISSET(1, pOldMask)) {
280         LOG("before affinity cpu is 1");
281     }
282     CPU_ZERO(&setMask);
283     CPU_SET(cpuIndex, &setMask);
284     LOG("fix cpu to %d", cpuIndex);
285     ret = sched_setaffinity(0, sizeof(setMask), &setMask);
286     if (ret != 0) {
287         LOG("sched_setaffinity failed, ret = %d", ret);
288         return -1;
289     }
290     return 0;
291 }
292