Chris@223: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@223: Chris@223: /* Chris@223: Sonic Visualiser Chris@223: An audio file viewer and annotation editor. Chris@223: Centre for Digital Music, Queen Mary, University of London. Chris@223: This file copyright 2006 Chris Cannam and QMUL. Chris@223: Chris@223: This program is free software; you can redistribute it and/or Chris@223: modify it under the terms of the GNU General Public License as Chris@223: published by the Free Software Foundation; either version 2 of the Chris@223: License, or (at your option) any later version. See the file Chris@223: COPYING included with this distribution for more information. Chris@223: */ Chris@223: Chris@223: #include "System.h" Chris@223: Chris@223: #include Chris@223: #include Chris@223: Chris@223: #include Chris@223: Chris@223: #ifndef _WIN32 Chris@223: #include Chris@223: #include Chris@608: #include Chris@608: #include Chris@223: #endif Chris@223: Chris@223: #ifdef __APPLE__ Chris@223: #include Chris@223: #include Chris@223: #endif Chris@223: Chris@405: #include Chris@405: #include Chris@405: Chris@223: #include Chris@223: Chris@255: #ifdef __APPLE__ Chris@255: extern "C" { Chris@255: void * Chris@255: rpl_realloc (void *p, size_t n) Chris@255: { Chris@255: p = realloc(p, n); Chris@255: if (p == 0 && n == 0) Chris@255: { Chris@255: p = malloc(0); Chris@255: } Chris@255: return p; Chris@255: } Chris@255: } Chris@255: #endif Chris@255: Chris@223: #ifdef _WIN32 Chris@223: Chris@223: extern "C" { Chris@223: Chris@765: /* usleep is now in mingw Chris@223: void usleep(unsigned long usec) Chris@223: { Chris@223: ::Sleep(usec / 1000); Chris@223: } Chris@765: */ Chris@223: Chris@501: int gettimeofday(struct timeval *tv, void *tz) Chris@223: { Chris@223: union { Chris@223: long long ns100; Chris@223: FILETIME ft; Chris@223: } now; Chris@223: Chris@223: ::GetSystemTimeAsFileTime(&now.ft); Chris@223: tv->tv_usec = (long)((now.ns100 / 10LL) % 1000000LL); Chris@223: tv->tv_sec = (long)((now.ns100 - 116444736000000000LL) / 10000000LL); Chris@572: return 0; Chris@223: } Chris@223: Chris@223: } Chris@223: Chris@223: #endif Chris@223: Chris@223: ProcessStatus Chris@223: GetProcessStatus(int pid) Chris@223: { Chris@223: #ifdef _WIN32 Chris@223: HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); Chris@223: if (!handle) { Chris@223: return ProcessNotRunning; Chris@223: } else { Chris@223: CloseHandle(handle); Chris@223: return ProcessRunning; Chris@223: } Chris@223: #else Chris@223: if (kill(getpid(), 0) == 0) { Chris@223: if (kill(pid, 0) == 0) { Chris@223: return ProcessRunning; Chris@223: } else { Chris@223: return ProcessNotRunning; Chris@223: } Chris@223: } else { Chris@223: return UnknownProcessStatus; Chris@223: } Chris@223: #endif Chris@223: } Chris@223: Chris@223: #ifdef _WIN32 Chris@223: /* MEMORYSTATUSEX is missing from older Windows headers, so define a Chris@223: local replacement. This trick from MinGW source code. Ugh */ Chris@223: typedef struct Chris@223: { Chris@223: DWORD dwLength; Chris@223: DWORD dwMemoryLoad; Chris@223: DWORDLONG ullTotalPhys; Chris@223: DWORDLONG ullAvailPhys; Chris@223: DWORDLONG ullTotalPageFile; Chris@223: DWORDLONG ullAvailPageFile; Chris@223: DWORDLONG ullTotalVirtual; Chris@223: DWORDLONG ullAvailVirtual; Chris@223: DWORDLONG ullAvailExtendedVirtual; Chris@223: } lMEMORYSTATUSEX; Chris@223: typedef WINBOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*); Chris@223: #endif Chris@223: Chris@223: void Chris@1038: GetRealMemoryMBAvailable(ssize_t &available, ssize_t &total) Chris@223: { Chris@223: available = -1; Chris@223: total = -1; Chris@223: Chris@223: #ifdef _WIN32 Chris@223: Chris@223: static bool checked = false; Chris@223: static bool exFound = false; Chris@223: static PFN_MS_EX ex; Chris@223: Chris@223: if (!checked) { Chris@223: Chris@223: HMODULE h = GetModuleHandleA("kernel32.dll"); Chris@223: Chris@223: if (h) { Chris@223: if ((ex = (PFN_MS_EX)GetProcAddress(h, "GlobalMemoryStatusEx"))) { Chris@223: exFound = true; Chris@223: } Chris@223: } Chris@223: Chris@223: checked = true; Chris@223: } Chris@223: Chris@223: DWORDLONG wavail = 0; Chris@223: DWORDLONG wtotal = 0; Chris@223: Chris@223: if (exFound) { Chris@223: Chris@223: lMEMORYSTATUSEX lms; Chris@223: lms.dwLength = sizeof(lms); Chris@223: if (!ex(&lms)) { Chris@843: cerr << "WARNING: GlobalMemoryStatusEx failed: error code " Chris@843: << GetLastError() << endl; Chris@223: return; Chris@223: } Chris@223: wavail = lms.ullAvailPhys; Chris@223: wtotal = lms.ullTotalPhys; Chris@223: Chris@223: } else { Chris@223: Chris@223: /* Fall back to GlobalMemoryStatus which is always available. Chris@223: but returns wrong results for physical memory > 4GB */ Chris@223: Chris@223: MEMORYSTATUS ms; Chris@223: GlobalMemoryStatus(&ms); Chris@223: wavail = ms.dwAvailPhys; Chris@223: wtotal = ms.dwTotalPhys; Chris@223: } Chris@223: Chris@223: DWORDLONG size = wavail / 1048576; Chris@223: if (size > INT_MAX) size = INT_MAX; Chris@1038: available = ssize_t(size); Chris@223: Chris@223: size = wtotal / 1048576; Chris@223: if (size > INT_MAX) size = INT_MAX; Chris@1038: total = ssize_t(size); Chris@223: Chris@223: return; Chris@223: Chris@223: #else Chris@223: #ifdef __APPLE__ Chris@223: Chris@223: unsigned int val; Chris@223: int mib[2]; Chris@223: size_t size_sys; Chris@223: Chris@223: mib[0] = CTL_HW; Chris@223: Chris@223: mib[1] = HW_PHYSMEM; Chris@223: size_sys = sizeof(val); Chris@223: sysctl(mib, 2, &val, &size_sys, NULL, 0); Chris@223: if (val) total = val / 1048576; Chris@223: Chris@223: mib[1] = HW_USERMEM; Chris@223: size_sys = sizeof(val); Chris@223: sysctl(mib, 2, &val, &size_sys, NULL, 0); Chris@223: if (val) available = val / 1048576; Chris@223: Chris@223: return; Chris@223: Chris@223: #else Chris@223: Chris@223: FILE *meminfo = fopen("/proc/meminfo", "r"); Chris@223: if (!meminfo) return; Chris@223: Chris@223: char buf[256]; Chris@223: while (!feof(meminfo)) { Chris@223: fgets(buf, 256, meminfo); Chris@223: bool isMemFree = (strncmp(buf, "MemFree:", 8) == 0); Chris@223: bool isMemTotal = (!isMemFree && (strncmp(buf, "MemTotal:", 9) == 0)); Chris@223: if (isMemFree || isMemTotal) { Chris@223: QString line = QString(buf).trimmed(); Chris@223: QStringList elements = line.split(' ', QString::SkipEmptyParts); Chris@223: QString unit = "kB"; Chris@223: if (elements.size() > 2) unit = elements[2]; Chris@223: int size = elements[1].toInt(); Chris@843: // cerr << "have size \"" << size << "\", unit \"" Chris@843: // << unit << "\"" << endl; Chris@223: if (unit.toLower() == "gb") size = size * 1024; Chris@223: else if (unit.toLower() == "mb") size = size; Chris@223: else if (unit.toLower() == "kb") size = size / 1024; Chris@223: else size = size / 1048576; Chris@223: Chris@223: if (isMemFree) available = size; Chris@223: else total = size; Chris@223: } Chris@223: if (available != -1 && total != -1) { Chris@223: fclose(meminfo); Chris@223: return; Chris@223: } Chris@223: } Chris@223: fclose(meminfo); Chris@223: Chris@223: return; Chris@223: Chris@223: #endif Chris@223: #endif Chris@223: } Chris@223: Chris@1038: ssize_t Chris@223: GetDiscSpaceMBAvailable(const char *path) Chris@223: { Chris@223: #ifdef _WIN32 Chris@223: ULARGE_INTEGER available, total, totalFree; Chris@223: if (GetDiskFreeSpaceExA(path, &available, &total, &totalFree)) { Chris@223: __int64 a = available.QuadPart; Chris@223: a /= 1048576; Chris@223: if (a > INT_MAX) a = INT_MAX; Chris@1038: return ssize_t(a); Chris@223: } else { Chris@843: cerr << "WARNING: GetDiskFreeSpaceEx failed: error code " Chris@843: << GetLastError() << endl; Chris@223: return -1; Chris@223: } Chris@223: #else Chris@223: struct statvfs buf; Chris@223: if (!statvfs(path, &buf)) { Chris@223: // do the multiplies and divides in this order to reduce the Chris@223: // likelihood of arithmetic overflow Chris@843: // cerr << "statvfs(" << path << ") says available: " << buf.f_bavail << ", block size: " << buf.f_bsize << endl; Chris@223: uint64_t available = ((buf.f_bavail / 1024) * buf.f_bsize) / 1024; Chris@223: if (available > INT_MAX) available = INT_MAX; Chris@1038: return ssize_t(available); Chris@223: } else { Chris@223: perror("statvfs failed"); Chris@223: return -1; Chris@223: } Chris@223: #endif Chris@223: } Chris@303: Chris@835: #ifdef _WIN32 Chris@835: extern void SystemMemoryBarrier() Chris@835: { Chris@835: #ifdef __MSVC__ Chris@835: MemoryBarrier(); Chris@835: #else /* mingw */ Chris@835: LONG Barrier = 0; Chris@835: __asm__ __volatile__("xchgl %%eax,%0 " Chris@835: : "=r" (Barrier)); Chris@835: #endif Chris@835: } Chris@835: #else /* !_WIN32 */ Chris@835: #if !defined(__APPLE__) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ == 0)) Chris@835: void Chris@835: SystemMemoryBarrier() Chris@835: { Chris@835: pthread_mutex_t dummy = PTHREAD_MUTEX_INITIALIZER; Chris@835: pthread_mutex_lock(&dummy); Chris@835: pthread_mutex_unlock(&dummy); Chris@835: } Chris@835: #endif /* !defined(__APPLE__) etc */ Chris@835: #endif /* !_WIN32 */ Chris@835: Chris@835: Chris@303: static char *startupLocale = 0; Chris@303: Chris@303: void Chris@303: StoreStartupLocale() Chris@303: { Chris@303: char *loc = setlocale(LC_ALL, 0); Chris@303: if (!loc) return; Chris@303: if (startupLocale) free(startupLocale); Chris@303: startupLocale = strdup(loc); Chris@303: } Chris@303: Chris@303: void Chris@303: RestoreStartupLocale() Chris@303: { Chris@303: if (!startupLocale) { Chris@303: setlocale(LC_ALL, ""); Chris@303: } else { Chris@303: setlocale(LC_ALL, startupLocale); Chris@303: } Chris@303: } Chris@223: Chris@223: double mod(double x, double y) { return x - (y * floor(x / y)); } Chris@223: float modf(float x, float y) { return x - (y * floorf(x / y)); } Chris@223: Chris@223: double princarg(double a) { return mod(a + M_PI, -2 * M_PI) + M_PI; } Chris@1039: float princargf(float a) { return float(princarg(a)); } Chris@223: Chris@1176: #ifdef _WIN32 Chris@1176: Chris@1176: PluginLoadStatus Chris@1176: TestPluginLoadability(QString soname, QString descriptorFn) Chris@1176: { Chris@1176: //!!! Can't do the POSIX logic below, but we have no good Chris@1176: // alternative here yet Chris@1176: return PluginLoadOK; Chris@1176: } Chris@1176: Chris@1176: #else Chris@1165: Chris@1165: #include Chris@1165: #include Chris@1165: Chris@1165: PluginLoadStatus Chris@1165: TestPluginLoadability(QString soname, QString descriptorFn) Chris@1165: { Chris@1165: //!!! This is POSIX only, no equivalent on Windows, where we'll Chris@1165: //!!! have to do something completely different Chris@1165: Chris@1165: pid_t pid = fork(); Chris@1165: Chris@1165: if (pid < 0) { Chris@1165: return UnknownPluginLoadStatus; // fork failed Chris@1165: } Chris@1165: Chris@1165: if (pid == 0) { // the child process Chris@1165: Chris@1165: void *handle = DLOPEN(soname, RTLD_NOW | RTLD_LOCAL); Chris@1165: if (!handle) { Chris@1165: cerr << "isPluginLibraryLoadable: Failed to open plugin library \"" Chris@1165: << soname << "\": " << dlerror() << "\n"; Chris@1165: cerr << "exiting with status 1" << endl; Chris@1165: exit(1); Chris@1165: } Chris@1165: Chris@1165: void *fn = DLSYM(handle, descriptorFn.toLocal8Bit().data()); Chris@1165: if (!fn) { Chris@1165: cerr << "isPluginLibraryLoadable: Failed to find plugin descriptor function \"" << descriptorFn << "\" in library \"" << soname << "\": " << dlerror() << "\n"; Chris@1165: exit(2); Chris@1165: } Chris@1165: Chris@1166: // cerr << "isPluginLibraryLoadable: Successfully loaded library \"" << soname << "\" and retrieved descriptor function" << endl; Chris@1166: Chris@1165: exit(0); Chris@1165: Chris@1165: } else { // the parent process Chris@1165: Chris@1165: int status = 0; Chris@1165: Chris@1165: do { Chris@1165: waitpid(pid, &status, 0); Chris@1165: } while (WIFSTOPPED(status)); Chris@1165: Chris@1165: if (WIFEXITED(status)) { Chris@1165: switch (WEXITSTATUS(status)) { Chris@1165: case 0: return PluginLoadOK; // success Chris@1165: case 1: return PluginLoadFailedToLoadLibrary; Chris@1165: case 2: return PluginLoadFailedToFindDescriptor; Chris@1165: default: return PluginLoadFailedElsewhere; Chris@1165: } Chris@1165: } Chris@1165: Chris@1165: if (WIFSIGNALED(status)) { Chris@1165: return PluginLoadFailedElsewhere; Chris@1165: } Chris@1165: Chris@1165: return UnknownPluginLoadStatus; Chris@1165: } Chris@1165: } Chris@1165: Chris@1165: #endif