/* * Copyright (c) 2020-2021 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. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include "utils.h" #include #include "log.h" // init rand seed at startup __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; while (runned < msec) { ++loop; clock_gettime(CLOCK_MONOTONIC, &time2); runned = (time2.tv_sec - time1.tv_sec) * 1000 + (time2.tv_nsec - time1.tv_nsec) / 1000000; } LOGD("KeepRun end : tv_sec=%ld, tv_nsec=%ld\n", time2.tv_sec, time2.tv_nsec); return loop; } // check process state use 'waitpid' int CheckProcStatus(pid_t pid, int *code, int flag) { int status; int rt = waitpid(pid, &status, flag); errno = 0; 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) { // waitpid return error 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 -2; } if (code == nullptr) { return -1; } if (WIFEXITED(status)) { *code = WEXITSTATUS(status); return 1; } else if (WIFSIGNALED(status)) { *code = WTERMSIG(status); return 2; } else if (WIFSTOPPED(status)) { *code = WSTOPSIG(status); return 3; } return 4; } // start a elf, only check if execve success or not 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) { // child 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; sigemptyset(&set); sigaddset(&set, SIGCHLD); int pid = StartElf(fname, argv, envp); if (pid == -1) { // fork error 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, SIGKILL) == -1) { LOGE("ERROR: kill child FAIL: %s\n", strerror(errno)); return -1; } } // else: sigtimedwait return ok, child has exited already, nothing else to do } int rt = CheckProcStatus(pid, &exitCode, 0); if ((rt <= 0) || (exitCode == EXECVE_RETURN_OK) || (exitCode == EXECVE_RETURN_ERROR)) { return -1; } if (isTimeout) { LOGE("ERROR: child execute timed out!\n"); return -2; } return exitCode; } int StartExecveError(const char *fname, char * const argv[], char * const envp[]) { 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) { // child 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); } // parent Msleep(30); int exitCode; int procStat = CheckProcStatus(pid, &exitCode); LOG("procStat=%d, exitCode=%d\n", procStat, exitCode); if (procStat != 1) { return -3; } else if (exitCode == EXECVE_RETURN_OK) { return -2; } else { return exitCode; } } // Get a pid number that currently not exist // by creat a child process and exit. pid_t GetNonExistPid() { pid_t pid = fork(); if (pid < 0) { LOG("fork error, wait 5 seconds than try angain..."); sleep(5); pid = fork(); if (pid < 0) { LOG("still fork error!"); return -1; } } if (pid > 0) { // parent Msleep(20); if (waitpid(pid, nullptr, 0) != pid) { LOG("waitpid failed, errno = %d", errno); return -1; } } else { // child exit(0); } return pid; } // return n: 0 < n <= max uint32_t GetRandom(uint32_t max) { if (max == 0 || max == 1) { return 1; } return (rand() % max) + 1; } // get cur-time plus ms 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; } // calculate time difference, in ms int GetTimeDiff(struct timespec ts1, struct timespec ts2) { const unsigned int nsecPerSec = 1000000000; int ms = (ts1.tv_sec - ts2.tv_sec) * nsecPerSec + (ts1.tv_nsec - ts2.tv_nsec); ms = ms / 1000000; 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; }