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