You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
6.0KB

  1. #include <system.hpp>
  2. #include <string.hpp>
  3. #include <thread>
  4. #include <dirent.h>
  5. #include <sys/stat.h>
  6. #if defined ARCH_LIN || defined ARCH_MAC
  7. #include <pthread.h>
  8. #include <sched.h>
  9. #include <execinfo.h> // for backtrace and backtrace_symbols
  10. #include <unistd.h> // for execl
  11. #include <sys/utsname.h>
  12. #endif
  13. #if defined ARCH_WIN
  14. #include <windows.h>
  15. #include <shellapi.h>
  16. #include <processthreadsapi.h>
  17. #include <dbghelp.h>
  18. #endif
  19. namespace rack {
  20. namespace system {
  21. std::list<std::string> getEntries(const std::string &path) {
  22. std::list<std::string> filenames;
  23. DIR *dir = opendir(path.c_str());
  24. if (dir) {
  25. struct dirent *d;
  26. while ((d = readdir(dir))) {
  27. std::string filename = d->d_name;
  28. if (filename == "." || filename == "..")
  29. continue;
  30. filenames.push_back(path + "/" + filename);
  31. }
  32. closedir(dir);
  33. }
  34. filenames.sort();
  35. return filenames;
  36. }
  37. bool isFile(const std::string &path) {
  38. struct stat statbuf;
  39. if (stat(path.c_str(), &statbuf))
  40. return false;
  41. return S_ISREG(statbuf.st_mode);
  42. }
  43. bool isDirectory(const std::string &path) {
  44. struct stat statbuf;
  45. if (stat(path.c_str(), &statbuf))
  46. return false;
  47. return S_ISDIR(statbuf.st_mode);
  48. }
  49. void moveFile(const std::string &srcPath, const std::string &destPath) {
  50. std::remove(destPath.c_str());
  51. // Whether this overwrites existing files is implementation-defined.
  52. // i.e. Mingw64 fails to overwrite.
  53. // This is why we remove the file above.
  54. std::rename(srcPath.c_str(), destPath.c_str());
  55. }
  56. void copyFile(const std::string &srcPath, const std::string &destPath) {
  57. // Open source
  58. FILE *source = fopen(srcPath.c_str(), "rb");
  59. if (!source)
  60. return;
  61. DEFER({
  62. fclose(source);
  63. });
  64. // Open destination
  65. FILE *dest = fopen(destPath.c_str(), "wb");
  66. if (!dest)
  67. return;
  68. DEFER({
  69. fclose(dest);
  70. });
  71. // Copy buffer
  72. const int bufferSize = (1<<15);
  73. char buffer[bufferSize];
  74. while (1) {
  75. size_t size = fread(buffer, 1, bufferSize, source);
  76. if (size == 0)
  77. break;
  78. size = fwrite(buffer, 1, size, dest);
  79. if (size == 0)
  80. break;
  81. }
  82. }
  83. void createDirectory(const std::string &path) {
  84. #if defined ARCH_WIN
  85. std::wstring pathW = string::toWstring(path);
  86. CreateDirectoryW(pathW.c_str(), NULL);
  87. #else
  88. mkdir(path.c_str(), 0755);
  89. #endif
  90. }
  91. int getLogicalCoreCount() {
  92. return std::thread::hardware_concurrency();
  93. }
  94. void setThreadName(const std::string &name) {
  95. #if defined ARCH_LIN
  96. pthread_setname_np(pthread_self(), name.c_str());
  97. #elif defined ARCH_WIN
  98. // Unsupported on Windows
  99. #endif
  100. }
  101. void setThreadRealTime(bool realTime) {
  102. #if defined ARCH_LIN
  103. int err;
  104. int policy;
  105. struct sched_param param;
  106. if (realTime) {
  107. // Round-robin scheduler policy
  108. policy = SCHED_RR;
  109. param.sched_priority = sched_get_priority_max(policy);
  110. }
  111. else {
  112. // Default scheduler policy
  113. policy = 0;
  114. param.sched_priority = 0;
  115. }
  116. err = pthread_setschedparam(pthread_self(), policy, &param);
  117. assert(!err);
  118. // pthread_getschedparam(pthread_self(), &policy, &param);
  119. // DEBUG("policy %d priority %d", policy, param.sched_priority);
  120. #elif defined ARCH_MAC
  121. // Not yet implemented
  122. #elif defined ARCH_WIN
  123. // Set process class first
  124. if (realTime) {
  125. SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
  126. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  127. }
  128. else {
  129. SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
  130. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  131. }
  132. #endif
  133. }
  134. std::string getStackTrace() {
  135. int stackLen = 128;
  136. void *stack[stackLen];
  137. std::string s;
  138. #if defined ARCH_LIN || defined ARCH_MAC
  139. stackLen = backtrace(stack, stackLen);
  140. char **strings = backtrace_symbols(stack, stackLen);
  141. for (int i = 1; i < stackLen; i++) {
  142. s += string::f("%d: %s\n", stackLen - i - 1, strings[i]);
  143. }
  144. free(strings);
  145. #elif defined ARCH_WIN
  146. HANDLE process = GetCurrentProcess();
  147. SymInitialize(process, NULL, true);
  148. stackLen = CaptureStackBackTrace(0, stackLen, stack, NULL);
  149. SYMBOL_INFO *symbol = (SYMBOL_INFO*) calloc(sizeof(SYMBOL_INFO) + 256, 1);
  150. symbol->MaxNameLen = 255;
  151. symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
  152. for (int i = 1; i < stackLen; i++) {
  153. SymFromAddr(process, (DWORD64) stack[i], 0, symbol);
  154. s += string::f("%d: %s 0x%0x\n", stackLen - i - 1, symbol->Name, symbol->Address);
  155. }
  156. free(symbol);
  157. #endif
  158. return s;
  159. }
  160. void openBrowser(const std::string &url) {
  161. #if defined ARCH_LIN
  162. std::string command = "xdg-open \"" + url + "\"";
  163. (void) std::system(command.c_str());
  164. #endif
  165. #if defined ARCH_MAC
  166. std::string command = "open \"" + url + "\"";
  167. std::system(command.c_str());
  168. #endif
  169. #if defined ARCH_WIN
  170. std::wstring urlW = string::toWstring(url);
  171. ShellExecuteW(NULL, L"open", urlW.c_str(), NULL, NULL, SW_SHOWNORMAL);
  172. #endif
  173. }
  174. void openFolder(const std::string &path) {
  175. #if defined ARCH_LIN
  176. std::string command = "xdg-open \"" + path + "\"";
  177. (void) std::system(command.c_str());
  178. #endif
  179. #if defined ARCH_WIN
  180. std::wstring pathW = string::toWstring(path);
  181. ShellExecuteW(NULL, L"explorer", pathW.c_str(), NULL, NULL, SW_SHOWNORMAL);
  182. #endif
  183. }
  184. void runProcessDetached(const std::string &path) {
  185. #if defined ARCH_WIN
  186. STARTUPINFOW startupInfo;
  187. PROCESS_INFORMATION processInfo;
  188. std::memset(&startupInfo, 0, sizeof(startupInfo));
  189. startupInfo.cb = sizeof(startupInfo);
  190. std::memset(&processInfo, 0, sizeof(processInfo));
  191. std::wstring pathW = string::toWstring(path);
  192. CreateProcessW(pathW.c_str(), NULL,
  193. NULL, NULL, false, 0, NULL, NULL,
  194. &startupInfo, &processInfo);
  195. #else
  196. // Not implemented on Linux or Mac
  197. assert(0);
  198. #endif
  199. }
  200. std::string getOperatingSystemInfo() {
  201. #if defined ARCH_LIN || defined ARCH_MAC
  202. struct utsname u;
  203. uname(&u);
  204. return string::f("%s %s %s %s", u.sysname, u.release, u.version, u.machine);
  205. #elif defined ARCH_WIN
  206. OSVERSIONINFOW info;
  207. ZeroMemory(&info, sizeof(info));
  208. info.dwOSVersionInfoSize = sizeof(info);
  209. GetVersionExW(&info);
  210. // See https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_osversioninfoa for a list of Windows version numbers.
  211. return string::f("Windows %u.%u", info.dwMajorVersion, info.dwMinorVersion);
  212. #endif
  213. }
  214. } // namespace system
  215. } // namespace rack