| Chris@223 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */ | 
| Chris@223 | 2 | 
| Chris@223 | 3 /* | 
| Chris@223 | 4     Sonic Visualiser | 
| Chris@223 | 5     An audio file viewer and annotation editor. | 
| Chris@223 | 6     Centre for Digital Music, Queen Mary, University of London. | 
| Chris@223 | 7     This file copyright 2006 Chris Cannam and QMUL. | 
| Chris@223 | 8 | 
| Chris@223 | 9     This program is free software; you can redistribute it and/or | 
| Chris@223 | 10     modify it under the terms of the GNU General Public License as | 
| Chris@223 | 11     published by the Free Software Foundation; either version 2 of the | 
| Chris@223 | 12     License, or (at your option) any later version.  See the file | 
| Chris@223 | 13     COPYING included with this distribution for more information. | 
| Chris@223 | 14 */ | 
| Chris@223 | 15 | 
| Chris@223 | 16 #include "System.h" | 
| Chris@223 | 17 | 
| Chris@223 | 18 #include <QStringList> | 
| Chris@223 | 19 #include <QString> | 
| Chris@223 | 20 | 
| Chris@223 | 21 #include <stdint.h> | 
| Chris@223 | 22 | 
| Chris@223 | 23 #ifndef _WIN32 | 
| Chris@223 | 24 #include <signal.h> | 
| Chris@223 | 25 #include <sys/statvfs.h> | 
| Chris@608 | 26 #include <locale.h> | 
| Chris@608 | 27 #include <unistd.h> | 
| Chris@223 | 28 #endif | 
| Chris@223 | 29 | 
| Chris@223 | 30 #ifdef __APPLE__ | 
| Chris@223 | 31 #include <sys/param.h> | 
| Chris@223 | 32 #include <sys/sysctl.h> | 
| Chris@223 | 33 #endif | 
| Chris@223 | 34 | 
| Chris@405 | 35 #include <limits.h> | 
| Chris@405 | 36 #include <cstdlib> | 
| Chris@405 | 37 | 
| Chris@223 | 38 #include <iostream> | 
| Chris@223 | 39 | 
| Chris@255 | 40 #ifdef __APPLE__ | 
| Chris@255 | 41 extern "C" { | 
| Chris@255 | 42 void * | 
| Chris@255 | 43 rpl_realloc (void *p, size_t n) | 
| Chris@255 | 44 { | 
| Chris@255 | 45     p = realloc(p, n); | 
| Chris@255 | 46     if (p == 0 && n == 0) | 
| Chris@255 | 47     { | 
| Chris@255 | 48     p = malloc(0); | 
| Chris@255 | 49     } | 
| Chris@255 | 50     return p; | 
| Chris@255 | 51 } | 
| Chris@255 | 52 } | 
| Chris@255 | 53 #endif | 
| Chris@255 | 54 | 
| Chris@223 | 55 #ifdef _WIN32 | 
| Chris@223 | 56 | 
| Chris@223 | 57 extern "C" { | 
| Chris@223 | 58 | 
| Chris@765 | 59 /* usleep is now in mingw | 
| Chris@223 | 60 void usleep(unsigned long usec) | 
| Chris@223 | 61 { | 
| Chris@223 | 62     ::Sleep(usec / 1000); | 
| Chris@223 | 63 } | 
| Chris@765 | 64 */ | 
| Chris@223 | 65 | 
| Chris@501 | 66 int gettimeofday(struct timeval *tv, void *tz) | 
| Chris@223 | 67 { | 
| Chris@223 | 68     union { | 
| Chris@223 | 69 	long long ns100; | 
| Chris@223 | 70 	FILETIME ft; | 
| Chris@223 | 71     } now; | 
| Chris@223 | 72 | 
| Chris@223 | 73     ::GetSystemTimeAsFileTime(&now.ft); | 
| Chris@223 | 74     tv->tv_usec = (long)((now.ns100 / 10LL) % 1000000LL); | 
| Chris@223 | 75     tv->tv_sec = (long)((now.ns100 - 116444736000000000LL) / 10000000LL); | 
| Chris@572 | 76     return 0; | 
| Chris@223 | 77 } | 
| Chris@223 | 78 | 
| Chris@223 | 79 } | 
| Chris@223 | 80 | 
| Chris@223 | 81 #endif | 
| Chris@223 | 82 | 
| Chris@223 | 83 ProcessStatus | 
| Chris@223 | 84 GetProcessStatus(int pid) | 
| Chris@223 | 85 { | 
| Chris@223 | 86 #ifdef _WIN32 | 
| Chris@223 | 87     HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); | 
| Chris@223 | 88     if (!handle) { | 
| Chris@223 | 89         return ProcessNotRunning; | 
| Chris@223 | 90     } else { | 
| Chris@223 | 91         CloseHandle(handle); | 
| Chris@223 | 92         return ProcessRunning; | 
| Chris@223 | 93     } | 
| Chris@223 | 94 #else | 
| Chris@223 | 95     if (kill(getpid(), 0) == 0) { | 
| Chris@223 | 96         if (kill(pid, 0) == 0) { | 
| Chris@223 | 97             return ProcessRunning; | 
| Chris@223 | 98         } else { | 
| Chris@223 | 99             return ProcessNotRunning; | 
| Chris@223 | 100         } | 
| Chris@223 | 101     } else { | 
| Chris@223 | 102         return UnknownProcessStatus; | 
| Chris@223 | 103     } | 
| Chris@223 | 104 #endif | 
| Chris@223 | 105 } | 
| Chris@223 | 106 | 
| Chris@223 | 107 #ifdef _WIN32 | 
| Chris@223 | 108 /*  MEMORYSTATUSEX is missing from older Windows headers, so define a | 
| Chris@223 | 109     local replacement.  This trick from MinGW source code.  Ugh */ | 
| Chris@223 | 110 typedef struct | 
| Chris@223 | 111 { | 
| Chris@223 | 112     DWORD dwLength; | 
| Chris@223 | 113     DWORD dwMemoryLoad; | 
| Chris@223 | 114     DWORDLONG ullTotalPhys; | 
| Chris@223 | 115     DWORDLONG ullAvailPhys; | 
| Chris@223 | 116     DWORDLONG ullTotalPageFile; | 
| Chris@223 | 117     DWORDLONG ullAvailPageFile; | 
| Chris@223 | 118     DWORDLONG ullTotalVirtual; | 
| Chris@223 | 119     DWORDLONG ullAvailVirtual; | 
| Chris@223 | 120     DWORDLONG ullAvailExtendedVirtual; | 
| Chris@223 | 121 } lMEMORYSTATUSEX; | 
| Chris@223 | 122 typedef WINBOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*); | 
| Chris@223 | 123 #endif | 
| Chris@223 | 124 | 
| Chris@223 | 125 void | 
| Chris@1038 | 126 GetRealMemoryMBAvailable(ssize_t &available, ssize_t &total) | 
| Chris@223 | 127 { | 
| Chris@223 | 128     available = -1; | 
| Chris@223 | 129     total = -1; | 
| Chris@223 | 130 | 
| Chris@223 | 131 #ifdef _WIN32 | 
| Chris@223 | 132 | 
| Chris@223 | 133     static bool checked = false; | 
| Chris@223 | 134     static bool exFound = false; | 
| Chris@223 | 135     static PFN_MS_EX ex; | 
| Chris@223 | 136 | 
| Chris@223 | 137     if (!checked) { | 
| Chris@223 | 138 | 
| Chris@223 | 139         HMODULE h = GetModuleHandleA("kernel32.dll"); | 
| Chris@223 | 140 | 
| Chris@223 | 141         if (h) { | 
| Chris@223 | 142             if ((ex = (PFN_MS_EX)GetProcAddress(h, "GlobalMemoryStatusEx"))) { | 
| Chris@223 | 143                 exFound = true; | 
| Chris@223 | 144             } | 
| Chris@223 | 145         } | 
| Chris@223 | 146 | 
| Chris@223 | 147         checked = true; | 
| Chris@223 | 148     } | 
| Chris@223 | 149 | 
| Chris@223 | 150     DWORDLONG wavail = 0; | 
| Chris@223 | 151     DWORDLONG wtotal = 0; | 
| Chris@223 | 152 | 
| Chris@223 | 153     if (exFound) { | 
| Chris@223 | 154 | 
| Chris@223 | 155         lMEMORYSTATUSEX lms; | 
| Chris@223 | 156 	lms.dwLength = sizeof(lms); | 
| Chris@223 | 157 	if (!ex(&lms)) { | 
| Chris@843 | 158             cerr << "WARNING: GlobalMemoryStatusEx failed: error code " | 
| Chris@843 | 159                       << GetLastError() << endl; | 
| Chris@223 | 160             return; | 
| Chris@223 | 161         } | 
| Chris@223 | 162         wavail = lms.ullAvailPhys; | 
| Chris@223 | 163         wtotal = lms.ullTotalPhys; | 
| Chris@223 | 164 | 
| Chris@223 | 165     } else { | 
| Chris@223 | 166 | 
| Chris@223 | 167         /* Fall back to GlobalMemoryStatus which is always available. | 
| Chris@223 | 168            but returns wrong results for physical memory > 4GB  */ | 
| Chris@223 | 169 | 
| Chris@223 | 170 	MEMORYSTATUS ms; | 
| Chris@223 | 171 	GlobalMemoryStatus(&ms); | 
| Chris@223 | 172 	wavail = ms.dwAvailPhys; | 
| Chris@223 | 173         wtotal = ms.dwTotalPhys; | 
| Chris@223 | 174     } | 
| Chris@223 | 175 | 
| Chris@223 | 176     DWORDLONG size = wavail / 1048576; | 
| Chris@223 | 177     if (size > INT_MAX) size = INT_MAX; | 
| Chris@1038 | 178     available = ssize_t(size); | 
| Chris@223 | 179 | 
| Chris@223 | 180     size = wtotal / 1048576; | 
| Chris@223 | 181     if (size > INT_MAX) size = INT_MAX; | 
| Chris@1038 | 182     total = ssize_t(size); | 
| Chris@223 | 183 | 
| Chris@223 | 184     return; | 
| Chris@223 | 185 | 
| Chris@223 | 186 #else | 
| Chris@223 | 187 #ifdef __APPLE__ | 
| Chris@223 | 188 | 
| Chris@223 | 189     unsigned int val; | 
| Chris@223 | 190     int mib[2]; | 
| Chris@223 | 191     size_t size_sys; | 
| Chris@223 | 192 | 
| Chris@223 | 193     mib[0] = CTL_HW; | 
| Chris@223 | 194 | 
| Chris@223 | 195     mib[1] = HW_PHYSMEM; | 
| Chris@223 | 196     size_sys = sizeof(val); | 
| Chris@223 | 197     sysctl(mib, 2, &val, &size_sys, NULL, 0); | 
| Chris@223 | 198     if (val) total = val / 1048576; | 
| Chris@223 | 199 | 
| Chris@223 | 200     mib[1] = HW_USERMEM; | 
| Chris@223 | 201     size_sys = sizeof(val); | 
| Chris@223 | 202     sysctl(mib, 2, &val, &size_sys, NULL, 0); | 
| Chris@223 | 203     if (val) available = val / 1048576; | 
| Chris@223 | 204 | 
| Chris@223 | 205     return; | 
| Chris@223 | 206 | 
| Chris@223 | 207 #else | 
| Chris@223 | 208 | 
| Chris@223 | 209     FILE *meminfo = fopen("/proc/meminfo", "r"); | 
| Chris@223 | 210     if (!meminfo) return; | 
| Chris@223 | 211 | 
| Chris@223 | 212     char buf[256]; | 
| Chris@223 | 213     while (!feof(meminfo)) { | 
| Chris@223 | 214         fgets(buf, 256, meminfo); | 
| Chris@223 | 215         bool isMemFree = (strncmp(buf, "MemFree:", 8) == 0); | 
| Chris@223 | 216         bool isMemTotal = (!isMemFree && (strncmp(buf, "MemTotal:", 9) == 0)); | 
| Chris@223 | 217         if (isMemFree || isMemTotal) { | 
| Chris@223 | 218             QString line = QString(buf).trimmed(); | 
| Chris@223 | 219             QStringList elements = line.split(' ', QString::SkipEmptyParts); | 
| Chris@223 | 220             QString unit = "kB"; | 
| Chris@223 | 221             if (elements.size() > 2) unit = elements[2]; | 
| Chris@223 | 222             int size = elements[1].toInt(); | 
| Chris@843 | 223 //            cerr << "have size \"" << size << "\", unit \"" | 
| Chris@843 | 224 //                      << unit << "\"" << endl; | 
| Chris@223 | 225             if (unit.toLower() == "gb") size = size * 1024; | 
| Chris@223 | 226             else if (unit.toLower() == "mb") size = size; | 
| Chris@223 | 227             else if (unit.toLower() == "kb") size = size / 1024; | 
| Chris@223 | 228             else size = size / 1048576; | 
| Chris@223 | 229 | 
| Chris@223 | 230             if (isMemFree) available = size; | 
| Chris@223 | 231             else total = size; | 
| Chris@223 | 232         } | 
| Chris@223 | 233         if (available != -1 && total != -1) { | 
| Chris@223 | 234             fclose(meminfo); | 
| Chris@223 | 235             return; | 
| Chris@223 | 236         } | 
| Chris@223 | 237     } | 
| Chris@223 | 238     fclose(meminfo); | 
| Chris@223 | 239 | 
| Chris@223 | 240     return; | 
| Chris@223 | 241 | 
| Chris@223 | 242 #endif | 
| Chris@223 | 243 #endif | 
| Chris@223 | 244 } | 
| Chris@223 | 245 | 
| Chris@1038 | 246 ssize_t | 
| Chris@223 | 247 GetDiscSpaceMBAvailable(const char *path) | 
| Chris@223 | 248 { | 
| Chris@223 | 249 #ifdef _WIN32 | 
| Chris@223 | 250     ULARGE_INTEGER available, total, totalFree; | 
| Chris@223 | 251     if (GetDiskFreeSpaceExA(path, &available, &total, &totalFree)) { | 
| Chris@223 | 252 	  __int64 a = available.QuadPart; | 
| Chris@223 | 253         a /= 1048576; | 
| Chris@223 | 254         if (a > INT_MAX) a = INT_MAX; | 
| Chris@1038 | 255         return ssize_t(a); | 
| Chris@223 | 256     } else { | 
| Chris@843 | 257         cerr << "WARNING: GetDiskFreeSpaceEx failed: error code " | 
| Chris@843 | 258                   << GetLastError() << endl; | 
| Chris@223 | 259         return -1; | 
| Chris@223 | 260     } | 
| Chris@223 | 261 #else | 
| Chris@223 | 262     struct statvfs buf; | 
| Chris@223 | 263     if (!statvfs(path, &buf)) { | 
| Chris@223 | 264         // do the multiplies and divides in this order to reduce the | 
| Chris@223 | 265         // likelihood of arithmetic overflow | 
| Chris@843 | 266 //        cerr << "statvfs(" << path << ") says available: " << buf.f_bavail << ", block size: " << buf.f_bsize << endl; | 
| Chris@223 | 267         uint64_t available = ((buf.f_bavail / 1024) * buf.f_bsize) / 1024; | 
| Chris@223 | 268         if (available > INT_MAX) available = INT_MAX; | 
| Chris@1038 | 269         return ssize_t(available); | 
| Chris@223 | 270     } else { | 
| Chris@223 | 271         perror("statvfs failed"); | 
| Chris@223 | 272         return -1; | 
| Chris@223 | 273     } | 
| Chris@223 | 274 #endif | 
| Chris@223 | 275 } | 
| Chris@303 | 276 | 
| Chris@835 | 277 #ifdef _WIN32 | 
| Chris@835 | 278 extern void SystemMemoryBarrier() | 
| Chris@835 | 279 { | 
| Chris@835 | 280 #ifdef __MSVC__ | 
| Chris@835 | 281     MemoryBarrier(); | 
| Chris@835 | 282 #else /* mingw */ | 
| Chris@835 | 283     LONG Barrier = 0; | 
| Chris@835 | 284     __asm__ __volatile__("xchgl %%eax,%0 " | 
| Chris@835 | 285                          : "=r" (Barrier)); | 
| Chris@835 | 286 #endif | 
| Chris@835 | 287 } | 
| Chris@835 | 288 #else /* !_WIN32 */ | 
| Chris@835 | 289 #if !defined(__APPLE__) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ == 0)) | 
| Chris@835 | 290 void | 
| Chris@835 | 291 SystemMemoryBarrier() | 
| Chris@835 | 292 { | 
| Chris@835 | 293     pthread_mutex_t dummy = PTHREAD_MUTEX_INITIALIZER; | 
| Chris@835 | 294     pthread_mutex_lock(&dummy); | 
| Chris@835 | 295     pthread_mutex_unlock(&dummy); | 
| Chris@835 | 296 } | 
| Chris@835 | 297 #endif /* !defined(__APPLE__) etc */ | 
| Chris@835 | 298 #endif /* !_WIN32 */ | 
| Chris@835 | 299 | 
| Chris@835 | 300 | 
| Chris@303 | 301 static char *startupLocale = 0; | 
| Chris@303 | 302 | 
| Chris@303 | 303 void | 
| Chris@303 | 304 StoreStartupLocale() | 
| Chris@303 | 305 { | 
| Chris@303 | 306     char *loc = setlocale(LC_ALL, 0); | 
| Chris@303 | 307     if (!loc) return; | 
| Chris@303 | 308     if (startupLocale) free(startupLocale); | 
| Chris@303 | 309     startupLocale = strdup(loc); | 
| Chris@303 | 310 } | 
| Chris@303 | 311 | 
| Chris@303 | 312 void | 
| Chris@303 | 313 RestoreStartupLocale() | 
| Chris@303 | 314 { | 
| Chris@303 | 315     if (!startupLocale) { | 
| Chris@303 | 316         setlocale(LC_ALL, ""); | 
| Chris@303 | 317     } else { | 
| Chris@303 | 318         setlocale(LC_ALL, startupLocale); | 
| Chris@303 | 319     } | 
| Chris@303 | 320 } | 
| Chris@223 | 321 | 
| Chris@223 | 322 double mod(double x, double y) { return x - (y * floor(x / y)); } | 
| Chris@223 | 323 float modf(float x, float y) { return x - (y * floorf(x / y)); } | 
| Chris@223 | 324 | 
| Chris@223 | 325 double princarg(double a) { return mod(a + M_PI, -2 * M_PI) + M_PI; } | 
| Chris@1039 | 326 float princargf(float a) { return float(princarg(a)); } | 
| Chris@223 | 327 | 
| Chris@1176 | 328 |