| 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@223 | 59 void usleep(unsigned long usec) | 
| Chris@223 | 60 { | 
| Chris@223 | 61     ::Sleep(usec / 1000); | 
| Chris@223 | 62 } | 
| Chris@223 | 63 | 
| Chris@501 | 64 int gettimeofday(struct timeval *tv, void *tz) | 
| Chris@223 | 65 { | 
| Chris@223 | 66     union { | 
| Chris@223 | 67 	long long ns100; | 
| Chris@223 | 68 	FILETIME ft; | 
| Chris@223 | 69     } now; | 
| Chris@223 | 70 | 
| Chris@223 | 71     ::GetSystemTimeAsFileTime(&now.ft); | 
| Chris@223 | 72     tv->tv_usec = (long)((now.ns100 / 10LL) % 1000000LL); | 
| Chris@223 | 73     tv->tv_sec = (long)((now.ns100 - 116444736000000000LL) / 10000000LL); | 
| Chris@572 | 74     return 0; | 
| Chris@223 | 75 } | 
| Chris@223 | 76 | 
| Chris@223 | 77 } | 
| Chris@223 | 78 | 
| Chris@223 | 79 #endif | 
| Chris@223 | 80 | 
| Chris@223 | 81 ProcessStatus | 
| Chris@223 | 82 GetProcessStatus(int pid) | 
| Chris@223 | 83 { | 
| Chris@223 | 84 #ifdef _WIN32 | 
| Chris@223 | 85     HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); | 
| Chris@223 | 86     if (!handle) { | 
| Chris@223 | 87         return ProcessNotRunning; | 
| Chris@223 | 88     } else { | 
| Chris@223 | 89         CloseHandle(handle); | 
| Chris@223 | 90         return ProcessRunning; | 
| Chris@223 | 91     } | 
| Chris@223 | 92 #else | 
| Chris@223 | 93     if (kill(getpid(), 0) == 0) { | 
| Chris@223 | 94         if (kill(pid, 0) == 0) { | 
| Chris@223 | 95             return ProcessRunning; | 
| Chris@223 | 96         } else { | 
| Chris@223 | 97             return ProcessNotRunning; | 
| Chris@223 | 98         } | 
| Chris@223 | 99     } else { | 
| Chris@223 | 100         return UnknownProcessStatus; | 
| Chris@223 | 101     } | 
| Chris@223 | 102 #endif | 
| Chris@223 | 103 } | 
| Chris@223 | 104 | 
| Chris@223 | 105 #ifdef _WIN32 | 
| Chris@223 | 106 /*  MEMORYSTATUSEX is missing from older Windows headers, so define a | 
| Chris@223 | 107     local replacement.  This trick from MinGW source code.  Ugh */ | 
| Chris@223 | 108 typedef struct | 
| Chris@223 | 109 { | 
| Chris@223 | 110     DWORD dwLength; | 
| Chris@223 | 111     DWORD dwMemoryLoad; | 
| Chris@223 | 112     DWORDLONG ullTotalPhys; | 
| Chris@223 | 113     DWORDLONG ullAvailPhys; | 
| Chris@223 | 114     DWORDLONG ullTotalPageFile; | 
| Chris@223 | 115     DWORDLONG ullAvailPageFile; | 
| Chris@223 | 116     DWORDLONG ullTotalVirtual; | 
| Chris@223 | 117     DWORDLONG ullAvailVirtual; | 
| Chris@223 | 118     DWORDLONG ullAvailExtendedVirtual; | 
| Chris@223 | 119 } lMEMORYSTATUSEX; | 
| Chris@223 | 120 typedef WINBOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*); | 
| Chris@223 | 121 #endif | 
| Chris@223 | 122 | 
| Chris@223 | 123 void | 
| Chris@223 | 124 GetRealMemoryMBAvailable(int &available, int &total) | 
| Chris@223 | 125 { | 
| Chris@223 | 126     available = -1; | 
| Chris@223 | 127     total = -1; | 
| Chris@223 | 128 | 
| Chris@223 | 129 #ifdef _WIN32 | 
| Chris@223 | 130 | 
| Chris@223 | 131     static bool checked = false; | 
| Chris@223 | 132     static bool exFound = false; | 
| Chris@223 | 133     static PFN_MS_EX ex; | 
| Chris@223 | 134 | 
| Chris@223 | 135     if (!checked) { | 
| Chris@223 | 136 | 
| Chris@223 | 137         HMODULE h = GetModuleHandleA("kernel32.dll"); | 
| Chris@223 | 138 | 
| Chris@223 | 139         if (h) { | 
| Chris@223 | 140             if ((ex = (PFN_MS_EX)GetProcAddress(h, "GlobalMemoryStatusEx"))) { | 
| Chris@223 | 141                 exFound = true; | 
| Chris@223 | 142             } | 
| Chris@223 | 143         } | 
| Chris@223 | 144 | 
| Chris@223 | 145         checked = true; | 
| Chris@223 | 146     } | 
| Chris@223 | 147 | 
| Chris@223 | 148     DWORDLONG wavail = 0; | 
| Chris@223 | 149     DWORDLONG wtotal = 0; | 
| Chris@223 | 150 | 
| Chris@223 | 151     if (exFound) { | 
| Chris@223 | 152 | 
| Chris@223 | 153         lMEMORYSTATUSEX lms; | 
| Chris@223 | 154 	lms.dwLength = sizeof(lms); | 
| Chris@223 | 155 	if (!ex(&lms)) { | 
| Chris@223 | 156             std::cerr << "WARNING: GlobalMemoryStatusEx failed: error code " | 
| Chris@223 | 157                       << GetLastError() << std::endl; | 
| Chris@223 | 158             return; | 
| Chris@223 | 159         } | 
| Chris@223 | 160         wavail = lms.ullAvailPhys; | 
| Chris@223 | 161         wtotal = lms.ullTotalPhys; | 
| Chris@223 | 162 | 
| Chris@223 | 163     } else { | 
| Chris@223 | 164 | 
| Chris@223 | 165         /* Fall back to GlobalMemoryStatus which is always available. | 
| Chris@223 | 166            but returns wrong results for physical memory > 4GB  */ | 
| Chris@223 | 167 | 
| Chris@223 | 168 	MEMORYSTATUS ms; | 
| Chris@223 | 169 	GlobalMemoryStatus(&ms); | 
| Chris@223 | 170 	wavail = ms.dwAvailPhys; | 
| Chris@223 | 171         wtotal = ms.dwTotalPhys; | 
| Chris@223 | 172     } | 
| Chris@223 | 173 | 
| Chris@223 | 174     DWORDLONG size = wavail / 1048576; | 
| Chris@223 | 175     if (size > INT_MAX) size = INT_MAX; | 
| Chris@223 | 176     available = int(size); | 
| Chris@223 | 177 | 
| Chris@223 | 178     size = wtotal / 1048576; | 
| Chris@223 | 179     if (size > INT_MAX) size = INT_MAX; | 
| Chris@223 | 180     total = int(size); | 
| Chris@223 | 181 | 
| Chris@223 | 182     return; | 
| Chris@223 | 183 | 
| Chris@223 | 184 #else | 
| Chris@223 | 185 #ifdef __APPLE__ | 
| Chris@223 | 186 | 
| Chris@223 | 187     unsigned int val; | 
| Chris@223 | 188     int mib[2]; | 
| Chris@223 | 189     size_t size_sys; | 
| Chris@223 | 190 | 
| Chris@223 | 191     mib[0] = CTL_HW; | 
| Chris@223 | 192 | 
| Chris@223 | 193     mib[1] = HW_PHYSMEM; | 
| Chris@223 | 194     size_sys = sizeof(val); | 
| Chris@223 | 195     sysctl(mib, 2, &val, &size_sys, NULL, 0); | 
| Chris@223 | 196     if (val) total = val / 1048576; | 
| Chris@223 | 197 | 
| Chris@223 | 198     mib[1] = HW_USERMEM; | 
| Chris@223 | 199     size_sys = sizeof(val); | 
| Chris@223 | 200     sysctl(mib, 2, &val, &size_sys, NULL, 0); | 
| Chris@223 | 201     if (val) available = val / 1048576; | 
| Chris@223 | 202 | 
| Chris@223 | 203     return; | 
| Chris@223 | 204 | 
| Chris@223 | 205 #else | 
| Chris@223 | 206 | 
| Chris@223 | 207     FILE *meminfo = fopen("/proc/meminfo", "r"); | 
| Chris@223 | 208     if (!meminfo) return; | 
| Chris@223 | 209 | 
| Chris@223 | 210     char buf[256]; | 
| Chris@223 | 211     while (!feof(meminfo)) { | 
| Chris@223 | 212         fgets(buf, 256, meminfo); | 
| Chris@223 | 213         bool isMemFree = (strncmp(buf, "MemFree:", 8) == 0); | 
| Chris@223 | 214         bool isMemTotal = (!isMemFree && (strncmp(buf, "MemTotal:", 9) == 0)); | 
| Chris@223 | 215         if (isMemFree || isMemTotal) { | 
| Chris@223 | 216             QString line = QString(buf).trimmed(); | 
| Chris@223 | 217             QStringList elements = line.split(' ', QString::SkipEmptyParts); | 
| Chris@223 | 218             QString unit = "kB"; | 
| Chris@223 | 219             if (elements.size() > 2) unit = elements[2]; | 
| Chris@223 | 220             int size = elements[1].toInt(); | 
| Chris@223 | 221 //            std::cerr << "have size \"" << size << "\", unit \"" | 
| Chris@223 | 222 //                      << unit.toStdString() << "\"" << std::endl; | 
| Chris@223 | 223             if (unit.toLower() == "gb") size = size * 1024; | 
| Chris@223 | 224             else if (unit.toLower() == "mb") size = size; | 
| Chris@223 | 225             else if (unit.toLower() == "kb") size = size / 1024; | 
| Chris@223 | 226             else size = size / 1048576; | 
| Chris@223 | 227 | 
| Chris@223 | 228             if (isMemFree) available = size; | 
| Chris@223 | 229             else total = size; | 
| Chris@223 | 230         } | 
| Chris@223 | 231         if (available != -1 && total != -1) { | 
| Chris@223 | 232             fclose(meminfo); | 
| Chris@223 | 233             return; | 
| Chris@223 | 234         } | 
| Chris@223 | 235     } | 
| Chris@223 | 236     fclose(meminfo); | 
| Chris@223 | 237 | 
| Chris@223 | 238     return; | 
| Chris@223 | 239 | 
| Chris@223 | 240 #endif | 
| Chris@223 | 241 #endif | 
| Chris@223 | 242 } | 
| Chris@223 | 243 | 
| Chris@223 | 244 int | 
| Chris@223 | 245 GetDiscSpaceMBAvailable(const char *path) | 
| Chris@223 | 246 { | 
| Chris@223 | 247 #ifdef _WIN32 | 
| Chris@223 | 248     ULARGE_INTEGER available, total, totalFree; | 
| Chris@223 | 249     if (GetDiskFreeSpaceExA(path, &available, &total, &totalFree)) { | 
| Chris@223 | 250 	  __int64 a = available.QuadPart; | 
| Chris@223 | 251         a /= 1048576; | 
| Chris@223 | 252         if (a > INT_MAX) a = INT_MAX; | 
| Chris@223 | 253         return int(a); | 
| Chris@223 | 254     } else { | 
| Chris@223 | 255         std::cerr << "WARNING: GetDiskFreeSpaceEx failed: error code " | 
| Chris@223 | 256                   << GetLastError() << std::endl; | 
| Chris@223 | 257         return -1; | 
| Chris@223 | 258     } | 
| Chris@223 | 259 #else | 
| Chris@223 | 260     struct statvfs buf; | 
| Chris@223 | 261     if (!statvfs(path, &buf)) { | 
| Chris@223 | 262         // do the multiplies and divides in this order to reduce the | 
| Chris@223 | 263         // likelihood of arithmetic overflow | 
| Chris@436 | 264 //        std::cerr << "statvfs(" << path << ") says available: " << buf.f_bavail << ", block size: " << buf.f_bsize << std::endl; | 
| Chris@223 | 265         uint64_t available = ((buf.f_bavail / 1024) * buf.f_bsize) / 1024; | 
| Chris@223 | 266         if (available > INT_MAX) available = INT_MAX; | 
| Chris@223 | 267         return int(available); | 
| Chris@223 | 268     } else { | 
| Chris@223 | 269         perror("statvfs failed"); | 
| Chris@223 | 270         return -1; | 
| Chris@223 | 271     } | 
| Chris@223 | 272 #endif | 
| Chris@223 | 273 } | 
| Chris@303 | 274 | 
| Chris@303 | 275 static char *startupLocale = 0; | 
| Chris@303 | 276 | 
| Chris@303 | 277 void | 
| Chris@303 | 278 StoreStartupLocale() | 
| Chris@303 | 279 { | 
| Chris@303 | 280     char *loc = setlocale(LC_ALL, 0); | 
| Chris@303 | 281     if (!loc) return; | 
| Chris@303 | 282     if (startupLocale) free(startupLocale); | 
| Chris@303 | 283     startupLocale = strdup(loc); | 
| Chris@303 | 284 } | 
| Chris@303 | 285 | 
| Chris@303 | 286 void | 
| Chris@303 | 287 RestoreStartupLocale() | 
| Chris@303 | 288 { | 
| Chris@303 | 289     if (!startupLocale) { | 
| Chris@303 | 290         setlocale(LC_ALL, ""); | 
| Chris@303 | 291     } else { | 
| Chris@303 | 292         setlocale(LC_ALL, startupLocale); | 
| Chris@303 | 293     } | 
| Chris@303 | 294 } | 
| Chris@223 | 295 | 
| Chris@223 | 296 double mod(double x, double y) { return x - (y * floor(x / y)); } | 
| Chris@223 | 297 float modf(float x, float y) { return x - (y * floorf(x / y)); } | 
| Chris@223 | 298 | 
| Chris@223 | 299 double princarg(double a) { return mod(a + M_PI, -2 * M_PI) + M_PI; } | 
| Chris@223 | 300 float princargf(float a) { return modf(a + M_PI, -2 * M_PI) + M_PI; } | 
| Chris@223 | 301 |