* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "utils.h"
#include <gtest/gtest.h>
#include "log.h"
__attribute__((constructor)) static void Initialize(void)
{
LOGD("srand(time(0)) is called.");
srand(time(nullptr));
}
int CheckValueClose(double target, double actual, double accuracy)
{
double diff = actual - target;
double pct;
if (diff < 0) {
diff = -diff;
}
if (actual == 0) {
return 0;
} else {
pct = diff / actual;
}
LOGD("diff=%f, pct=%f\n", diff, pct);
return (pct <= accuracy);
}
const int SYS_US_PER_MS = 1000;
void Msleep(int msec)
{
usleep(msec * SYS_US_PER_MS);
}
int KeepRun(int msec)
{
struct timespec time1 = { 0, 0 };
struct timespec time2 = { 0, 0 };
clock_gettime(CLOCK_MONOTONIC, &time1);
LOGD("KeepRun start : tv_sec=%ld, tv_nsec=%ld\n", time1.tv_sec, time1.tv_nsec);
int loop = 0;
int runned = 0;
int sectomsec = 1000;
int nsectomsec = 1000000;
while (runned < msec) {
++loop;
clock_gettime(CLOCK_MONOTONIC, &time2);
runned = (time2.tv_sec - time1.tv_sec) * sectomsec + (time2.tv_nsec - time1.tv_nsec) / nsectomsec;
}
LOGD("KeepRun end : tv_sec=%ld, tv_nsec=%ld\n", time2.tv_sec, time2.tv_nsec);
return loop;
}
int CheckProcStatus(pid_t pid, int *code, int flag)
{
int status;
int rt = waitpid(pid, &status, flag);
errno = 0;
int errorcode = -2;
if (rt == -1) {
LOGE("waitpid return -1, errno=%d:%s\n", errno, strerror(errno));
return -1;
} else if (rt == 0) {
return 0;
} else if (rt != pid) {
if (errno) {
LOGE("waitpid return error, rt=%d, errno=%d:%s\n", rt, errno, strerror(errno));
} else {
LOGE("waitpid return error, errno is not set(no more info)\n");
}
return errorcode;
}
if (code == nullptr) {
return -1;
}
int num2 = 2;
int num3 = 3;
int num4 = 4;
if (WIFEXITED(status)) {
*code = WEXITSTATUS(status);
return 1;
} else if (WIFSIGNALED(status)) {
*code = WTERMSIG(status);
return num2;
} else if (WIFSTOPPED(status)) {
*code = WSTOPSIG(status);
return num3;
}
return num4;
}
void AssertProcAlive(pid_t pid)
{
int exitCode;
int procStat = CheckProcStatus(pid, &exitCode);
ASSERT_EQ(procStat, 0) << "target process should still alive.\n";
}
void ExpectProcAlive(pid_t pid)
{
int exitCode;
int procStat = CheckProcStatus(pid, &exitCode);
EXPECT_EQ(procStat, 0) << "target process should still alive.\n";
}
void AssertProcExitedOK(pid_t pid)
{
int exitCode;
int processExistd = 1;
int procStat = CheckProcStatus(pid, &exitCode);
EXPECT_EQ(procStat, processExistd);
ASSERT_EQ(exitCode, 0) << "target process should exited 0.\n";
}
void ExpectProcExitedOK(pid_t pid)
{
int exitCode;
int processExistd = 1;
int procStat = CheckProcStatus(pid, &exitCode);
EXPECT_EQ(procStat, processExistd);
EXPECT_EQ(exitCode, 0) << "target process should exited 0.\n";
}
void WaitProcExitedOK(pid_t pid)
{
int exitCode;
int processExistd = 1;
int procStat = CheckProcStatus(pid, &exitCode, 0);
EXPECT_EQ(procStat, processExistd);
EXPECT_EQ(exitCode, 0) << "target process should exited 0.\n";
}
void ExpectProcKilled(pid_t pid, int signum)
{
int exitCode;
int killedBySignal = 2;
int procStat = CheckProcStatus(pid, &exitCode);
EXPECT_EQ(procStat, killedBySignal);
EXPECT_EQ(exitCode, signum) << "target process should killed by " << signum;
}
void AssertProcKilled(pid_t pid, int signum)
{
int exitCode;
int killedBySignal = 2;
int procStat = CheckProcStatus(pid, &exitCode);
EXPECT_EQ(procStat, killedBySignal);
EXPECT_EQ(exitCode, signum) << "target process should killed by " << signum;
}
void WaitProcKilled(pid_t pid, int signum)
{
int exitCode;
int killedBySignal = 2;
int procStat = CheckProcStatus(pid, &exitCode, 0);
ASSERT_EQ(procStat, killedBySignal) << "target process should killed by " << signum;
ASSERT_EQ(exitCode, signum) << "target process should killed by " << signum;
}
static int StartElf(const char *fname, char * const argv[], char * const envp[])
{
int pid = fork();
if (pid == -1) {
LOGE("ERROR: Fork Error, errno=%d, err=%s\n", errno, strerror(errno));
return -1;
} else if (pid == 0) {
errno = 0;
int rt = execve(fname, argv, envp);
if (rt == -1) {
LOGE("ERROR: execve return -1, errno=%d, err=%s\n", errno, strerror(errno));
_Exit(EXECVE_RETURN_ERROR);
}
LOGE("ERROR: execve should never return on success. rt=%d, errno=%d, err=%s\n", rt, errno, strerror(errno));
_Exit(EXECVE_RETURN_OK);
}
return pid;
}
int RunElf(const char *fname, char * const argv[], char * const envp[], int timeoutSec)
{
int isTimeout = 0;
int exitCode;
sigset_t set;
sigset_t origMask;
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
if (sigprocmask(SIG_BLOCK, &set, &origMask) < 0) {
LOG("sigprocmask");
}
int pid = StartElf(fname, argv, envp);
if (pid == -1) {
return -1;
}
if (timeoutSec > 0) {
struct timespec time1 = { timeoutSec, 0 };
if (sigtimedwait(&set, nullptr, &time1) == -1) {
if (errno == EAGAIN) {
isTimeout = 1;
} else {
LOGE("ERROR: sigtimedwait FAIL: %s\n", strerror(errno));
return -1;
}
if (kill(pid, SIGTERM) == -1) {
LOGE("ERROR: kill child FAIL: %s\n", strerror(errno));
return -1;
}
}
}
int errorcode1 = -1;
int errorcode2 = -2;
int rt = CheckProcStatus(pid, &exitCode, 0);
if ((rt <= 0) || (exitCode == EXECVE_RETURN_OK) || (exitCode == EXECVE_RETURN_ERROR)) {
return errorcode1;
}
if (isTimeout) {
LOGE("ERROR: child execute timed out!\n");
return errorcode2;
}
return exitCode;
}
int StartExecveError(const char *fname, char * const argv[], char * const envp[])
{
int sleeptime = 30;
pid_t pid = fork();
if (pid == -1) {
LOGE("ERROR: Fork Error, errno=%d, err=%s\n", errno, strerror(errno));
return -1;
} else if (pid == 0) {
int rt = execve(fname, argv, envp);
if (rt == -1) {
LOG("ERROR: execve return -1, errno=%d, err=%s\n", errno, strerror(errno));
_Exit(errno);
}
LOGE("ERROR: execve should never return on success. rt=%d, errno=%d, err=%s\n", rt, errno, strerror(errno));
_Exit(EXECVE_RETURN_OK);
}
Msleep(sleeptime);
int exitCode;
int errorcode1 = -2;
int errorcode2 = -3;
int procStat = CheckProcStatus(pid, &exitCode);
LOG("procStat=%d, exitCode=%d\n", procStat, exitCode);
if (procStat != 1) {
return errorcode2;
} else if (exitCode == EXECVE_RETURN_OK) {
return errorcode1;
} else {
return exitCode;
}
}
pid_t GetNonExistPid()
{
int sleeptime5 = 5;
int sleeptime20 = 20;
pid_t pid = fork();
if (pid < 0) {
LOG("fork error, wait 5 seconds than try angain...");
sleep(sleeptime5);
pid = fork();
if (pid < 0) {
LOG("still fork error!");
return -1;
}
}
if (pid > 0) {
Msleep(sleeptime20);
if (waitpid(pid, nullptr, 0) != pid) {
LOG("waitpid failed, errno = %d", errno);
return -1;
}
} else {
_Exit(0);
}
return pid;
}
uint32_t GetRandom(uint32_t max)
{
int fd;
int r = 0;
if (max == 0 || max == 1) {
return 1;
}
fd = open("/dev/random", O_RDONLY);
if (fd == -1) {
LOG("open /dev/random failed, errno = %d", errno);
}
if (read(fd, &r, sizeof(int)) == -1) {
LOG("read failed, errno = %d", errno);
}
if (close(fd) == -1) {
LOG("close failed, errno = %d", errno);
}
return (r % max) + 1;
}
void GetDelayedTime(struct timespec *ts, unsigned int ms)
{
const unsigned int nsecPerSec = 1000000000;
unsigned int setTimeNs = ms * 1000000;
struct timespec tsNow = { 0 };
clock_gettime(CLOCK_REALTIME, &tsNow);
ts->tv_sec = tsNow.tv_sec + (tsNow.tv_nsec + setTimeNs) / nsecPerSec;
ts->tv_nsec = (tsNow.tv_nsec + setTimeNs) % nsecPerSec;
}
int GetTimeDiff(struct timespec ts1, struct timespec ts2)
{
const unsigned int nsecPerSec = 1000000000;
const unsigned int nsectomsec = 1000000;
int ms = (ts1.tv_sec - ts2.tv_sec) * nsecPerSec + (ts1.tv_nsec - ts2.tv_nsec);
ms = ms / nsectomsec;
return ms;
}
int GetCpuCount(void)
{
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
int temp = sched_getaffinity(getpid(), sizeof(cpu_set_t), &cpuset);
if (temp != 0) {
printf("%s %d Error : %d\n", __FUNCTION__, __LINE__, temp);
}
return CPU_COUNT(&cpuset);
}
int FixCurProcessToOneCpu(int cpuIndex, cpu_set_t *pOldMask)
{
int ret;
cpu_set_t setMask;
CPU_ZERO(pOldMask);
ret = sched_getaffinity(0, sizeof(cpu_set_t), pOldMask);
if (ret != 0) {
LOG("sched_getaffinity failed, ret = %d", ret);
return -1;
}
if (CPU_ISSET(0, pOldMask)) {
LOG("before affinity cpu is 0");
}
if (CPU_ISSET(1, pOldMask)) {
LOG("before affinity cpu is 1");
}
CPU_ZERO(&setMask);
CPU_SET(cpuIndex, &setMask);
LOG("fix cpu to %d", cpuIndex);
ret = sched_setaffinity(0, sizeof(setMask), &setMask);
if (ret != 0) {
LOG("sched_setaffinity failed, ret = %d", ret);
return -1;
}
return 0;
}