#include "system.hpp" #include "string.hpp" #include #include #include #if defined ARCH_LIN || defined ARCH_MAC #include #include #include // for backtrace and backtrace_symbols #include // for execl #include #endif #if defined ARCH_WIN #include #include #include #include #endif namespace rack { namespace system { std::list getEntries(const std::string &path) { std::list filenames; DIR *dir = opendir(path.c_str()); if (dir) { struct dirent *d; while ((d = readdir(dir))) { std::string filename = d->d_name; if (filename == "." || filename == "..") continue; filenames.push_back(path + "/" + filename); } closedir(dir); } filenames.sort(); return filenames; } bool isFile(const std::string &path) { struct stat statbuf; if (stat(path.c_str(), &statbuf)) return false; return S_ISREG(statbuf.st_mode); } bool isDirectory(const std::string &path) { struct stat statbuf; if (stat(path.c_str(), &statbuf)) return false; return S_ISDIR(statbuf.st_mode); } void moveFile(const std::string &srcPath, const std::string &destPath) { std::remove(destPath.c_str()); // Whether this overwrites existing files is implementation-defined. // i.e. Mingw64 fails to overwrite. // This is why we remove the file above. std::rename(srcPath.c_str(), destPath.c_str()); } void copyFile(const std::string &srcPath, const std::string &destPath) { // Open source FILE *source = fopen(srcPath.c_str(), "rb"); if (!source) return; DEFER({ fclose(source); }); // Open destination FILE *dest = fopen(destPath.c_str(), "wb"); if (!dest) return; DEFER({ fclose(dest); }); // Copy buffer const int bufferSize = (1<<15); char buffer[bufferSize]; while (1) { size_t size = fread(buffer, 1, bufferSize, source); if (size == 0) break; size = fwrite(buffer, 1, size, dest); if (size == 0) break; } } void createDirectory(const std::string &path) { #if defined ARCH_WIN std::wstring pathW = string::toWstring(path); CreateDirectoryW(pathW.c_str(), NULL); #else mkdir(path.c_str(), 0755); #endif } int getLogicalCoreCount() { return std::thread::hardware_concurrency(); } void setThreadName(const std::string &name) { #if defined ARCH_LIN pthread_setname_np(pthread_self(), name.c_str()); #elif defined ARCH_WIN // Unsupported on Windows #endif } void setThreadRealTime(bool realTime) { #if defined ARCH_LIN int err; int policy; struct sched_param param; if (realTime) { // Round-robin scheduler policy policy = SCHED_RR; param.sched_priority = sched_get_priority_max(policy); } else { // Default scheduler policy policy = 0; param.sched_priority = 0; } err = pthread_setschedparam(pthread_self(), policy, ¶m); assert(!err); // pthread_getschedparam(pthread_self(), &policy, ¶m); // DEBUG("policy %d priority %d", policy, param.sched_priority); #elif defined ARCH_MAC // Not yet implemented #elif defined ARCH_WIN // Set process class first if (realTime) { SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); } else { SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); } #endif } std::string getStackTrace() { int stackLen = 128; void *stack[stackLen]; std::string s; #if defined ARCH_LIN || defined ARCH_MAC stackLen = backtrace(stack, stackLen); char **strings = backtrace_symbols(stack, stackLen); for (int i = 1; i < stackLen; i++) { s += string::f("%d: %s\n", stackLen - i - 1, strings[i]); } free(strings); #elif defined ARCH_WIN HANDLE process = GetCurrentProcess(); SymInitialize(process, NULL, true); stackLen = CaptureStackBackTrace(0, stackLen, stack, NULL); SYMBOL_INFO *symbol = (SYMBOL_INFO*) calloc(sizeof(SYMBOL_INFO) + 256, 1); symbol->MaxNameLen = 255; symbol->SizeOfStruct = sizeof(SYMBOL_INFO); for (int i = 1; i < stackLen; i++) { SymFromAddr(process, (DWORD64) stack[i], 0, symbol); s += string::f("%d: %s 0x%0x\n", stackLen - i - 1, symbol->Name, symbol->Address); } free(symbol); #endif return s; } void openBrowser(const std::string &url) { #if defined ARCH_LIN std::string command = "xdg-open \"" + url + "\""; (void) std::system(command.c_str()); #endif #if defined ARCH_MAC std::string command = "open \"" + url + "\""; std::system(command.c_str()); #endif #if defined ARCH_WIN std::wstring urlW = string::toWstring(url); ShellExecuteW(NULL, L"open", urlW.c_str(), NULL, NULL, SW_SHOWNORMAL); #endif } void openFolder(const std::string &path) { #if defined ARCH_LIN std::string command = "xdg-open \"" + path + "\""; (void) std::system(command.c_str()); #endif #if defined ARCH_WIN std::wstring pathW = string::toWstring(path); ShellExecuteW(NULL, L"explorer", pathW.c_str(), NULL, NULL, SW_SHOWNORMAL); #endif } void runProcessDetached(const std::string &path) { #if defined ARCH_WIN STARTUPINFOW startupInfo; PROCESS_INFORMATION processInfo; std::memset(&startupInfo, 0, sizeof(startupInfo)); startupInfo.cb = sizeof(startupInfo); std::memset(&processInfo, 0, sizeof(processInfo)); std::wstring pathW = string::toWstring(path); CreateProcessW(pathW.c_str(), NULL, NULL, NULL, false, 0, NULL, NULL, &startupInfo, &processInfo); #else // Not implemented on Linux or Mac assert(0); #endif } std::string getOperatingSystemInfo() { #if defined ARCH_LIN || defined ARCH_MAC struct utsname u; uname(&u); return string::f("%s %s %s %s", u.sysname, u.release, u.version, u.machine); #elif defined ARCH_WIN OSVERSIONINFOW info; ZeroMemory(&info, sizeof(info)); info.dwOSVersionInfoSize = sizeof(info); GetVersionExW(&info); // See https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_osversioninfoa for a list of Windows version numbers. return string::f("Windows %u.%u", info.dwMajorVersion, info.dwMinorVersion); #endif } } // namespace system } // namespace rack