annotate system/System.cpp @ 1879:652c5360e682

Ensure transforms are populated before instantiateDefaultPluginFor runs - otherwise if we have prior knowledge of a transform id, we can find ourselves trying to instantiate it before the plugin factory has heard of it and e.g. knows which server to use
author Chris Cannam
date Thu, 25 Jun 2020 12:20:06 +0100
parents 00405d2cf0d1
children e5d0ea9ac8f1
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@1825 30 #ifndef AVOID_WINRT_DEPENDENCY
Chris@1818 31 #ifdef _MSC_VER
Chris@1818 32 #include <winrt/Windows.UI.ViewManagement.h>
Chris@1818 33 #endif
Chris@1825 34 #endif
Chris@1818 35
Chris@223 36 #ifdef __APPLE__
Chris@223 37 #include <sys/param.h>
Chris@223 38 #include <sys/sysctl.h>
Chris@223 39 #endif
Chris@223 40
Chris@405 41 #include <limits.h>
Chris@405 42 #include <cstdlib>
Chris@405 43
Chris@223 44 #include <iostream>
Chris@223 45
Chris@255 46 #ifdef __APPLE__
Chris@255 47 extern "C" {
Chris@1356 48 void *
Chris@1356 49 rpl_realloc (void *p, size_t n)
Chris@255 50 {
Chris@1356 51 p = realloc(p, n);
Chris@1356 52 if (p == 0 && n == 0)
Chris@1356 53 {
Chris@1356 54 p = malloc(0);
Chris@1356 55 }
Chris@1356 56 return p;
Chris@255 57 }
Chris@255 58 }
Chris@255 59 #endif
Chris@255 60
Chris@223 61 #ifdef _WIN32
Chris@223 62
Chris@223 63 extern "C" {
Chris@223 64
Chris@1218 65 #ifdef _MSC_VER
Chris@1356 66 void usleep(unsigned long usec)
Chris@1356 67 {
Chris@1356 68 ::Sleep(usec / 1000);
Chris@1356 69 }
Chris@1218 70 #endif
Chris@223 71
Chris@1475 72 int gettimeofday(struct timeval *tv, void * /* tz */)
Chris@1356 73 {
Chris@1356 74 union {
Chris@1356 75 long long ns100;
Chris@1356 76 FILETIME ft;
Chris@1356 77 } now;
Chris@223 78
Chris@1356 79 ::GetSystemTimeAsFileTime(&now.ft);
Chris@1356 80 tv->tv_usec = (long)((now.ns100 / 10LL) % 1000000LL);
Chris@1356 81 tv->tv_sec = (long)((now.ns100 - 116444736000000000LL) / 10000000LL);
Chris@1356 82 return 0;
Chris@1356 83 }
Chris@223 84
Chris@223 85 }
Chris@223 86
Chris@223 87 #endif
Chris@223 88
Chris@223 89 ProcessStatus
Chris@223 90 GetProcessStatus(int pid)
Chris@223 91 {
Chris@223 92 #ifdef _WIN32
Chris@223 93 HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
Chris@223 94 if (!handle) {
Chris@223 95 return ProcessNotRunning;
Chris@223 96 } else {
Chris@223 97 CloseHandle(handle);
Chris@223 98 return ProcessRunning;
Chris@223 99 }
Chris@223 100 #else
Chris@223 101 if (kill(getpid(), 0) == 0) {
Chris@223 102 if (kill(pid, 0) == 0) {
Chris@223 103 return ProcessRunning;
Chris@223 104 } else {
Chris@223 105 return ProcessNotRunning;
Chris@223 106 }
Chris@223 107 } else {
Chris@223 108 return UnknownProcessStatus;
Chris@223 109 }
Chris@223 110 #endif
Chris@223 111 }
Chris@223 112
Chris@223 113 #ifdef _WIN32
Chris@223 114 /* MEMORYSTATUSEX is missing from older Windows headers, so define a
Chris@223 115 local replacement. This trick from MinGW source code. Ugh */
Chris@223 116 typedef struct
Chris@223 117 {
Chris@223 118 DWORD dwLength;
Chris@223 119 DWORD dwMemoryLoad;
Chris@223 120 DWORDLONG ullTotalPhys;
Chris@223 121 DWORDLONG ullAvailPhys;
Chris@223 122 DWORDLONG ullTotalPageFile;
Chris@223 123 DWORDLONG ullAvailPageFile;
Chris@223 124 DWORDLONG ullTotalVirtual;
Chris@223 125 DWORDLONG ullAvailVirtual;
Chris@223 126 DWORDLONG ullAvailExtendedVirtual;
Chris@223 127 } lMEMORYSTATUSEX;
Chris@1218 128 typedef BOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*);
Chris@223 129 #endif
Chris@223 130
Chris@223 131 void
Chris@1038 132 GetRealMemoryMBAvailable(ssize_t &available, ssize_t &total)
Chris@223 133 {
Chris@223 134 available = -1;
Chris@223 135 total = -1;
Chris@223 136
Chris@223 137 #ifdef _WIN32
Chris@223 138
Chris@223 139 static bool checked = false;
Chris@223 140 static bool exFound = false;
Chris@223 141 static PFN_MS_EX ex;
Chris@223 142
Chris@223 143 if (!checked) {
Chris@223 144
Chris@223 145 HMODULE h = GetModuleHandleA("kernel32.dll");
Chris@223 146
Chris@223 147 if (h) {
Chris@223 148 if ((ex = (PFN_MS_EX)GetProcAddress(h, "GlobalMemoryStatusEx"))) {
Chris@223 149 exFound = true;
Chris@223 150 }
Chris@223 151 }
Chris@223 152
Chris@223 153 checked = true;
Chris@223 154 }
Chris@223 155
Chris@223 156 DWORDLONG wavail = 0;
Chris@223 157 DWORDLONG wtotal = 0;
Chris@223 158
Chris@223 159 if (exFound) {
Chris@223 160
Chris@223 161 lMEMORYSTATUSEX lms;
Chris@1356 162 lms.dwLength = sizeof(lms);
Chris@1356 163 if (!ex(&lms)) {
Chris@843 164 cerr << "WARNING: GlobalMemoryStatusEx failed: error code "
Chris@1356 165 << GetLastError() << endl;
Chris@223 166 return;
Chris@223 167 }
Chris@223 168 wavail = lms.ullAvailPhys;
Chris@223 169 wtotal = lms.ullTotalPhys;
Chris@223 170
Chris@223 171 } else {
Chris@223 172
Chris@223 173 /* Fall back to GlobalMemoryStatus which is always available.
Chris@223 174 but returns wrong results for physical memory > 4GB */
Chris@223 175
Chris@1356 176 MEMORYSTATUS ms;
Chris@1356 177 GlobalMemoryStatus(&ms);
Chris@1356 178 wavail = ms.dwAvailPhys;
Chris@223 179 wtotal = ms.dwTotalPhys;
Chris@223 180 }
Chris@223 181
Chris@223 182 DWORDLONG size = wavail / 1048576;
Chris@223 183 if (size > INT_MAX) size = INT_MAX;
Chris@1038 184 available = ssize_t(size);
Chris@223 185
Chris@223 186 size = wtotal / 1048576;
Chris@223 187 if (size > INT_MAX) size = INT_MAX;
Chris@1038 188 total = ssize_t(size);
Chris@223 189
Chris@223 190 return;
Chris@223 191
Chris@223 192 #else
Chris@223 193 #ifdef __APPLE__
Chris@223 194
Chris@1779 195 unsigned int val32;
Chris@1779 196 int64_t val64;
Chris@223 197 int mib[2];
Chris@223 198 size_t size_sys;
Chris@223 199
Chris@223 200 mib[0] = CTL_HW;
Chris@223 201
Chris@1779 202 mib[1] = HW_MEMSIZE;
Chris@1779 203 size_sys = sizeof(val64);
Chris@1779 204 sysctl(mib, 2, &val64, &size_sys, NULL, 0);
Chris@1779 205 if (val64) total = val64 / 1048576;
Chris@223 206
Chris@223 207 mib[1] = HW_USERMEM;
Chris@1779 208 size_sys = sizeof(val32);
Chris@1779 209 sysctl(mib, 2, &val32, &size_sys, NULL, 0);
Chris@1779 210 if (val32) available = val32 / 1048576;
Chris@1779 211
Chris@1779 212 // The newer memsize sysctl returns a 64-bit value, but usermem is
Chris@1779 213 // an old 32-bit value that doesn't seem to have an updated
Chris@1779 214 // alternative (?) - so it can't return more than 2G. In practice
Chris@1779 215 // it seems to return values far lower than that, even where more
Chris@1779 216 // than 2G of real memory is free. So we can't actually tell when
Chris@1779 217 // we're getting low on memory at all. Most of the time I think we
Chris@1779 218 // just need to use an arbitrary value like this one.
Chris@1779 219 if (available < total/4) {
Chris@1779 220 available = total/4;
Chris@1779 221 }
Chris@223 222
Chris@223 223 return;
Chris@223 224
Chris@223 225 #else
Chris@223 226
Chris@223 227 FILE *meminfo = fopen("/proc/meminfo", "r");
Chris@223 228 if (!meminfo) return;
Chris@223 229
Chris@223 230 char buf[256];
Chris@223 231 while (!feof(meminfo)) {
Chris@1363 232 if (!fgets(buf, 256, meminfo)) {
Chris@1424 233 fclose(meminfo);
Chris@1363 234 return;
Chris@1363 235 }
Chris@223 236 bool isMemFree = (strncmp(buf, "MemFree:", 8) == 0);
Chris@223 237 bool isMemTotal = (!isMemFree && (strncmp(buf, "MemTotal:", 9) == 0));
Chris@223 238 if (isMemFree || isMemTotal) {
Chris@223 239 QString line = QString(buf).trimmed();
Chris@223 240 QStringList elements = line.split(' ', QString::SkipEmptyParts);
Chris@223 241 QString unit = "kB";
Chris@223 242 if (elements.size() > 2) unit = elements[2];
Chris@223 243 int size = elements[1].toInt();
Chris@843 244 // cerr << "have size \"" << size << "\", unit \""
Chris@843 245 // << unit << "\"" << endl;
Chris@223 246 if (unit.toLower() == "gb") size = size * 1024;
Chris@223 247 else if (unit.toLower() == "mb") size = size;
Chris@223 248 else if (unit.toLower() == "kb") size = size / 1024;
Chris@223 249 else size = size / 1048576;
Chris@223 250
Chris@223 251 if (isMemFree) available = size;
Chris@223 252 else total = size;
Chris@223 253 }
Chris@223 254 if (available != -1 && total != -1) {
Chris@223 255 fclose(meminfo);
Chris@223 256 return;
Chris@223 257 }
Chris@223 258 }
Chris@223 259 fclose(meminfo);
Chris@223 260
Chris@223 261 return;
Chris@223 262
Chris@223 263 #endif
Chris@223 264 #endif
Chris@223 265 }
Chris@223 266
Chris@1038 267 ssize_t
Chris@223 268 GetDiscSpaceMBAvailable(const char *path)
Chris@223 269 {
Chris@223 270 #ifdef _WIN32
Chris@223 271 ULARGE_INTEGER available, total, totalFree;
Chris@223 272 if (GetDiskFreeSpaceExA(path, &available, &total, &totalFree)) {
Chris@1356 273 __int64 a = available.QuadPart;
Chris@223 274 a /= 1048576;
Chris@223 275 if (a > INT_MAX) a = INT_MAX;
Chris@1038 276 return ssize_t(a);
Chris@223 277 } else {
Chris@843 278 cerr << "WARNING: GetDiskFreeSpaceEx failed: error code "
Chris@1356 279 << GetLastError() << endl;
Chris@223 280 return -1;
Chris@223 281 }
Chris@223 282 #else
Chris@223 283 struct statvfs buf;
Chris@223 284 if (!statvfs(path, &buf)) {
Chris@223 285 // do the multiplies and divides in this order to reduce the
Chris@223 286 // likelihood of arithmetic overflow
Chris@843 287 // cerr << "statvfs(" << path << ") says available: " << buf.f_bavail << ", block size: " << buf.f_bsize << endl;
Chris@223 288 uint64_t available = ((buf.f_bavail / 1024) * buf.f_bsize) / 1024;
Chris@223 289 if (available > INT_MAX) available = INT_MAX;
Chris@1038 290 return ssize_t(available);
Chris@223 291 } else {
Chris@223 292 perror("statvfs failed");
Chris@223 293 return -1;
Chris@223 294 }
Chris@223 295 #endif
Chris@223 296 }
Chris@303 297
Chris@835 298 #ifdef _WIN32
Chris@835 299 extern void SystemMemoryBarrier()
Chris@835 300 {
Chris@1218 301 #ifdef _MSC_VER
Chris@835 302 MemoryBarrier();
Chris@835 303 #else /* mingw */
Chris@835 304 LONG Barrier = 0;
Chris@835 305 __asm__ __volatile__("xchgl %%eax,%0 "
Chris@835 306 : "=r" (Barrier));
Chris@835 307 #endif
Chris@835 308 }
Chris@835 309 #else /* !_WIN32 */
Chris@1357 310 #if !defined(__APPLE__) && defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ == 0))
Chris@835 311 void
Chris@835 312 SystemMemoryBarrier()
Chris@835 313 {
Chris@835 314 pthread_mutex_t dummy = PTHREAD_MUTEX_INITIALIZER;
Chris@835 315 pthread_mutex_lock(&dummy);
Chris@835 316 pthread_mutex_unlock(&dummy);
Chris@835 317 }
Chris@835 318 #endif /* !defined(__APPLE__) etc */
Chris@835 319 #endif /* !_WIN32 */
Chris@835 320
Chris@835 321
Chris@1582 322 static char *startupLocale = nullptr;
Chris@303 323
Chris@303 324 void
Chris@303 325 StoreStartupLocale()
Chris@303 326 {
Chris@1582 327 char *loc = setlocale(LC_ALL, nullptr);
Chris@303 328 if (!loc) return;
Chris@303 329 if (startupLocale) free(startupLocale);
Chris@303 330 startupLocale = strdup(loc);
Chris@303 331 }
Chris@303 332
Chris@303 333 void
Chris@303 334 RestoreStartupLocale()
Chris@303 335 {
Chris@303 336 if (!startupLocale) {
Chris@303 337 setlocale(LC_ALL, "");
Chris@303 338 } else {
Chris@303 339 setlocale(LC_ALL, startupLocale);
Chris@303 340 }
Chris@303 341 }
Chris@223 342
Chris@1818 343 bool
Chris@1819 344 OSReportsDarkThemeActive()
Chris@1818 345 {
Chris@1825 346 #ifndef AVOID_WINRT_DEPENDENCY
Chris@1818 347 #ifdef _MSC_VER
Chris@1818 348 using namespace winrt::Windows::UI::ViewManagement;
Chris@1818 349 UISettings settings;
Chris@1818 350 auto background = settings.GetColorValue(UIColorType::Background);
Chris@1818 351 if (int(background.R) + int(background.G) + int(background.B) < 384) {
Chris@1818 352 return true;
Chris@1818 353 }
Chris@1818 354 #endif
Chris@1825 355 #endif
Chris@1818 356 return false;
Chris@1818 357 }
Chris@1818 358
Chris@1820 359 bool
Chris@1820 360 OSQueryAccentColour(int &r, int &g, int &b)
Chris@1820 361 {
Chris@1820 362 SVCERR << "OSQueryAccentColour() called" << endl;
Chris@1825 363 #ifndef AVOID_WINRT_DEPENDENCY
Chris@1820 364 #ifdef _MSC_VER
Chris@1820 365 using namespace winrt::Windows::UI::ViewManagement;
Chris@1821 366 bool dark = OSReportsDarkThemeActive();
Chris@1820 367 UISettings settings;
Chris@1821 368 auto accent = settings.GetColorValue
Chris@1821 369 (dark ? UIColorType::AccentLight1 : UIColorType::Accent);
Chris@1821 370 r = accent.R;
Chris@1821 371 g = accent.G;
Chris@1821 372 b = accent.B;
Chris@1820 373 return true;
Chris@1820 374 #endif
Chris@1825 375 #endif
Chris@1826 376 (void)r;
Chris@1826 377 (void)g;
Chris@1826 378 (void)b;
Chris@1820 379 return false;
Chris@1820 380 }
Chris@1820 381
Chris@223 382 double mod(double x, double y) { return x - (y * floor(x / y)); }
Chris@223 383 float modf(float x, float y) { return x - (y * floorf(x / y)); }
Chris@223 384
Chris@223 385 double princarg(double a) { return mod(a + M_PI, -2 * M_PI) + M_PI; }
Chris@1039 386 float princargf(float a) { return float(princarg(a)); }
Chris@223 387
Chris@1475 388 bool
Chris@1475 389 getEnvUtf8(std::string variable, std::string &value)
Chris@1475 390 {
Chris@1475 391 value = "";
Chris@1475 392
Chris@1475 393 #ifdef _WIN32
Chris@1475 394 int wvarlen = MultiByteToWideChar(CP_UTF8, 0,
Chris@1475 395 variable.c_str(), int(variable.length()),
Chris@1475 396 0, 0);
Chris@1475 397 if (wvarlen < 0) {
Chris@1475 398 SVCERR << "WARNING: Unable to convert environment variable name "
Chris@1475 399 << variable << " to wide characters" << endl;
Chris@1475 400 return false;
Chris@1475 401 }
Chris@1475 402
Chris@1475 403 wchar_t *wvarbuf = new wchar_t[wvarlen + 1];
Chris@1475 404 (void)MultiByteToWideChar(CP_UTF8, 0,
Chris@1475 405 variable.c_str(), int(variable.length()),
Chris@1475 406 wvarbuf, wvarlen);
Chris@1475 407 wvarbuf[wvarlen] = L'\0';
Chris@1475 408
Chris@1475 409 wchar_t *wvalue = _wgetenv(wvarbuf);
Chris@1176 410
Chris@1475 411 delete[] wvarbuf;
Chris@1475 412
Chris@1475 413 if (!wvalue) {
Chris@1475 414 return false;
Chris@1475 415 }
Chris@1475 416
Chris@1480 417 int wvallen = int(wcslen(wvalue));
Chris@1475 418 int vallen = WideCharToMultiByte(CP_UTF8, 0,
Chris@1480 419 wvalue, wvallen,
Chris@1475 420 0, 0, 0, 0);
Chris@1475 421 if (vallen < 0) {
Chris@1475 422 SVCERR << "WARNING: Unable to convert environment value to UTF-8"
Chris@1475 423 << endl;
Chris@1475 424 return false;
Chris@1475 425 }
Chris@1475 426
Chris@1475 427 char *val = new char[vallen + 1];
Chris@1475 428 (void)WideCharToMultiByte(CP_UTF8, 0,
Chris@1480 429 wvalue, wvallen,
Chris@1475 430 val, vallen, 0, 0);
Chris@1475 431 val[vallen] = '\0';
Chris@1475 432
Chris@1475 433 value = val;
Chris@1475 434
Chris@1475 435 delete[] val;
Chris@1475 436 return true;
Chris@1475 437
Chris@1475 438 #else
Chris@1475 439
Chris@1475 440 char *val = getenv(variable.c_str());
Chris@1475 441 if (!val) {
Chris@1475 442 return false;
Chris@1475 443 }
Chris@1475 444
Chris@1475 445 value = val;
Chris@1475 446 return true;
Chris@1475 447
Chris@1475 448 #endif
Chris@1475 449 }
Chris@1475 450
Chris@1475 451 bool
Chris@1475 452 putEnvUtf8(std::string variable, std::string value)
Chris@1475 453 {
Chris@1477 454 #ifdef _WIN32
Chris@1475 455 std::string entry = variable + "=" + value;
Chris@1475 456
Chris@1475 457 int wentlen = MultiByteToWideChar(CP_UTF8, 0,
Chris@1475 458 entry.c_str(), int(entry.length()),
Chris@1475 459 0, 0);
Chris@1475 460 if (wentlen < 0) {
Chris@1475 461 SVCERR << "WARNING: Unable to convert environment entry to "
Chris@1475 462 << "wide characters" << endl;
Chris@1475 463 return false;
Chris@1475 464 }
Chris@1475 465
Chris@1475 466 wchar_t *wentbuf = new wchar_t[wentlen + 1];
Chris@1475 467 (void)MultiByteToWideChar(CP_UTF8, 0,
Chris@1475 468 entry.c_str(), int(entry.length()),
Chris@1475 469 wentbuf, wentlen);
Chris@1475 470 wentbuf[wentlen] = L'\0';
Chris@1475 471
Chris@1475 472 int rv = _wputenv(wentbuf);
Chris@1475 473
Chris@1475 474 delete[] wentbuf;
Chris@1475 475
Chris@1475 476 if (rv != 0) {
Chris@1475 477 SVCERR << "WARNING: Failed to set environment entry" << endl;
Chris@1475 478 return false;
Chris@1475 479 }
Chris@1475 480 return true;
Chris@1475 481
Chris@1475 482 #else
Chris@1475 483
Chris@1477 484 int rv = setenv(variable.c_str(), value.c_str(), 1);
Chris@1475 485 if (rv != 0) {
Chris@1475 486 SVCERR << "WARNING: Failed to set environment entry" << endl;
Chris@1475 487 return false;
Chris@1475 488 }
Chris@1475 489 return true;
Chris@1475 490
Chris@1475 491 #endif
Chris@1475 492 }
Chris@1475 493