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