#include "referer.h" #include "log_util.h" ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // refer refer::refer() : ref_(1) { on_born(); } refer::~refer() { on_dead(); } void refer::on_born(void) {} void refer::on_dead(void) {} int32_t refer::add_ref(void) { LOCKER lock(mutex_); return ++ref_; } int32_t refer::release(void) { int32_t ref = 0; { LOCKER lock(mutex_); ref = --ref_; } if (ref == 0) delete this; return ref; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // chronograph #include chronograph::chronograph() { reset(); } chronograph::~chronograph() {} bool chronograph::now(struct timeval* tv) { struct timezone tz = { 0 }; return gettimeofday(tv, &tz) == 0; } bool chronograph::now(uint64_t* seconds, uint64_t* u_seconds) { struct timeval tv = { 0 }; struct timezone tz = { 0 }; if (gettimeofday(&tv, &tz) == 0) { if (seconds) *seconds = tv.tv_sec; if (u_seconds) *u_seconds = tv.tv_usec; return true; } else { return false; } } std::string chronograph::now(bool with_ms/*whether with milliseconds*/) // return '2022-11-30 10:38:42.123', no '.123' if with_ms was false { struct timeval tv = { 0 }; if (!chronograph::now(&tv)) return ""; char buf[40] = { 0 }; time_t t = tv.tv_sec; struct tm* l = localtime(&t); if (with_ms) sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d.%06d", l->tm_year + 1900, l->tm_mon + 1, l->tm_mday , l->tm_hour, l->tm_min, l->tm_sec, tv.tv_usec); else sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", l->tm_year + 1900, l->tm_mon + 1, l->tm_mday , l->tm_hour, l->tm_min, l->tm_sec); return buf; } uint64_t chronograph::elapse_s(void) { struct timeval tv = { 0 }; chronograph::now(&tv); return tv.tv_sec - bgn_.tv_sec; } uint64_t chronograph::elapse_ms(void) { struct timeval tv = { 0 }; uint64_t dif = 0; chronograph::now(&tv); dif = SEC_2_MS(tv.tv_sec - bgn_.tv_sec); dif += tv.tv_usec / MSEC_2_US(1); dif -= bgn_.tv_usec / MSEC_2_US(1); return dif; } uint64_t chronograph::elapse_us(void) { struct timeval tv = { 0 }; uint64_t dif = 0; chronograph::now(&tv); dif = SEC_2_US(tv.tv_sec - bgn_.tv_sec); dif += tv.tv_usec; dif -= bgn_.tv_usec; return dif; } void chronograph::reset() { chronograph::now(&bgn_); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // sys utility #include #include #include #include namespace sys_util { static bool find_module(const char* path, bool is_dir, void* param) { std::string* para = (std::string*)param; if (para[0].empty()) { para[1] = path; return false; } else { const char* name = strrchr(path, '/'); if (name++ == nullptr) name = path; if (strstr(name, para[0].c_str())) { para[1] = path; return false; } return true; } } typedef struct _enum_proc_cb { bool(*on_found)(uint64_t pid, const char* path_name, void* param); void* param; }ENPROCCB, * LPENPROCCB; static bool found_process(const char* path, bool is_dir, void* param) { LPENPROCCB cb = (LPENPROCCB)param; const char* id = strstr(path + 2, "/"); uint64_t pid = 0; std::string path_name(""); if (id++ == nullptr) { id = path; } while (*id) { if (*id < '0' || *id > '9') break; pid *= 10; pid += *id - '0'; id++; } if (*id) return true; path_name = get_module_path(nullptr, pid); return cb->on_found(pid, path_name.c_str(), cb->param); } int32_t enum_modules(bool(*on_found)(const char* path_module_name, bool is_dir, void* param),// return false to stop enumeratin void* param, // user defined data, passed into callback on_found unsigned pid // process id, -1 is self ) // return errno { char path[128] = { 0 }; if (pid == -1) pid = getpid(); sprintf(path, "/proc/%u/map_files/", pid); return enum_files(path, on_found, param, false); } int32_t enum_files(const char* dir, // dir path bool(*on_found)(const char* path_name, bool is_dir, void* param), // return false to stop enumeratin void* param // user defined data, passed into callback on_found , bool recursive ) // return errno { int32_t ret = 0; DIR* pdir = nullptr; struct dirent* ent = nullptr; pdir = opendir(dir); if (!pdir) return errno; while ((ent = readdir(pdir))) { if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue; std::string file(dir); file += "/"; file += ent->d_name; if ((ent->d_type & DT_DIR) == 0) file = read_link(file.c_str()); if (!on_found(file.c_str(), ent->d_type & DT_DIR, param)) { ret = 0x5e17; break; } if ((ent->d_type & DT_DIR) && recursive) { std::string sub(dir); sub += "/"; sub += ent->d_name; ret = enum_files(sub.c_str(), on_found, param, recursive); if (ret == 0x5e17) break; } } closedir(pdir); return ret == 0x5e17 ? 0 : ret; } int32_t enum_processes(bool(*on_found)(uint64_t pid, const char* path_name, void* param), void* param) { ENPROCCB cb; cb.on_found = on_found; cb.param = param; return enum_files("/proc", found_process, &cb, false); } std::string get_module_path(const char* module_name, unsigned pid) // get module full path, nullptr is for main-exe { std::string param[] = { module_name ? module_name : "", "" }; enum_modules(find_module, param, pid); return param[1]; } std::string read_link(const char* lnk) { char path[512] = { 0 }; readlink(lnk, path, sizeof(path) - 1); return path; } size_t get_page_size(void) { size_t size = sysconf(_SC_PAGESIZE); if (size < 1024 || (size & 0x0fe0000ff)) // nKB && < 16MB size = getpagesize(); return size; } bool create_folder(const char* dir) { bool ret = mkdir(dir, S_IREAD | S_IWRITE | S_IEXEC) == 0 || errno == EEXIST; if(errno == ENOENT) { std::string path(dir), cur(""); size_t pos = path.find("/", 1); while(pos != std::string::npos) { ret = mkdir(path.substr(0, pos).c_str(), S_IREAD | S_IWRITE | S_IEXEC) == 0 || errno == EEXIST; if(!ret) { printf("mkdir(%s) = %d(%s)\n", path.substr(0, pos).c_str(), errno, strerror(errno)); break; } pos = path.find("/", pos + 1); } if(ret) ret = mkdir(path.c_str(), S_IREAD | S_IWRITE | S_IEXEC) == 0; } return ret; } int32_t get_memory_info(uint64_t* total, uint64_t* available) { if (!total && !available) return 0; char line[128] = { 0 }; FILE* src = fopen("/proc/meminfo", "rb"); int32_t count = total && available ? 2 : 1; unsigned long val = 0; if (!src) return log_cls::log_when_err(-1, "fopen('/proc/meminfo', 'rb')", LOG_LEVEL_FATAL); while (fgets(line, sizeof(line) - 1, src)) { if (sscanf(line, "MemTotal: %ld", &val)) { if (total) { *total = val * 1024; if (--count == 0) break; } } else if (sscanf(line, "MemFree: %ld", &val)) { if (available) { *available = val * 1024; if (--count == 0) break; } } } fclose(src); return 0; } std::string format_readable_bytes(uint64_t bytes) { std::string str("\0", 80); if (bytes >= SIZE_GB(1)) { double v = bytes * 1.0f / (SIZE_GB(1)); size_t pos = 0; sprintf(&str[0], "%.2fGB", v); pos = str.find("."); while (pos > 3) { pos -= 3; str.insert(pos, ","); } } else if (bytes >= SIZE_MB(1)) { double v = bytes * 1.0f / (SIZE_MB(1)); sprintf(&str[0], "%.2fMB", v); } else if (bytes >= SIZE_KB(1)) { double v = bytes * 1.0f / (SIZE_KB(1)); sprintf(&str[0], "%.2fKB", v); } else { sprintf(&str[0], "%uB", (unsigned)bytes); } return str; } std::string get_command_output(const char* cmd, uint16_t max_line_len, bool one_line) { FILE* src = popen(cmd, "r"); std::string ret(""); if (src) { char* buf = new char[max_line_len + 4]; if (buf) { memset(buf, 0, max_line_len + 4); fgets(buf, max_line_len, src); ret = buf; while (!one_line && fgets(buf, max_line_len, src)) ret += "\n" + std::string(buf); delete[] buf; } pclose(src); } return ret; } }