2022-05-19 05:11:57 +08:00
|
|
|
#include "common/util.h"
|
2021-05-09 13:15:17 +08:00
|
|
|
|
2022-11-09 05:21:07 +08:00
|
|
|
#include <sys/ioctl.h>
|
2021-08-09 17:56:45 +08:00
|
|
|
#include <sys/stat.h>
|
2021-10-29 18:27:35 +08:00
|
|
|
#include <dirent.h>
|
2021-08-09 17:56:45 +08:00
|
|
|
|
2021-06-01 22:53:12 +08:00
|
|
|
#include <cassert>
|
2021-06-09 04:46:22 +08:00
|
|
|
#include <cerrno>
|
2021-06-01 22:53:12 +08:00
|
|
|
#include <cstring>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <fstream>
|
|
|
|
#include <iomanip>
|
2022-12-13 06:47:27 +08:00
|
|
|
#include <random>
|
2021-10-29 18:27:35 +08:00
|
|
|
#include <sstream>
|
2021-03-09 11:17:46 +08:00
|
|
|
|
2020-01-18 03:01:02 +08:00
|
|
|
#ifdef __linux__
|
|
|
|
#include <sys/prctl.h>
|
|
|
|
#include <sys/syscall.h>
|
2020-10-18 03:40:01 +08:00
|
|
|
#ifndef __USE_GNU
|
2020-06-06 05:09:41 +08:00
|
|
|
#define __USE_GNU
|
2020-01-18 03:01:02 +08:00
|
|
|
#endif
|
2020-10-18 03:40:01 +08:00
|
|
|
#include <sched.h>
|
2021-05-09 13:15:17 +08:00
|
|
|
#endif // __linux__
|
2020-01-18 03:01:02 +08:00
|
|
|
|
2021-12-13 06:42:23 +08:00
|
|
|
namespace util {
|
|
|
|
|
2020-01-18 03:01:02 +08:00
|
|
|
void set_thread_name(const char* name) {
|
|
|
|
#ifdef __linux__
|
|
|
|
// pthread_setname_np is dumb (fails instead of truncates)
|
|
|
|
prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int set_realtime_priority(int level) {
|
|
|
|
#ifdef __linux__
|
|
|
|
long tid = syscall(SYS_gettid);
|
|
|
|
|
|
|
|
// should match python using chrt
|
|
|
|
struct sched_param sa;
|
|
|
|
memset(&sa, 0, sizeof(sa));
|
|
|
|
sa.sched_priority = level;
|
|
|
|
return sched_setscheduler(tid, SCHED_FIFO, &sa);
|
|
|
|
#else
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2021-10-19 04:21:24 +08:00
|
|
|
int set_core_affinity(std::vector<int> cores) {
|
2020-09-02 23:52:41 +08:00
|
|
|
#ifdef __linux__
|
2020-06-06 05:09:41 +08:00
|
|
|
long tid = syscall(SYS_gettid);
|
2021-10-19 04:21:24 +08:00
|
|
|
cpu_set_t cpu;
|
2020-06-06 05:09:41 +08:00
|
|
|
|
2021-10-19 04:21:24 +08:00
|
|
|
CPU_ZERO(&cpu);
|
|
|
|
for (const int n : cores) {
|
|
|
|
CPU_SET(n, &cpu);
|
|
|
|
}
|
|
|
|
return sched_setaffinity(tid, sizeof(cpu), &cpu);
|
2020-06-06 05:09:41 +08:00
|
|
|
#else
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
2021-04-14 02:43:43 +08:00
|
|
|
|
|
|
|
std::string read_file(const std::string& fn) {
|
2021-06-23 04:48:41 +08:00
|
|
|
std::ifstream f(fn, std::ios::binary | std::ios::in);
|
|
|
|
if (f.is_open()) {
|
|
|
|
f.seekg(0, std::ios::end);
|
|
|
|
int size = f.tellg();
|
|
|
|
if (f.good() && size > 0) {
|
|
|
|
std::string result(size, '\0');
|
|
|
|
f.seekg(0, std::ios::beg);
|
|
|
|
f.read(result.data(), size);
|
|
|
|
// return either good() or has reached end-of-file (e.g. /sys/power/wakeup_count)
|
|
|
|
if (f.good() || f.eof()) {
|
|
|
|
result.resize(f.gcount());
|
2021-04-14 04:56:08 +08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
2021-06-23 04:48:41 +08:00
|
|
|
// fallback for files created on read, e.g. procfs
|
|
|
|
std::stringstream buffer;
|
|
|
|
buffer << f.rdbuf();
|
|
|
|
return buffer.str();
|
2021-04-14 02:43:43 +08:00
|
|
|
}
|
2021-06-23 04:48:41 +08:00
|
|
|
return std::string();
|
2021-04-14 02:43:43 +08:00
|
|
|
}
|
|
|
|
|
2021-08-02 16:59:54 +08:00
|
|
|
std::map<std::string, std::string> read_files_in_dir(const std::string &path) {
|
|
|
|
std::map<std::string, std::string> ret;
|
2021-05-12 17:15:54 +08:00
|
|
|
DIR *d = opendir(path.c_str());
|
2021-08-02 16:59:54 +08:00
|
|
|
if (!d) return ret;
|
2021-05-12 17:15:54 +08:00
|
|
|
|
|
|
|
struct dirent *de = NULL;
|
|
|
|
while ((de = readdir(d))) {
|
2021-09-02 06:10:59 +08:00
|
|
|
if (de->d_type != DT_DIR) {
|
2021-08-02 16:59:54 +08:00
|
|
|
ret[de->d_name] = util::read_file(path + "/" + de->d_name);
|
2021-05-12 17:15:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-15 08:33:46 +08:00
|
|
|
closedir(d);
|
2021-08-02 16:59:54 +08:00
|
|
|
return ret;
|
2021-05-12 17:15:54 +08:00
|
|
|
}
|
|
|
|
|
2021-04-14 02:43:43 +08:00
|
|
|
int write_file(const char* path, const void* data, size_t size, int flags, mode_t mode) {
|
2021-09-01 07:22:56 +08:00
|
|
|
int fd = HANDLE_EINTR(open(path, flags, mode));
|
2021-04-14 02:43:43 +08:00
|
|
|
if (fd == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
2021-09-01 07:22:56 +08:00
|
|
|
ssize_t n = HANDLE_EINTR(write(fd, data, size));
|
2021-04-14 02:43:43 +08:00
|
|
|
close(fd);
|
|
|
|
return (n >= 0 && (size_t)n == size) ? 0 : -1;
|
|
|
|
}
|
|
|
|
|
2021-10-29 19:23:31 +08:00
|
|
|
FILE* safe_fopen(const char* filename, const char* mode) {
|
|
|
|
FILE* fp = NULL;
|
|
|
|
do {
|
|
|
|
fp = fopen(filename, mode);
|
|
|
|
} while ((nullptr == fp) && (errno == EINTR));
|
|
|
|
return fp;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t safe_fwrite(const void* ptr, size_t size, size_t count, FILE* stream) {
|
|
|
|
size_t written = 0;
|
|
|
|
do {
|
|
|
|
size_t ret = ::fwrite((void*)((char *)ptr + written * size), size, count - written, stream);
|
|
|
|
if (ret == 0 && errno != EINTR) break;
|
|
|
|
written += ret;
|
|
|
|
} while (written != count);
|
|
|
|
return written;
|
|
|
|
}
|
|
|
|
|
|
|
|
int safe_fflush(FILE *stream) {
|
|
|
|
int ret = EOF;
|
|
|
|
do {
|
|
|
|
ret = fflush(stream);
|
|
|
|
} while ((EOF == ret) && (errno == EINTR));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-11-09 05:21:07 +08:00
|
|
|
int safe_ioctl(int fd, unsigned long request, void *argp) {
|
|
|
|
int ret;
|
|
|
|
do {
|
|
|
|
ret = ioctl(fd, request, argp);
|
|
|
|
} while ((ret == -1) && (errno == EINTR));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-06-01 22:53:12 +08:00
|
|
|
std::string readlink(const std::string &path) {
|
|
|
|
char buff[4096];
|
|
|
|
ssize_t len = ::readlink(path.c_str(), buff, sizeof(buff)-1);
|
|
|
|
if (len != -1) {
|
|
|
|
buff[len] = '\0';
|
|
|
|
return std::string(buff);
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
bool file_exists(const std::string& fn) {
|
2021-08-09 17:56:45 +08:00
|
|
|
struct stat st = {};
|
|
|
|
return stat(fn.c_str(), &st) != -1;
|
2021-06-01 22:53:12 +08:00
|
|
|
}
|
|
|
|
|
2021-10-29 18:27:35 +08:00
|
|
|
static bool createDirectory(std::string dir, mode_t mode) {
|
|
|
|
auto verify_dir = [](const std::string& dir) -> bool {
|
|
|
|
struct stat st = {};
|
|
|
|
return (stat(dir.c_str(), &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR);
|
|
|
|
};
|
|
|
|
// remove trailing /'s
|
|
|
|
while (dir.size() > 1 && dir.back() == '/') {
|
|
|
|
dir.pop_back();
|
|
|
|
}
|
|
|
|
// try to mkdir this directory
|
|
|
|
if (mkdir(dir.c_str(), mode) == 0) return true;
|
|
|
|
if (errno == EEXIST) return verify_dir(dir);
|
|
|
|
if (errno != ENOENT) return false;
|
|
|
|
|
|
|
|
// mkdir failed because the parent dir doesn't exist, so try to create it
|
|
|
|
size_t slash = dir.rfind('/');
|
|
|
|
if ((slash == std::string::npos || slash < 1) ||
|
|
|
|
!createDirectory(dir.substr(0, slash), mode)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// try again
|
|
|
|
if (mkdir(dir.c_str(), mode) == 0) return true;
|
|
|
|
return errno == EEXIST && verify_dir(dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool create_directories(const std::string& dir, mode_t mode) {
|
|
|
|
if (dir.empty()) return false;
|
|
|
|
return createDirectory(dir, mode);
|
|
|
|
}
|
|
|
|
|
2023-05-24 01:02:22 +08:00
|
|
|
std::string getenv(const char* key, std::string default_val) {
|
2021-08-04 19:29:03 +08:00
|
|
|
const char* val = ::getenv(key);
|
|
|
|
return val ? val : default_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
int getenv(const char* key, int default_val) {
|
|
|
|
const char* val = ::getenv(key);
|
|
|
|
return val ? atoi(val) : default_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
float getenv(const char* key, float default_val) {
|
|
|
|
const char* val = ::getenv(key);
|
|
|
|
return val ? atof(val) : default_val;
|
2021-06-01 22:53:12 +08:00
|
|
|
}
|
|
|
|
|
2021-11-04 23:18:01 +08:00
|
|
|
std::string hexdump(const uint8_t* in, const size_t size) {
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << std::hex << std::setfill('0');
|
|
|
|
for (size_t i = 0; i < size; i++) {
|
|
|
|
ss << std::setw(2) << static_cast<unsigned int>(in[i]);
|
2021-06-01 22:53:12 +08:00
|
|
|
}
|
2021-11-04 23:18:01 +08:00
|
|
|
return ss.str();
|
2021-06-01 22:53:12 +08:00
|
|
|
}
|
|
|
|
|
2022-12-13 06:47:27 +08:00
|
|
|
std::string random_string(std::string::size_type length) {
|
2023-08-11 18:46:47 +08:00
|
|
|
const std::string chrs = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
2022-12-13 06:47:27 +08:00
|
|
|
std::mt19937 rg{std::random_device{}()};
|
2023-08-11 18:46:47 +08:00
|
|
|
std::uniform_int_distribution<std::string::size_type> pick(0, chrs.length() - 1);
|
2022-12-13 06:47:27 +08:00
|
|
|
std::string s;
|
|
|
|
s.reserve(length);
|
|
|
|
while (length--) {
|
|
|
|
s += chrs[pick(rg)];
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2021-06-01 22:53:12 +08:00
|
|
|
std::string dir_name(std::string const &path) {
|
|
|
|
size_t pos = path.find_last_of("/");
|
|
|
|
if (pos == std::string::npos) return "";
|
|
|
|
return path.substr(0, pos);
|
|
|
|
}
|
|
|
|
|
2021-11-10 23:07:22 +08:00
|
|
|
std::string check_output(const std::string& command) {
|
|
|
|
char buffer[128];
|
|
|
|
std::string result;
|
|
|
|
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(command.c_str(), "r"), pclose);
|
|
|
|
|
|
|
|
if (!pipe) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
while (fgets(buffer, std::size(buffer), pipe.get()) != nullptr) {
|
|
|
|
result += std::string(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-06-11 16:17:52 +08:00
|
|
|
struct tm get_time() {
|
2021-06-01 22:53:12 +08:00
|
|
|
time_t rawtime;
|
|
|
|
time(&rawtime);
|
|
|
|
|
|
|
|
struct tm sys_time;
|
|
|
|
gmtime_r(&rawtime, &sys_time);
|
|
|
|
|
|
|
|
return sys_time;
|
|
|
|
}
|
|
|
|
|
2021-06-11 16:17:52 +08:00
|
|
|
bool time_valid(struct tm sys_time) {
|
2021-06-01 22:53:12 +08:00
|
|
|
int year = 1900 + sys_time.tm_year;
|
|
|
|
int month = 1 + sys_time.tm_mon;
|
2023-06-13 04:50:38 +08:00
|
|
|
return (year > 2023) || (year == 2023 && month >= 6);
|
2021-06-01 22:53:12 +08:00
|
|
|
}
|
2021-05-12 17:15:54 +08:00
|
|
|
|
2021-04-14 02:43:43 +08:00
|
|
|
} // namespace util
|