1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    The code included in this file is provided under the terms of the ISC license
11    http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12    To use, copy, modify, and/or distribute this software for any purpose with or
13    without fee is hereby granted provided that the above copyright notice and
14    this permission notice appear in all copies.
15 
16    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18    DISCLAIMED.
19 
20   ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
getJUCEVersion()26 String SystemStats::getJUCEVersion()
27 {
28     // Some basic tests, to keep an eye on things and make sure these types work ok
29     // on all platforms. Let me know if any of these assertions fail on your system!
30     static_assert (sizeof (pointer_sized_int) == sizeof (void*), "Basic sanity test failed: please report!");
31     static_assert (sizeof (int8) == 1,                           "Basic sanity test failed: please report!");
32     static_assert (sizeof (uint8) == 1,                          "Basic sanity test failed: please report!");
33     static_assert (sizeof (int16) == 2,                          "Basic sanity test failed: please report!");
34     static_assert (sizeof (uint16) == 2,                         "Basic sanity test failed: please report!");
35     static_assert (sizeof (int32) == 4,                          "Basic sanity test failed: please report!");
36     static_assert (sizeof (uint32) == 4,                         "Basic sanity test failed: please report!");
37     static_assert (sizeof (int64) == 8,                          "Basic sanity test failed: please report!");
38     static_assert (sizeof (uint64) == 8,                         "Basic sanity test failed: please report!");
39 
40     return "JUCE v" JUCE_STRINGIFY(JUCE_MAJOR_VERSION)
41                 "." JUCE_STRINGIFY(JUCE_MINOR_VERSION)
42                 "." JUCE_STRINGIFY(JUCE_BUILDNUMBER);
43 }
44 
45 #if JUCE_ANDROID && ! defined (JUCE_DISABLE_JUCE_VERSION_PRINTING)
46  #define JUCE_DISABLE_JUCE_VERSION_PRINTING 1
47 #endif
48 
49 #if JUCE_DEBUG && ! JUCE_DISABLE_JUCE_VERSION_PRINTING
50  struct JuceVersionPrinter
51  {
JuceVersionPrinterjuce::JuceVersionPrinter52      JuceVersionPrinter()
53      {
54          DBG (SystemStats::getJUCEVersion());
55      }
56  };
57 
58  static JuceVersionPrinter juceVersionPrinter;
59 #endif
60 
getDeviceIdentifiers()61 StringArray SystemStats::getDeviceIdentifiers()
62 {
63     StringArray ids;
64 
65    #if JUCE_WINDOWS
66     File f (File::getSpecialLocation (File::windowsSystemDirectory));
67    #else
68     File f ("~");
69    #endif
70     if (auto num = f.getFileIdentifier())
71     {
72         ids.add (String::toHexString ((int64) num));
73     }
74     else
75     {
76         for (auto& address : MACAddress::getAllAddresses())
77             ids.add (address.toString());
78     }
79 
80     jassert (! ids.isEmpty()); // Failed to create any IDs!
81     return ids;
82 }
83 
84 //==============================================================================
85 struct CPUInformation
86 {
CPUInformationjuce::CPUInformation87     CPUInformation() noexcept    { initialise(); }
88 
89     void initialise() noexcept;
90 
91     int numLogicalCPUs = 0, numPhysicalCPUs = 0;
92 
93     bool hasMMX      = false, hasSSE        = false, hasSSE2       = false, hasSSE3       = false,
94          has3DNow    = false, hasFMA3       = false, hasFMA4       = false, hasSSSE3      = false,
95          hasSSE41    = false, hasSSE42      = false, hasAVX        = false, hasAVX2       = false,
96          hasAVX512F  = false, hasAVX512BW   = false, hasAVX512CD   = false,
97          hasAVX512DQ = false, hasAVX512ER   = false, hasAVX512IFMA = false,
98          hasAVX512PF = false, hasAVX512VBMI = false, hasAVX512VL   = false,
99          hasAVX512VPOPCNTDQ = false,
100          hasNeon = false;
101 };
102 
getCPUInformation()103 static const CPUInformation& getCPUInformation() noexcept
104 {
105     static CPUInformation info;
106     return info;
107 }
108 
getNumCpus()109 int SystemStats::getNumCpus() noexcept          { return getCPUInformation().numLogicalCPUs; }
getNumPhysicalCpus()110 int SystemStats::getNumPhysicalCpus() noexcept  { return getCPUInformation().numPhysicalCPUs; }
hasMMX()111 bool SystemStats::hasMMX() noexcept             { return getCPUInformation().hasMMX; }
has3DNow()112 bool SystemStats::has3DNow() noexcept           { return getCPUInformation().has3DNow; }
hasFMA3()113 bool SystemStats::hasFMA3() noexcept            { return getCPUInformation().hasFMA3; }
hasFMA4()114 bool SystemStats::hasFMA4() noexcept            { return getCPUInformation().hasFMA4; }
hasSSE()115 bool SystemStats::hasSSE() noexcept             { return getCPUInformation().hasSSE; }
hasSSE2()116 bool SystemStats::hasSSE2() noexcept            { return getCPUInformation().hasSSE2; }
hasSSE3()117 bool SystemStats::hasSSE3() noexcept            { return getCPUInformation().hasSSE3; }
hasSSSE3()118 bool SystemStats::hasSSSE3() noexcept           { return getCPUInformation().hasSSSE3; }
hasSSE41()119 bool SystemStats::hasSSE41() noexcept           { return getCPUInformation().hasSSE41; }
hasSSE42()120 bool SystemStats::hasSSE42() noexcept           { return getCPUInformation().hasSSE42; }
hasAVX()121 bool SystemStats::hasAVX() noexcept             { return getCPUInformation().hasAVX; }
hasAVX2()122 bool SystemStats::hasAVX2() noexcept            { return getCPUInformation().hasAVX2; }
hasAVX512F()123 bool SystemStats::hasAVX512F() noexcept         { return getCPUInformation().hasAVX512F; }
hasAVX512BW()124 bool SystemStats::hasAVX512BW() noexcept        { return getCPUInformation().hasAVX512BW; }
hasAVX512CD()125 bool SystemStats::hasAVX512CD() noexcept        { return getCPUInformation().hasAVX512CD; }
hasAVX512DQ()126 bool SystemStats::hasAVX512DQ() noexcept        { return getCPUInformation().hasAVX512DQ; }
hasAVX512ER()127 bool SystemStats::hasAVX512ER() noexcept        { return getCPUInformation().hasAVX512ER; }
hasAVX512IFMA()128 bool SystemStats::hasAVX512IFMA() noexcept      { return getCPUInformation().hasAVX512IFMA; }
hasAVX512PF()129 bool SystemStats::hasAVX512PF() noexcept        { return getCPUInformation().hasAVX512PF; }
hasAVX512VBMI()130 bool SystemStats::hasAVX512VBMI() noexcept      { return getCPUInformation().hasAVX512VBMI; }
hasAVX512VL()131 bool SystemStats::hasAVX512VL() noexcept        { return getCPUInformation().hasAVX512VL; }
hasAVX512VPOPCNTDQ()132 bool SystemStats::hasAVX512VPOPCNTDQ() noexcept { return getCPUInformation().hasAVX512VPOPCNTDQ; }
hasNeon()133 bool SystemStats::hasNeon() noexcept            { return getCPUInformation().hasNeon; }
134 
135 
136 //==============================================================================
getStackBacktrace()137 String SystemStats::getStackBacktrace()
138 {
139     String result;
140 
141    #if JUCE_ANDROID || JUCE_MINGW || JUCE_WASM
142     jassertfalse; // sorry, not implemented yet!
143 
144    #elif JUCE_WINDOWS
145     HANDLE process = GetCurrentProcess();
146     SymInitialize (process, nullptr, TRUE);
147 
148     void* stack[128];
149     int frames = (int) CaptureStackBackTrace (0, numElementsInArray (stack), stack, nullptr);
150 
151     HeapBlock<SYMBOL_INFO> symbol;
152     symbol.calloc (sizeof (SYMBOL_INFO) + 256, 1);
153     symbol->MaxNameLen = 255;
154     symbol->SizeOfStruct = sizeof (SYMBOL_INFO);
155 
156     for (int i = 0; i < frames; ++i)
157     {
158         DWORD64 displacement = 0;
159 
160         if (SymFromAddr (process, (DWORD64) stack[i], &displacement, symbol))
161         {
162             result << i << ": ";
163 
164             IMAGEHLP_MODULE64 moduleInfo;
165             zerostruct (moduleInfo);
166             moduleInfo.SizeOfStruct = sizeof (moduleInfo);
167 
168             if (::SymGetModuleInfo64 (process, symbol->ModBase, &moduleInfo))
169                 result << moduleInfo.ModuleName << ": ";
170 
171             result << symbol->Name << " + 0x" << String::toHexString ((int64) displacement) << newLine;
172         }
173     }
174 
175    #else
176     void* stack[128];
177     int frames = backtrace (stack, numElementsInArray (stack));
178     char** frameStrings = backtrace_symbols (stack, frames);
179 
180     for (int i = 0; i < frames; ++i)
181         result << frameStrings[i] << newLine;
182 
183     ::free (frameStrings);
184    #endif
185 
186     return result;
187 }
188 
189 //==============================================================================
190 #if ! JUCE_WASM
191 
192 static SystemStats::CrashHandlerFunction globalCrashHandler = nullptr;
193 
194 #if JUCE_WINDOWS
handleCrash(LPEXCEPTION_POINTERS ep)195 static LONG WINAPI handleCrash (LPEXCEPTION_POINTERS ep)
196 {
197     globalCrashHandler (ep);
198     return EXCEPTION_EXECUTE_HANDLER;
199 }
200 #else
handleCrash(int signum)201 static void handleCrash (int signum)
202 {
203     globalCrashHandler ((void*) (pointer_sized_int) signum);
204     ::kill (getpid(), SIGKILL);
205 }
206 
207 int juce_siginterrupt (int sig, int flag);
208 #endif
209 
setApplicationCrashHandler(CrashHandlerFunction handler)210 void SystemStats::setApplicationCrashHandler (CrashHandlerFunction handler)
211 {
212     jassert (handler != nullptr); // This must be a valid function.
213     globalCrashHandler = handler;
214 
215    #if JUCE_WINDOWS
216     SetUnhandledExceptionFilter (handleCrash);
217    #else
218     const int signals[] = { SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGABRT, SIGSYS };
219 
220     for (int i = 0; i < numElementsInArray (signals); ++i)
221     {
222         ::signal (signals[i], handleCrash);
223         juce_siginterrupt (signals[i], 1);
224     }
225    #endif
226 }
227 
228 #endif
229 
isRunningInAppExtensionSandbox()230 bool SystemStats::isRunningInAppExtensionSandbox() noexcept
231 {
232    #if JUCE_MAC || JUCE_IOS
233     static bool firstQuery = true;
234     static bool isRunningInAppSandbox = false;
235 
236     if (firstQuery)
237     {
238         firstQuery = false;
239 
240         File bundle = File::getSpecialLocation (File::invokedExecutableFile).getParentDirectory();
241 
242        #if JUCE_MAC
243         bundle = bundle.getParentDirectory().getParentDirectory();
244        #endif
245 
246         if (bundle.isDirectory())
247             isRunningInAppSandbox = (bundle.getFileExtension() == ".appex");
248     }
249 
250     return isRunningInAppSandbox;
251    #else
252     return false;
253    #endif
254 }
255 
256 } // namespace juce
257