xref: /test/xts/acts/kernel_lite/utils/utils.cpp (revision f6603c60)
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
25__attribute__((constructor)) static void Initialize(void)
26{
27    LOGD("srand(time(0)) is called.");
28    srand(time(nullptr));
29}
30
31int 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
47const int SYS_US_PER_MS = 1000;
48void Msleep(int msec)
49{
50    usleep(msec * SYS_US_PER_MS);
51}
52
53int 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'
71int 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
107static 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
126int 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
169int 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.
200pid_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
225uint32_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
234void 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
245int 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
253int 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
266int 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