annotate system/System.cpp @ 1671:82d03c9661f9 single-point

Rework isReady()/getCompletion() on models. Previously the new overhauled models were implementing getCompletion() but inheriting a version of isReady() (from the Model base) that didn't call it, referring only to isOK(). So they were reporting completion as soon as they had begun. Instead hoist getCompletion() to abstract base and call it from Model::isReady().
author Chris Cannam
date Wed, 27 Mar 2019 13:15:16 +0000
parents 70e172e6cc59
children 85903b0e9b42
rev   line source
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@1356 4 Sonic Visualiser
Chris@1356 5 An audio file viewer and annotation editor.
Chris@1356 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1475 7 This file copyright 2006-2018 Chris Cannam and QMUL.
Chris@223 8
Chris@1356 9 This program is free software; you can redistribute it and/or
Chris@1356 10 modify it under the terms of the GNU General Public License as
Chris@1356 11 published by the Free Software Foundation; either version 2 of the
Chris@1356 12 License, or (at your option) any later version. See the file
Chris@1356 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@1356 42 void *
Chris@1356 43 rpl_realloc (void *p, size_t n)
Chris@255 44 {
Chris@1356 45 p = realloc(p, n);
Chris@1356 46 if (p == 0 && n == 0)
Chris@1356 47 {
Chris@1356 48 p = malloc(0);
Chris@1356 49 }
Chris@1356 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@1218 59 #ifdef _MSC_VER
Chris@1356 60 void usleep(unsigned long usec)
Chris@1356 61 {
Chris@1356 62 ::Sleep(usec / 1000);
Chris@1356 63 }
Chris@1218 64 #endif
Chris@223 65
Chris@1475 66 int gettimeofday(struct timeval *tv, void * /* tz */)
Chris@1356 67 {
Chris@1356 68 union {
Chris@1356 69 long long ns100;
Chris@1356 70 FILETIME ft;
Chris@1356 71 } now;
Chris@223 72
Chris@1356 73 ::GetSystemTimeAsFileTime(&now.ft);
Chris@1356 74 tv->tv_usec = (long)((now.ns100 / 10LL) % 1000000LL);
Chris@1356 75 tv->tv_sec = (long)((now.ns100 - 116444736000000000LL) / 10000000LL);
Chris@1356 76 return 0;
Chris@1356 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@1218 122 typedef BOOL (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@1356 156 lms.dwLength = sizeof(lms);
Chris@1356 157 if (!ex(&lms)) {
Chris@843 158 cerr << "WARNING: GlobalMemoryStatusEx failed: error code "
Chris@1356 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@1356 170 MEMORYSTATUS ms;
Chris@1356 171 GlobalMemoryStatus(&ms);
Chris@1356 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@1363 214 if (!fgets(buf, 256, meminfo)) {
Chris@1424 215 fclose(meminfo);
Chris@1363 216 return;
Chris@1363 217 }
Chris@223 218 bool isMemFree = (strncmp(buf, "MemFree:", 8) == 0);
Chris@223 219 bool isMemTotal = (!isMemFree && (strncmp(buf, "MemTotal:", 9) == 0));
Chris@223 220 if (isMemFree || isMemTotal) {
Chris@223 221 QString line = QString(buf).trimmed();
Chris@223 222 QStringList elements = line.split(' ', QString::SkipEmptyParts);
Chris@223 223 QString unit = "kB";
Chris@223 224 if (elements.size() > 2) unit = elements[2];
Chris@223 225 int size = elements[1].toInt();
Chris@843 226 // cerr << "have size \"" << size << "\", unit \""
Chris@843 227 // << unit << "\"" << endl;
Chris@223 228 if (unit.toLower() == "gb") size = size * 1024;
Chris@223 229 else if (unit.toLower() == "mb") size = size;
Chris@223 230 else if (unit.toLower() == "kb") size = size / 1024;
Chris@223 231 else size = size / 1048576;
Chris@223 232
Chris@223 233 if (isMemFree) available = size;
Chris@223 234 else total = size;
Chris@223 235 }
Chris@223 236 if (available != -1 && total != -1) {
Chris@223 237 fclose(meminfo);
Chris@223 238 return;
Chris@223 239 }
Chris@223 240 }
Chris@223 241 fclose(meminfo);
Chris@223 242
Chris@223 243 return;
Chris@223 244
Chris@223 245 #endif
Chris@223 246 #endif
Chris@223 247 }
Chris@223 248
Chris@1038 249 ssize_t
Chris@223 250 GetDiscSpaceMBAvailable(const char *path)
Chris@223 251 {
Chris@223 252 #ifdef _WIN32
Chris@223 253 ULARGE_INTEGER available, total, totalFree;
Chris@223 254 if (GetDiskFreeSpaceExA(path, &available, &total, &totalFree)) {
Chris@1356 255 __int64 a = available.QuadPart;
Chris@223 256 a /= 1048576;
Chris@223 257 if (a > INT_MAX) a = INT_MAX;
Chris@1038 258 return ssize_t(a);
Chris@223 259 } else {
Chris@843 260 cerr << "WARNING: GetDiskFreeSpaceEx failed: error code "
Chris@1356 261 << GetLastError() << endl;
Chris@223 262 return -1;
Chris@223 263 }
Chris@223 264 #else
Chris@223 265 struct statvfs buf;
Chris@223 266 if (!statvfs(path, &buf)) {
Chris@223 267 // do the multiplies and divides in this order to reduce the
Chris@223 268 // likelihood of arithmetic overflow
Chris@843 269 // cerr << "statvfs(" << path << ") says available: " << buf.f_bavail << ", block size: " << buf.f_bsize << endl;
Chris@223 270 uint64_t available = ((buf.f_bavail / 1024) * buf.f_bsize) / 1024;
Chris@223 271 if (available > INT_MAX) available = INT_MAX;
Chris@1038 272 return ssize_t(available);
Chris@223 273 } else {
Chris@223 274 perror("statvfs failed");
Chris@223 275 return -1;
Chris@223 276 }
Chris@223 277 #endif
Chris@223 278 }
Chris@303 279
Chris@835 280 #ifdef _WIN32
Chris@835 281 extern void SystemMemoryBarrier()
Chris@835 282 {
Chris@1218 283 #ifdef _MSC_VER
Chris@835 284 MemoryBarrier();
Chris@835 285 #else /* mingw */
Chris@835 286 LONG Barrier = 0;
Chris@835 287 __asm__ __volatile__("xchgl %%eax,%0 "
Chris@835 288 : "=r" (Barrier));
Chris@835 289 #endif
Chris@835 290 }
Chris@835 291 #else /* !_WIN32 */
Chris@1357 292 #if !defined(__APPLE__) && defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ == 0))
Chris@835 293 void
Chris@835 294 SystemMemoryBarrier()
Chris@835 295 {
Chris@835 296 pthread_mutex_t dummy = PTHREAD_MUTEX_INITIALIZER;
Chris@835 297 pthread_mutex_lock(&dummy);
Chris@835 298 pthread_mutex_unlock(&dummy);
Chris@835 299 }
Chris@835 300 #endif /* !defined(__APPLE__) etc */
Chris@835 301 #endif /* !_WIN32 */
Chris@835 302
Chris@835 303
Chris@1582 304 static char *startupLocale = nullptr;
Chris@303 305
Chris@303 306 void
Chris@303 307 StoreStartupLocale()
Chris@303 308 {
Chris@1582 309 char *loc = setlocale(LC_ALL, nullptr);
Chris@303 310 if (!loc) return;
Chris@303 311 if (startupLocale) free(startupLocale);
Chris@303 312 startupLocale = strdup(loc);
Chris@303 313 }
Chris@303 314
Chris@303 315 void
Chris@303 316 RestoreStartupLocale()
Chris@303 317 {
Chris@303 318 if (!startupLocale) {
Chris@303 319 setlocale(LC_ALL, "");
Chris@303 320 } else {
Chris@303 321 setlocale(LC_ALL, startupLocale);
Chris@303 322 }
Chris@303 323 }
Chris@223 324
Chris@223 325 double mod(double x, double y) { return x - (y * floor(x / y)); }
Chris@223 326 float modf(float x, float y) { return x - (y * floorf(x / y)); }
Chris@223 327
Chris@223 328 double princarg(double a) { return mod(a + M_PI, -2 * M_PI) + M_PI; }
Chris@1039 329 float princargf(float a) { return float(princarg(a)); }
Chris@223 330
Chris@1475 331 bool
Chris@1475 332 getEnvUtf8(std::string variable, std::string &value)
Chris@1475 333 {
Chris@1475 334 value = "";
Chris@1475 335
Chris@1475 336 #ifdef _WIN32
Chris@1475 337 int wvarlen = MultiByteToWideChar(CP_UTF8, 0,
Chris@1475 338 variable.c_str(), int(variable.length()),
Chris@1475 339 0, 0);
Chris@1475 340 if (wvarlen < 0) {
Chris@1475 341 SVCERR << "WARNING: Unable to convert environment variable name "
Chris@1475 342 << variable << " to wide characters" << endl;
Chris@1475 343 return false;
Chris@1475 344 }
Chris@1475 345
Chris@1475 346 wchar_t *wvarbuf = new wchar_t[wvarlen + 1];
Chris@1475 347 (void)MultiByteToWideChar(CP_UTF8, 0,
Chris@1475 348 variable.c_str(), int(variable.length()),
Chris@1475 349 wvarbuf, wvarlen);
Chris@1475 350 wvarbuf[wvarlen] = L'\0';
Chris@1475 351
Chris@1475 352 wchar_t *wvalue = _wgetenv(wvarbuf);
Chris@1176 353
Chris@1475 354 delete[] wvarbuf;
Chris@1475 355
Chris@1475 356 if (!wvalue) {
Chris@1475 357 return false;
Chris@1475 358 }
Chris@1475 359
Chris@1480 360 int wvallen = int(wcslen(wvalue));
Chris@1475 361 int vallen = WideCharToMultiByte(CP_UTF8, 0,
Chris@1480 362 wvalue, wvallen,
Chris@1475 363 0, 0, 0, 0);
Chris@1475 364 if (vallen < 0) {
Chris@1475 365 SVCERR << "WARNING: Unable to convert environment value to UTF-8"
Chris@1475 366 << endl;
Chris@1475 367 return false;
Chris@1475 368 }
Chris@1475 369
Chris@1475 370 char *val = new char[vallen + 1];
Chris@1475 371 (void)WideCharToMultiByte(CP_UTF8, 0,
Chris@1480 372 wvalue, wvallen,
Chris@1475 373 val, vallen, 0, 0);
Chris@1475 374 val[vallen] = '\0';
Chris@1475 375
Chris@1475 376 value = val;
Chris@1475 377
Chris@1475 378 delete[] val;
Chris@1475 379 return true;
Chris@1475 380
Chris@1475 381 #else
Chris@1475 382
Chris@1475 383 char *val = getenv(variable.c_str());
Chris@1475 384 if (!val) {
Chris@1475 385 return false;
Chris@1475 386 }
Chris@1475 387
Chris@1475 388 value = val;
Chris@1475 389 return true;
Chris@1475 390
Chris@1475 391 #endif
Chris@1475 392 }
Chris@1475 393
Chris@1475 394 bool
Chris@1475 395 putEnvUtf8(std::string variable, std::string value)
Chris@1475 396 {
Chris@1477 397 #ifdef _WIN32
Chris@1475 398 std::string entry = variable + "=" + value;
Chris@1475 399
Chris@1475 400 int wentlen = MultiByteToWideChar(CP_UTF8, 0,
Chris@1475 401 entry.c_str(), int(entry.length()),
Chris@1475 402 0, 0);
Chris@1475 403 if (wentlen < 0) {
Chris@1475 404 SVCERR << "WARNING: Unable to convert environment entry to "
Chris@1475 405 << "wide characters" << endl;
Chris@1475 406 return false;
Chris@1475 407 }
Chris@1475 408
Chris@1475 409 wchar_t *wentbuf = new wchar_t[wentlen + 1];
Chris@1475 410 (void)MultiByteToWideChar(CP_UTF8, 0,
Chris@1475 411 entry.c_str(), int(entry.length()),
Chris@1475 412 wentbuf, wentlen);
Chris@1475 413 wentbuf[wentlen] = L'\0';
Chris@1475 414
Chris@1475 415 int rv = _wputenv(wentbuf);
Chris@1475 416
Chris@1475 417 delete[] wentbuf;
Chris@1475 418
Chris@1475 419 if (rv != 0) {
Chris@1475 420 SVCERR << "WARNING: Failed to set environment entry" << endl;
Chris@1475 421 return false;
Chris@1475 422 }
Chris@1475 423 return true;
Chris@1475 424
Chris@1475 425 #else
Chris@1475 426
Chris@1477 427 int rv = setenv(variable.c_str(), value.c_str(), 1);
Chris@1475 428 if (rv != 0) {
Chris@1475 429 SVCERR << "WARNING: Failed to set environment entry" << endl;
Chris@1475 430 return false;
Chris@1475 431 }
Chris@1475 432 return true;
Chris@1475 433
Chris@1475 434 #endif
Chris@1475 435 }
Chris@1475 436