util.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #include "common/util.h"
  2. #include <sys/ioctl.h>
  3. #include <sys/stat.h>
  4. #include <sys/resource.h>
  5. #include <cassert>
  6. #include <cerrno>
  7. #include <cstring>
  8. #include <dirent.h>
  9. #include <fstream>
  10. #include <iomanip>
  11. #include <random>
  12. #include <sstream>
  13. #ifdef __linux__
  14. #include <sys/prctl.h>
  15. #include <sys/syscall.h>
  16. #ifndef __USE_GNU
  17. #define __USE_GNU
  18. #endif
  19. #include <sched.h>
  20. #endif // __linux__
  21. namespace util {
  22. void set_thread_name(const char* name) {
  23. #ifdef __linux__
  24. // pthread_setname_np is dumb (fails instead of truncates)
  25. prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
  26. #endif
  27. }
  28. int set_realtime_priority(int level) {
  29. #ifdef __linux__
  30. long tid = syscall(SYS_gettid);
  31. // should match python using chrt
  32. struct sched_param sa;
  33. memset(&sa, 0, sizeof(sa));
  34. sa.sched_priority = level;
  35. return sched_setscheduler(tid, SCHED_FIFO, &sa);
  36. #else
  37. return -1;
  38. #endif
  39. }
  40. int set_core_affinity(std::vector<int> cores) {
  41. #ifdef __linux__
  42. long tid = syscall(SYS_gettid);
  43. cpu_set_t cpu;
  44. CPU_ZERO(&cpu);
  45. for (const int n : cores) {
  46. CPU_SET(n, &cpu);
  47. }
  48. return sched_setaffinity(tid, sizeof(cpu), &cpu);
  49. #else
  50. return -1;
  51. #endif
  52. }
  53. int set_file_descriptor_limit(uint64_t limit_val) {
  54. struct rlimit limit;
  55. int status;
  56. if ((status = getrlimit(RLIMIT_NOFILE, &limit)) < 0)
  57. return status;
  58. limit.rlim_cur = limit_val;
  59. if ((status = setrlimit(RLIMIT_NOFILE, &limit)) < 0)
  60. return status;
  61. return 0;
  62. }
  63. std::string read_file(const std::string& fn) {
  64. std::ifstream f(fn, std::ios::binary | std::ios::in);
  65. if (f.is_open()) {
  66. f.seekg(0, std::ios::end);
  67. int size = f.tellg();
  68. if (f.good() && size > 0) {
  69. std::string result(size, '\0');
  70. f.seekg(0, std::ios::beg);
  71. f.read(result.data(), size);
  72. // return either good() or has reached end-of-file (e.g. /sys/power/wakeup_count)
  73. if (f.good() || f.eof()) {
  74. result.resize(f.gcount());
  75. return result;
  76. }
  77. }
  78. // fallback for files created on read, e.g. procfs
  79. std::stringstream buffer;
  80. buffer << f.rdbuf();
  81. return buffer.str();
  82. }
  83. return std::string();
  84. }
  85. std::map<std::string, std::string> read_files_in_dir(const std::string &path) {
  86. std::map<std::string, std::string> ret;
  87. DIR *d = opendir(path.c_str());
  88. if (!d) return ret;
  89. struct dirent *de = NULL;
  90. while ((de = readdir(d))) {
  91. if (de->d_type != DT_DIR) {
  92. ret[de->d_name] = util::read_file(path + "/" + de->d_name);
  93. }
  94. }
  95. closedir(d);
  96. return ret;
  97. }
  98. int write_file(const char* path, const void* data, size_t size, int flags, mode_t mode) {
  99. int fd = HANDLE_EINTR(open(path, flags, mode));
  100. if (fd == -1) {
  101. return -1;
  102. }
  103. ssize_t n = HANDLE_EINTR(write(fd, data, size));
  104. close(fd);
  105. return (n >= 0 && (size_t)n == size) ? 0 : -1;
  106. }
  107. FILE* safe_fopen(const char* filename, const char* mode) {
  108. FILE* fp = NULL;
  109. do {
  110. fp = fopen(filename, mode);
  111. } while ((nullptr == fp) && (errno == EINTR));
  112. return fp;
  113. }
  114. size_t safe_fwrite(const void* ptr, size_t size, size_t count, FILE* stream) {
  115. size_t written = 0;
  116. do {
  117. size_t ret = ::fwrite((void*)((char *)ptr + written * size), size, count - written, stream);
  118. if (ret == 0 && errno != EINTR) break;
  119. written += ret;
  120. } while (written != count);
  121. return written;
  122. }
  123. int safe_fflush(FILE *stream) {
  124. int ret = EOF;
  125. do {
  126. ret = fflush(stream);
  127. } while ((EOF == ret) && (errno == EINTR));
  128. return ret;
  129. }
  130. int safe_ioctl(int fd, unsigned long request, void *argp) {
  131. int ret;
  132. do {
  133. ret = ioctl(fd, request, argp);
  134. } while ((ret == -1) && (errno == EINTR));
  135. return ret;
  136. }
  137. std::string readlink(const std::string &path) {
  138. char buff[4096];
  139. ssize_t len = ::readlink(path.c_str(), buff, sizeof(buff)-1);
  140. if (len != -1) {
  141. buff[len] = '\0';
  142. return std::string(buff);
  143. }
  144. return "";
  145. }
  146. bool file_exists(const std::string& fn) {
  147. struct stat st = {};
  148. return stat(fn.c_str(), &st) != -1;
  149. }
  150. static bool createDirectory(std::string dir, mode_t mode) {
  151. auto verify_dir = [](const std::string& dir) -> bool {
  152. struct stat st = {};
  153. return (stat(dir.c_str(), &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR);
  154. };
  155. // remove trailing /'s
  156. while (dir.size() > 1 && dir.back() == '/') {
  157. dir.pop_back();
  158. }
  159. // try to mkdir this directory
  160. if (mkdir(dir.c_str(), mode) == 0) return true;
  161. if (errno == EEXIST) return verify_dir(dir);
  162. if (errno != ENOENT) return false;
  163. // mkdir failed because the parent dir doesn't exist, so try to create it
  164. size_t slash = dir.rfind('/');
  165. if ((slash == std::string::npos || slash < 1) ||
  166. !createDirectory(dir.substr(0, slash), mode)) {
  167. return false;
  168. }
  169. // try again
  170. if (mkdir(dir.c_str(), mode) == 0) return true;
  171. return errno == EEXIST && verify_dir(dir);
  172. }
  173. bool create_directories(const std::string& dir, mode_t mode) {
  174. if (dir.empty()) return false;
  175. return createDirectory(dir, mode);
  176. }
  177. std::string getenv(const char* key, std::string default_val) {
  178. const char* val = ::getenv(key);
  179. return val ? val : default_val;
  180. }
  181. int getenv(const char* key, int default_val) {
  182. const char* val = ::getenv(key);
  183. return val ? atoi(val) : default_val;
  184. }
  185. float getenv(const char* key, float default_val) {
  186. const char* val = ::getenv(key);
  187. return val ? atof(val) : default_val;
  188. }
  189. std::string hexdump(const uint8_t* in, const size_t size) {
  190. std::stringstream ss;
  191. ss << std::hex << std::setfill('0');
  192. for (size_t i = 0; i < size; i++) {
  193. ss << std::setw(2) << static_cast<unsigned int>(in[i]);
  194. }
  195. return ss.str();
  196. }
  197. int random_int(int min, int max) {
  198. std::random_device dev;
  199. std::mt19937 rng(dev());
  200. std::uniform_int_distribution<std::mt19937::result_type> dist(min, max);
  201. return dist(rng);
  202. }
  203. std::string random_string(std::string::size_type length) {
  204. const std::string chrs = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  205. std::mt19937 rg{std::random_device{}()};
  206. std::uniform_int_distribution<std::string::size_type> pick(0, chrs.length() - 1);
  207. std::string s;
  208. s.reserve(length);
  209. while (length--) {
  210. s += chrs[pick(rg)];
  211. }
  212. return s;
  213. }
  214. bool starts_with(const std::string &s1, const std::string &s2) {
  215. return strncmp(s1.c_str(), s2.c_str(), s2.size()) == 0;
  216. }
  217. bool ends_with(const std::string& s, const std::string& suffix) {
  218. return s.size() >= suffix.size() &&
  219. strcmp(s.c_str() + (s.size() - suffix.size()), suffix.c_str()) == 0;
  220. }
  221. std::string check_output(const std::string& command) {
  222. char buffer[128];
  223. std::string result;
  224. std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(command.c_str(), "r"), pclose);
  225. if (!pipe) {
  226. return "";
  227. }
  228. while (fgets(buffer, std::size(buffer), pipe.get()) != nullptr) {
  229. result += std::string(buffer);
  230. }
  231. return result;
  232. }
  233. } // namespace util