1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // system_utils.h: declaration of OS-specific utility functions
8
9 #ifndef COMMON_SYSTEM_UTILS_H_
10 #define COMMON_SYSTEM_UTILS_H_
11
12 #include "common/Optional.h"
13 #include "common/angleutils.h"
14
15 #include <functional>
16 #include <string>
17 #include <string_view>
18
19 namespace angle
20 {
21 std::string GetExecutableName();
22 std::string GetExecutablePath();
23 std::string GetExecutableDirectory();
24 std::string GetModuleDirectory();
25 const char *GetSharedLibraryExtension();
26 const char *GetExecutableExtension();
27 char GetPathSeparator();
28 Optional<std::string> GetCWD();
29 bool SetCWD(const char *dirName);
30 bool SetEnvironmentVar(const char *variableName, const char *value);
31 bool UnsetEnvironmentVar(const char *variableName);
32 bool GetBoolEnvironmentVar(const char *variableName);
33 std::string GetEnvironmentVar(const char *variableName);
34 std::string GetEnvironmentVarOrUnCachedAndroidProperty(const char *variableName,
35 const char *propertyName);
36 std::string GetAndSetEnvironmentVarOrUnCachedAndroidProperty(const char *variableName,
37 const char *propertyName);
38 std::string GetEnvironmentVarOrAndroidProperty(const char *variableName, const char *propertyName);
39 const char *GetPathSeparatorForEnvironmentVar();
40 bool PrependPathToEnvironmentVar(const char *variableName, const char *path);
41 bool IsDirectory(const char *filename);
42 bool IsFullPath(std::string dirName);
43 std::string GetRootDirectory();
44 std::string ConcatenatePath(std::string first, std::string second);
45
46 Optional<std::string> GetTempDirectory();
47 Optional<std::string> CreateTemporaryFileInDirectory(const std::string &directory);
48 Optional<std::string> CreateTemporaryFile();
49
50 #if defined(ANGLE_PLATFORM_POSIX)
51 // Same as CreateTemporaryFileInDirectory(), but allows for supplying an extension.
52 Optional<std::string> CreateTemporaryFileInDirectoryWithExtension(const std::string &directory,
53 const std::string &extension);
54 #endif
55
56 // Get absolute time in seconds. Use this function to get an absolute time with an unknown origin.
57 double GetCurrentSystemTime();
58 // Get CPU time for current process in seconds.
59 double GetCurrentProcessCpuTime();
60
61 // Unique thread id (std::this_thread::get_id() gets recycled!)
62 uint64_t GetCurrentThreadUniqueId();
63 // Fast function to get thread id when performance is critical (may be recycled).
64 // On Android 7-8x faster than GetCurrentThreadUniqueId().
65 ThreadId GetCurrentThreadId();
66 // Returns id that does not represent a thread.
67 ThreadId InvalidThreadId();
68
69 // Run an application and get the output. Gets a nullptr-terminated set of args to execute the
70 // application with, and returns the stdout and stderr outputs as well as the exit code.
71 //
72 // Pass nullptr for stdoutOut/stderrOut if you don't need to capture. exitCodeOut is required.
73 //
74 // Returns false if it fails to actually execute the application.
75 bool RunApp(const std::vector<const char *> &args,
76 std::string *stdoutOut,
77 std::string *stderrOut,
78 int *exitCodeOut);
79
80 // Use SYSTEM_DIR to bypass loading ANGLE libraries with the same name as system DLLS
81 // (e.g. opengl32.dll)
82 enum class SearchType
83 {
84 // Try to find the library in the same directory as the current module
85 ModuleDir,
86 // Load the library from the system directories
87 SystemDir,
88 // Get a reference to an already loaded shared library.
89 AlreadyLoaded,
90 };
91
92 void *OpenSystemLibrary(const char *libraryName, SearchType searchType);
93 void *OpenSystemLibraryWithExtension(const char *libraryName, SearchType searchType);
94 void *OpenSystemLibraryAndGetError(const char *libraryName,
95 SearchType searchType,
96 std::string *errorOut);
97 void *OpenSystemLibraryWithExtensionAndGetError(const char *libraryName,
98 SearchType searchType,
99 std::string *errorOut);
100
101 void *GetLibrarySymbol(void *libraryHandle, const char *symbolName);
102 std::string GetLibraryPath(void *libraryHandle);
103 void CloseSystemLibrary(void *libraryHandle);
104
105 class Library : angle::NonCopyable
106 {
107 public:
Library()108 Library() {}
Library(void * libraryHandle)109 Library(void *libraryHandle) : mLibraryHandle(libraryHandle) {}
~Library()110 ~Library() { close(); }
111
open(const char * libraryName,SearchType searchType)112 [[nodiscard]] bool open(const char *libraryName, SearchType searchType)
113 {
114 close();
115 mLibraryHandle = OpenSystemLibrary(libraryName, searchType);
116 return mLibraryHandle != nullptr;
117 }
118
openWithExtension(const char * libraryName,SearchType searchType)119 [[nodiscard]] bool openWithExtension(const char *libraryName, SearchType searchType)
120 {
121 close();
122 mLibraryHandle = OpenSystemLibraryWithExtension(libraryName, searchType);
123 return mLibraryHandle != nullptr;
124 }
125
openAndGetError(const char * libraryName,SearchType searchType,std::string * errorOut)126 [[nodiscard]] bool openAndGetError(const char *libraryName,
127 SearchType searchType,
128 std::string *errorOut)
129 {
130 close();
131 mLibraryHandle = OpenSystemLibraryAndGetError(libraryName, searchType, errorOut);
132 return mLibraryHandle != nullptr;
133 }
134
openWithExtensionAndGetError(const char * libraryName,SearchType searchType,std::string * errorOut)135 [[nodiscard]] bool openWithExtensionAndGetError(const char *libraryName,
136 SearchType searchType,
137 std::string *errorOut)
138 {
139 close();
140 mLibraryHandle =
141 OpenSystemLibraryWithExtensionAndGetError(libraryName, searchType, errorOut);
142 return mLibraryHandle != nullptr;
143 }
144
close()145 void close()
146 {
147 if (mLibraryHandle)
148 {
149 CloseSystemLibrary(mLibraryHandle);
150 mLibraryHandle = nullptr;
151 }
152 }
153
getSymbol(const char * symbolName)154 void *getSymbol(const char *symbolName) { return GetLibrarySymbol(mLibraryHandle, symbolName); }
155
getNative()156 void *getNative() const { return mLibraryHandle; }
157
getPath()158 std::string getPath() const { return GetLibraryPath(mLibraryHandle); }
159
160 template <typename FuncT>
getAs(const char * symbolName,FuncT * funcOut)161 void getAs(const char *symbolName, FuncT *funcOut)
162 {
163 *funcOut = reinterpret_cast<FuncT>(getSymbol(symbolName));
164 }
165
166 private:
167 void *mLibraryHandle = nullptr;
168 };
169
170 Library *OpenSharedLibrary(const char *libraryName, SearchType searchType);
171 Library *OpenSharedLibraryWithExtension(const char *libraryName, SearchType searchType);
172 Library *OpenSharedLibraryAndGetError(const char *libraryName,
173 SearchType searchType,
174 std::string *errorOut);
175 Library *OpenSharedLibraryWithExtensionAndGetError(const char *libraryName,
176 SearchType searchType,
177 std::string *errorOut);
178
179 // Returns true if the process is currently being debugged.
180 bool IsDebuggerAttached();
181
182 // Calls system APIs to break into the debugger.
183 void BreakDebugger();
184
185 uint64_t GetProcessMemoryUsageKB();
186
187 bool ProtectMemory(uintptr_t start, size_t size);
188 bool UnprotectMemory(uintptr_t start, size_t size);
189
190 size_t GetPageSize();
191
192 // Return type of the PageFaultCallback
193 enum class PageFaultHandlerRangeType
194 {
195 // The memory address was known by the page fault handler
196 InRange,
197 // The memory address was not in the page fault handler's range
198 // and the signal will be forwarded to the default page handler.
199 OutOfRange,
200 };
201
202 using PageFaultCallback = std::function<PageFaultHandlerRangeType(uintptr_t)>;
203
204 class PageFaultHandler : angle::NonCopyable
205 {
206 public:
207 PageFaultHandler(PageFaultCallback callback);
208 virtual ~PageFaultHandler();
209
210 // Registers OS level page fault handler for memory protection signals
211 // and enables reception on PageFaultCallback
212 virtual bool enable() = 0;
213
214 // Unregisters OS level page fault handler and deactivates PageFaultCallback
215 virtual bool disable() = 0;
216
217 protected:
218 PageFaultCallback mCallback;
219 };
220
221 // Creates single instance page fault handler
222 PageFaultHandler *CreatePageFaultHandler(PageFaultCallback callback);
223
224 #ifdef ANGLE_PLATFORM_WINDOWS
225 // Convert an UTF-16 wstring to an UTF-8 string.
226 std::string Narrow(const std::wstring_view &utf16);
227
228 // Convert an UTF-8 string to an UTF-16 wstring.
229 std::wstring Widen(const std::string_view &utf8);
230 #endif
231
232 std::string StripFilenameFromPath(const std::string &path);
233
234 #if defined(ANGLE_PLATFORM_LINUX) || defined(ANGLE_PLATFORM_WINDOWS)
235 // Use C++ thread_local which is about 2x faster than std::this_thread::get_id()
GetCurrentThreadId()236 ANGLE_INLINE ThreadId GetCurrentThreadId()
237 {
238 thread_local int tls;
239 return static_cast<ThreadId>(reinterpret_cast<uintptr_t>(&tls));
240 }
InvalidThreadId()241 ANGLE_INLINE ThreadId InvalidThreadId()
242 {
243 return -1;
244 }
245 #else
246 // Default. Fastest on Android (about the same as `pthread_self` and a bit faster then `gettid`).
GetCurrentThreadId()247 ANGLE_INLINE ThreadId GetCurrentThreadId()
248 {
249 return std::this_thread::get_id();
250 }
InvalidThreadId()251 ANGLE_INLINE ThreadId InvalidThreadId()
252 {
253 return ThreadId();
254 }
255 #endif
256 } // namespace angle
257
258 #endif // COMMON_SYSTEM_UTILS_H_
259