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 "utils.h"
17#include <gtest/gtest.h>
18#include "log.h"
19
20
21// init rand seed at startup
22__attribute__((constructor)) static void Initialize(void)
23{
24    LOGD("srand(time(0)) is called.");
25    srand(time(nullptr));
26}
27
28int CheckValueClose(double target, double actual, double accuracy)
29{
30    double diff = actual - target;
31    double pct;
32    if (diff < 0) {
33        diff = -diff;
34    }
35    if (actual == 0) {
36        return 0;
37    } else {
38        pct = diff / actual;
39    }
40    LOGD("diff=%f, pct=%f\n", diff, pct);
41    return (pct <= accuracy);
42}
43
44const int SYS_US_PER_MS = 1000;
45void Msleep(int msec)
46{
47    usleep(msec * SYS_US_PER_MS);
48}
49
50int KeepRun(int msec)
51{
52    struct timespec time1 = { 0, 0 };
53    struct timespec time2 = { 0, 0 };
54    clock_gettime(CLOCK_MONOTONIC, &time1);
55    LOGD("KeepRun start : tv_sec=%ld, tv_nsec=%ld\n", time1.tv_sec, time1.tv_nsec);
56    int loop = 0;
57    int runned = 0;
58    int sectomsec = 1000;
59    int nsectomsec = 1000000;
60    while (runned < msec) {
61        ++loop;
62        clock_gettime(CLOCK_MONOTONIC, &time2);
63        runned = (time2.tv_sec - time1.tv_sec) * sectomsec + (time2.tv_nsec - time1.tv_nsec) / nsectomsec;
64    }
65    LOGD("KeepRun end : tv_sec=%ld, tv_nsec=%ld\n", time2.tv_sec, time2.tv_nsec);
66    return loop;
67}
68
69// check process state use 'waitpid'
70int CheckProcStatus(pid_t pid, int *code, int flag)
71{
72    int status;
73    int rt = waitpid(pid, &status, flag);
74    errno = 0;
75    int errorcode = -2;
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 errorcode;
88    }
89    if (code == nullptr) {
90        return -1;
91    }
92    int num2 = 2;
93    int num3 = 3;
94    int num4 = 4;
95    if (WIFEXITED(status)) {
96        *code = WEXITSTATUS(status);
97        return 1;
98    } else if (WIFSIGNALED(status)) {
99        *code = WTERMSIG(status);
100        return num2;
101    } else if (WIFSTOPPED(status)) {
102        *code = WSTOPSIG(status);
103        return num3;
104    }
105    return num4;
106}
107void AssertProcAlive(pid_t pid)
108{
109    int exitCode;
110    int procStat = CheckProcStatus(pid, &exitCode);
111    ASSERT_EQ(procStat, 0) << "target process should still alive.\n";
112}
113
114void ExpectProcAlive(pid_t pid)
115{
116    int exitCode;
117    int procStat = CheckProcStatus(pid, &exitCode);
118    EXPECT_EQ(procStat, 0) << "target process should still alive.\n";
119}
120
121void AssertProcExitedOK(pid_t pid)
122{
123    int exitCode;
124    int processExistd = 1;
125    int procStat = CheckProcStatus(pid, &exitCode);
126    EXPECT_EQ(procStat, processExistd);
127    ASSERT_EQ(exitCode, 0) << "target process should exited 0.\n";
128}
129
130void ExpectProcExitedOK(pid_t pid)
131{
132    int exitCode;
133    int processExistd = 1;
134    int procStat = CheckProcStatus(pid, &exitCode);
135    EXPECT_EQ(procStat, processExistd);
136    EXPECT_EQ(exitCode, 0) << "target process should exited 0.\n";
137}
138
139void WaitProcExitedOK(pid_t pid)
140{
141    int exitCode;
142    int processExistd = 1;
143    int procStat = CheckProcStatus(pid, &exitCode, 0);
144    EXPECT_EQ(procStat, processExistd);
145    EXPECT_EQ(exitCode, 0) << "target process should exited 0.\n";
146}
147
148void ExpectProcKilled(pid_t pid, int signum)
149{
150    int exitCode;
151    int killedBySignal = 2;
152    int procStat = CheckProcStatus(pid, &exitCode);
153    EXPECT_EQ(procStat, killedBySignal);
154    EXPECT_EQ(exitCode, signum) << "target process should killed by " << signum;
155}
156
157void AssertProcKilled(pid_t pid, int signum)
158{
159    int exitCode;
160    int killedBySignal = 2;
161    int procStat = CheckProcStatus(pid, &exitCode);
162    EXPECT_EQ(procStat, killedBySignal);
163    EXPECT_EQ(exitCode, signum) << "target process should killed by " << signum;
164}
165
166void WaitProcKilled(pid_t pid, int signum)
167{
168    int exitCode;
169    int killedBySignal = 2;
170    int procStat = CheckProcStatus(pid, &exitCode, 0);
171    ASSERT_EQ(procStat, killedBySignal) << "target process should killed by " << signum;
172    ASSERT_EQ(exitCode, signum) << "target process should killed by " << signum;
173}
174// start an elf, only check if execve success or not
175static int StartElf(const char *fname, char * const argv[], char * const envp[])
176{
177    int pid = fork();
178    if (pid == -1) {
179        LOGE("ERROR: Fork Error, errno=%d, err=%s\n", errno, strerror(errno));
180        return -1;
181    } else if (pid == 0) { // child
182        errno = 0;
183        int rt = execve(fname, argv, envp);
184        if (rt == -1) {
185            LOGE("ERROR: execve return -1, errno=%d, err=%s\n", errno, strerror(errno));
186            _Exit(EXECVE_RETURN_ERROR);
187        }
188        LOGE("ERROR: execve should never return on success. rt=%d, errno=%d, err=%s\n", rt, errno, strerror(errno));
189        _Exit(EXECVE_RETURN_OK);
190    }
191    return pid;
192}
193
194int RunElf(const char *fname, char * const argv[], char * const envp[], int timeoutSec)
195{
196    int isTimeout = 0;
197    int exitCode;
198    sigset_t set;
199    sigset_t origMask;
200    sigemptyset(&set);
201    sigaddset(&set, SIGCHLD);
202
203    if (sigprocmask(SIG_BLOCK, &set, &origMask) < 0) {
204        LOG("sigprocmask");
205    }
206    int pid = StartElf(fname, argv, envp);
207    if (pid == -1) { // fork error
208        return -1;
209    }
210
211    if (timeoutSec > 0) {
212        struct timespec time1 = { timeoutSec, 0 };
213        if (sigtimedwait(&set, nullptr, &time1) == -1) {
214            if (errno == EAGAIN) {
215                isTimeout = 1;
216            } else {
217                LOGE("ERROR: sigtimedwait FAIL: %s\n", strerror(errno));
218                return -1;
219            }
220            if (kill(pid, SIGTERM) == -1) {
221                LOGE("ERROR: kill child FAIL: %s\n", strerror(errno));
222                return -1;
223            }
224        }
225        // else: sigtimedwait return ok, child has exited already, nothing else to do
226    }
227    int errorcode1 = -1;
228    int errorcode2 = -2;
229    int rt = CheckProcStatus(pid, &exitCode, 0);
230    if ((rt <= 0) || (exitCode == EXECVE_RETURN_OK) || (exitCode == EXECVE_RETURN_ERROR)) {
231        return errorcode1;
232    }
233    if (isTimeout) {
234        LOGE("ERROR: child execute timed out!\n");
235        return errorcode2;
236    }
237    return exitCode;
238}
239
240int StartExecveError(const char *fname, char * const argv[], char * const envp[])
241{
242    int sleeptime = 30;
243    pid_t pid = fork();
244    if (pid == -1) {
245        LOGE("ERROR: Fork Error, errno=%d, err=%s\n", errno, strerror(errno));
246        return -1;
247    } else if (pid == 0) { // child
248        int rt = execve(fname, argv, envp);
249        if (rt == -1) {
250            LOG("ERROR: execve return -1, errno=%d, err=%s\n", errno, strerror(errno));
251            _Exit(errno);
252        }
253        LOGE("ERROR: execve should never return on success. rt=%d, errno=%d, err=%s\n", rt, errno, strerror(errno));
254        _Exit(EXECVE_RETURN_OK);
255    }
256    // parent
257    Msleep(sleeptime);
258    int exitCode;
259    int errorcode1 = -2;
260    int errorcode2 = -3;
261    int procStat = CheckProcStatus(pid, &exitCode);
262    LOG("procStat=%d, exitCode=%d\n", procStat, exitCode);
263    if (procStat != 1) {
264        return errorcode2;
265    } else if (exitCode == EXECVE_RETURN_OK) {
266        return errorcode1;
267    } else {
268        return exitCode;
269    }
270}
271
272// Get a pid number that currently not exist
273// by creat a child process and exit.
274pid_t GetNonExistPid()
275{
276    int sleeptime5 = 5;
277    int sleeptime20 = 20;
278    pid_t pid = fork();
279    if (pid < 0) {
280        LOG("fork error, wait 5 seconds than try angain...");
281        sleep(sleeptime5);
282        pid = fork();
283        if (pid < 0) {
284            LOG("still fork error!");
285            return -1;
286        }
287    }
288    if (pid > 0) { // parent
289        Msleep(sleeptime20);
290        if (waitpid(pid, nullptr, 0) != pid) {
291            LOG("waitpid failed, errno = %d", errno);
292            return -1;
293        }
294    } else { // child
295        _Exit(0);
296    }
297    return pid;
298}
299
300// return n: 0 < n <= max
301uint32_t GetRandom(uint32_t max)
302{
303    int fd;
304    int r = 0;
305    if (max == 0 || max == 1) {
306        return 1;
307    }
308    fd = open("/dev/random", O_RDONLY);
309    if (fd == -1) {
310        LOG("open /dev/random failed, errno = %d", errno);
311    }
312    if (read(fd, &r, sizeof(int)) == -1) {
313        LOG("read failed, errno = %d", errno);
314    }
315    if (close(fd) == -1) {
316        LOG("close failed, errno = %d", errno);
317    }
318    return (r % max) + 1;
319}
320
321// get cur-time plus ms
322void GetDelayedTime(struct timespec *ts, unsigned int ms)
323{
324    const unsigned int nsecPerSec = 1000000000;
325    unsigned int setTimeNs = ms * 1000000;
326    struct timespec tsNow = { 0 };
327    clock_gettime(CLOCK_REALTIME, &tsNow);
328    ts->tv_sec = tsNow.tv_sec + (tsNow.tv_nsec + setTimeNs) / nsecPerSec;
329    ts->tv_nsec = (tsNow.tv_nsec + setTimeNs) % nsecPerSec;
330}
331
332// calculate time difference, in ms
333int GetTimeDiff(struct timespec ts1, struct timespec ts2)
334{
335    const unsigned int nsecPerSec = 1000000000;
336    const unsigned int nsectomsec = 1000000;
337    int ms = (ts1.tv_sec - ts2.tv_sec) * nsecPerSec + (ts1.tv_nsec - ts2.tv_nsec);
338    ms = ms / nsectomsec;
339    return ms;
340}
341
342int GetCpuCount(void)
343{
344    cpu_set_t cpuset;
345
346    CPU_ZERO(&cpuset);
347    int temp = sched_getaffinity(getpid(), sizeof(cpu_set_t), &cpuset);
348    if (temp != 0) {
349        printf("%s %d Error : %d\n", __FUNCTION__, __LINE__, temp);
350    }
351
352    return CPU_COUNT(&cpuset);
353}
354
355int FixCurProcessToOneCpu(int cpuIndex, cpu_set_t *pOldMask)
356{
357    int ret;
358    cpu_set_t setMask;
359    CPU_ZERO(pOldMask);
360    ret = sched_getaffinity(0, sizeof(cpu_set_t), pOldMask);
361    if (ret != 0) {
362        LOG("sched_getaffinity failed, ret = %d", ret);
363        return -1;
364    }
365    if (CPU_ISSET(0, pOldMask)) {
366        LOG("before affinity cpu is 0");
367    }
368    if (CPU_ISSET(1, pOldMask)) {
369        LOG("before affinity cpu is 1");
370    }
371    CPU_ZERO(&setMask);
372    CPU_SET(cpuIndex, &setMask);
373    LOG("fix cpu to %d", cpuIndex);
374    ret = sched_setaffinity(0, sizeof(setMask), &setMask);
375    if (ret != 0) {
376        LOG("sched_setaffinity failed, ret = %d", ret);
377        return -1;
378    }
379    return 0;
380}
381