svcore  1.9
System.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam and QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "System.h"
00017 
00018 #include <QStringList>
00019 #include <QString>
00020 
00021 #include <stdint.h>
00022 
00023 #ifndef _WIN32
00024 #include <signal.h>
00025 #include <sys/statvfs.h>
00026 #include <locale.h>
00027 #include <unistd.h>
00028 #endif
00029 
00030 #ifdef __APPLE__
00031 #include <sys/param.h>
00032 #include <sys/sysctl.h>
00033 #endif
00034 
00035 #include <limits.h>
00036 #include <cstdlib>
00037 
00038 #include <iostream>
00039 
00040 #ifdef __APPLE__
00041 extern "C" {
00042 void *
00043 rpl_realloc (void *p, size_t n)
00044 {
00045     p = realloc(p, n);
00046     if (p == 0 && n == 0)
00047     {
00048     p = malloc(0);
00049     }
00050     return p;
00051 }
00052 }
00053 #endif
00054 
00055 #ifdef _WIN32
00056 
00057 extern "C" {
00058 
00059 /* usleep is now in mingw
00060 void usleep(unsigned long usec)
00061 {
00062     ::Sleep(usec / 1000);
00063 }
00064 */
00065 
00066 int gettimeofday(struct timeval *tv, void *tz)
00067 {
00068     union { 
00069         long long ns100;  
00070         FILETIME ft; 
00071     } now; 
00072     
00073     ::GetSystemTimeAsFileTime(&now.ft); 
00074     tv->tv_usec = (long)((now.ns100 / 10LL) % 1000000LL); 
00075     tv->tv_sec = (long)((now.ns100 - 116444736000000000LL) / 10000000LL); 
00076     return 0;
00077 }
00078 
00079 }
00080 
00081 #endif
00082 
00083 ProcessStatus
00084 GetProcessStatus(int pid)
00085 {
00086 #ifdef _WIN32
00087     HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
00088     if (!handle) {
00089         return ProcessNotRunning;
00090     } else {
00091         CloseHandle(handle);
00092         return ProcessRunning;
00093     }
00094 #else
00095     if (kill(getpid(), 0) == 0) {
00096         if (kill(pid, 0) == 0) {
00097             return ProcessRunning;
00098         } else {
00099             return ProcessNotRunning;
00100         }
00101     } else {
00102         return UnknownProcessStatus;
00103     }
00104 #endif
00105 }
00106 
00107 #ifdef _WIN32
00108 /*  MEMORYSTATUSEX is missing from older Windows headers, so define a
00109     local replacement.  This trick from MinGW source code.  Ugh */
00110 typedef struct
00111 {
00112     DWORD dwLength;
00113     DWORD dwMemoryLoad;
00114     DWORDLONG ullTotalPhys;
00115     DWORDLONG ullAvailPhys;
00116     DWORDLONG ullTotalPageFile;
00117     DWORDLONG ullAvailPageFile;
00118     DWORDLONG ullTotalVirtual;
00119     DWORDLONG ullAvailVirtual;
00120     DWORDLONG ullAvailExtendedVirtual;
00121 } lMEMORYSTATUSEX;
00122 typedef WINBOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*);
00123 #endif
00124 
00125 void
00126 GetRealMemoryMBAvailable(int &available, int &total)
00127 {
00128     available = -1;
00129     total = -1;
00130 
00131 #ifdef _WIN32
00132 
00133     static bool checked = false;
00134     static bool exFound = false;
00135     static PFN_MS_EX ex;
00136 
00137     if (!checked) {
00138 
00139         HMODULE h = GetModuleHandleA("kernel32.dll");
00140 
00141         if (h) {
00142             if ((ex = (PFN_MS_EX)GetProcAddress(h, "GlobalMemoryStatusEx"))) {
00143                 exFound = true;
00144             }
00145         }
00146         
00147         checked = true;
00148     }
00149 
00150     DWORDLONG wavail = 0;
00151     DWORDLONG wtotal = 0;
00152 
00153     if (exFound) {
00154 
00155         lMEMORYSTATUSEX lms;
00156         lms.dwLength = sizeof(lms);
00157         if (!ex(&lms)) {
00158             cerr << "WARNING: GlobalMemoryStatusEx failed: error code "
00159                       << GetLastError() << endl;
00160             return;
00161         }
00162         wavail = lms.ullAvailPhys;
00163         wtotal = lms.ullTotalPhys;
00164 
00165     } else {
00166 
00167         /* Fall back to GlobalMemoryStatus which is always available.
00168            but returns wrong results for physical memory > 4GB  */
00169 
00170         MEMORYSTATUS ms;
00171         GlobalMemoryStatus(&ms);
00172         wavail = ms.dwAvailPhys;
00173         wtotal = ms.dwTotalPhys;
00174     }
00175 
00176     DWORDLONG size = wavail / 1048576;
00177     if (size > INT_MAX) size = INT_MAX;
00178     available = int(size);
00179 
00180     size = wtotal / 1048576;
00181     if (size > INT_MAX) size = INT_MAX;
00182     total = int(size);
00183 
00184     return;
00185 
00186 #else
00187 #ifdef __APPLE__
00188 
00189     unsigned int val;
00190     int mib[2];
00191     size_t size_sys;
00192     
00193     mib[0] = CTL_HW;
00194 
00195     mib[1] = HW_PHYSMEM;
00196     size_sys = sizeof(val);
00197     sysctl(mib, 2, &val, &size_sys, NULL, 0);
00198     if (val) total = val / 1048576;
00199 
00200     mib[1] = HW_USERMEM;
00201     size_sys = sizeof(val);
00202     sysctl(mib, 2, &val, &size_sys, NULL, 0);
00203     if (val) available = val / 1048576;
00204 
00205     return;
00206 
00207 #else
00208 
00209     FILE *meminfo = fopen("/proc/meminfo", "r");
00210     if (!meminfo) return;
00211 
00212     char buf[256];
00213     while (!feof(meminfo)) {
00214         fgets(buf, 256, meminfo);
00215         bool isMemFree = (strncmp(buf, "MemFree:", 8) == 0);
00216         bool isMemTotal = (!isMemFree && (strncmp(buf, "MemTotal:", 9) == 0));
00217         if (isMemFree || isMemTotal) {
00218             QString line = QString(buf).trimmed();
00219             QStringList elements = line.split(' ', QString::SkipEmptyParts);
00220             QString unit = "kB";
00221             if (elements.size() > 2) unit = elements[2];
00222             int size = elements[1].toInt();
00223 //            cerr << "have size \"" << size << "\", unit \""
00224 //                      << unit << "\"" << endl;
00225             if (unit.toLower() == "gb") size = size * 1024;
00226             else if (unit.toLower() == "mb") size = size;
00227             else if (unit.toLower() == "kb") size = size / 1024;
00228             else size = size / 1048576;
00229 
00230             if (isMemFree) available = size;
00231             else total = size;
00232         }
00233         if (available != -1 && total != -1) {
00234             fclose(meminfo);
00235             return;
00236         }
00237     }
00238     fclose(meminfo);
00239 
00240     return;
00241 
00242 #endif
00243 #endif
00244 }
00245 
00246 int
00247 GetDiscSpaceMBAvailable(const char *path)
00248 {
00249 #ifdef _WIN32
00250     ULARGE_INTEGER available, total, totalFree;
00251     if (GetDiskFreeSpaceExA(path, &available, &total, &totalFree)) {
00252           __int64 a = available.QuadPart;
00253         a /= 1048576;
00254         if (a > INT_MAX) a = INT_MAX;
00255         return int(a);
00256     } else {
00257         cerr << "WARNING: GetDiskFreeSpaceEx failed: error code "
00258                   << GetLastError() << endl;
00259         return -1;
00260     }
00261 #else
00262     struct statvfs buf;
00263     if (!statvfs(path, &buf)) {
00264         // do the multiplies and divides in this order to reduce the
00265         // likelihood of arithmetic overflow
00266 //        cerr << "statvfs(" << path << ") says available: " << buf.f_bavail << ", block size: " << buf.f_bsize << endl;
00267         uint64_t available = ((buf.f_bavail / 1024) * buf.f_bsize) / 1024;
00268         if (available > INT_MAX) available = INT_MAX;
00269         return int(available);
00270     } else {
00271         perror("statvfs failed");
00272         return -1;
00273     }
00274 #endif
00275 }
00276 
00277 #ifdef _WIN32
00278 extern void SystemMemoryBarrier()
00279 {
00280 #ifdef __MSVC__
00281     MemoryBarrier();
00282 #else /* mingw */
00283     LONG Barrier = 0;
00284     __asm__ __volatile__("xchgl %%eax,%0 "
00285                          : "=r" (Barrier));
00286 #endif
00287 }
00288 #else /* !_WIN32 */
00289 #if !defined(__APPLE__) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ == 0))
00290 void
00291 SystemMemoryBarrier()
00292 {
00293     pthread_mutex_t dummy = PTHREAD_MUTEX_INITIALIZER;
00294     pthread_mutex_lock(&dummy);
00295     pthread_mutex_unlock(&dummy);
00296 }
00297 #endif /* !defined(__APPLE__) etc */
00298 #endif /* !_WIN32 */
00299 
00300 
00301 static char *startupLocale = 0;
00302 
00303 void
00304 StoreStartupLocale()
00305 {
00306     char *loc = setlocale(LC_ALL, 0);
00307     if (!loc) return;
00308     if (startupLocale) free(startupLocale);
00309     startupLocale = strdup(loc);
00310 }
00311 
00312 void
00313 RestoreStartupLocale()
00314 {
00315     if (!startupLocale) {
00316         setlocale(LC_ALL, "");
00317     } else {
00318         setlocale(LC_ALL, startupLocale);
00319     }
00320 }
00321 
00322 double mod(double x, double y) { return x - (y * floor(x / y)); }
00323 float modf(float x, float y) { return x - (y * floorf(x / y)); }
00324 
00325 double princarg(double a) { return mod(a + M_PI, -2 * M_PI) + M_PI; }
00326 float princargf(float a) { return modf(a + M_PI, -2 * M_PI) + M_PI; }
00327