xref: /aosp_15_r20/external/angle/src/common/system_utils_win.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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_win.cpp: Implementation of OS-specific functions for Windows
8 
9 #include "system_utils.h"
10 
11 #include <fileapi.h>
12 #include <stdarg.h>
13 #include <windows.h>
14 #include <algorithm>
15 #include <array>
16 #include <vector>
17 
18 namespace angle
19 {
20 
21 namespace
22 {
23 
GetPath(HMODULE module)24 std::string GetPath(HMODULE module)
25 {
26     std::array<wchar_t, MAX_PATH> executableFileBuf;
27     DWORD executablePathLen = GetModuleFileNameW(module, executableFileBuf.data(),
28                                                  static_cast<DWORD>(executableFileBuf.size()));
29     return Narrow(executablePathLen > 0 ? executableFileBuf.data() : L"");
30 }
31 
GetDirectory(HMODULE module)32 std::string GetDirectory(HMODULE module)
33 {
34     std::string executablePath = GetPath(module);
35     return StripFilenameFromPath(executablePath);
36 }
37 
38 }  // anonymous namespace
39 
GetExecutablePath()40 std::string GetExecutablePath()
41 {
42     return GetPath(nullptr);
43 }
44 
GetExecutableDirectory()45 std::string GetExecutableDirectory()
46 {
47     return GetDirectory(nullptr);
48 }
49 
GetSharedLibraryExtension()50 const char *GetSharedLibraryExtension()
51 {
52     return "dll";
53 }
54 
GetCWD()55 Optional<std::string> GetCWD()
56 {
57     std::array<wchar_t, MAX_PATH> pathBuf;
58     DWORD result = GetCurrentDirectoryW(static_cast<DWORD>(pathBuf.size()), pathBuf.data());
59     if (result == 0)
60     {
61         return Optional<std::string>::Invalid();
62     }
63     return Narrow(pathBuf.data());
64 }
65 
SetCWD(const char * dirName)66 bool SetCWD(const char *dirName)
67 {
68     return (SetCurrentDirectoryW(Widen(dirName).c_str()) == TRUE);
69 }
70 
GetPathSeparatorForEnvironmentVar()71 const char *GetPathSeparatorForEnvironmentVar()
72 {
73     return ";";
74 }
75 
GetCurrentSystemTime()76 double GetCurrentSystemTime()
77 {
78     LARGE_INTEGER frequency = {};
79     QueryPerformanceFrequency(&frequency);
80 
81     LARGE_INTEGER curTime;
82     QueryPerformanceCounter(&curTime);
83 
84     return static_cast<double>(curTime.QuadPart) / frequency.QuadPart;
85 }
86 
GetCurrentProcessCpuTime()87 double GetCurrentProcessCpuTime()
88 {
89     FILETIME creationTime = {};
90     FILETIME exitTime     = {};
91     FILETIME kernelTime   = {};
92     FILETIME userTime     = {};
93 
94     // Note this will not give accurate results if the current thread is
95     // scheduled for less than the tick rate, which is often 15 ms. In that
96     // case, GetProcessTimes will not return different values, making it
97     // possible to end up with 0 ms for a process that takes 93% of a core
98     // (14/15 ms)!  An alternative is QueryProcessCycleTime but there is no
99     // simple way to convert cycles back to seconds, and on top of that, it's
100     // not supported pre-Windows Vista.
101 
102     // Returns 100-ns intervals, so we want to divide by 1e7 to get seconds
103     GetProcessTimes(GetCurrentProcess(), &creationTime, &exitTime, &kernelTime, &userTime);
104 
105     ULARGE_INTEGER kernelInt64;
106     kernelInt64.LowPart      = kernelTime.dwLowDateTime;
107     kernelInt64.HighPart     = kernelTime.dwHighDateTime;
108     double systemTimeSeconds = static_cast<double>(kernelInt64.QuadPart) * 1e-7;
109 
110     ULARGE_INTEGER userInt64;
111     userInt64.LowPart      = userTime.dwLowDateTime;
112     userInt64.HighPart     = userTime.dwHighDateTime;
113     double userTimeSeconds = static_cast<double>(userInt64.QuadPart) * 1e-7;
114 
115     return systemTimeSeconds + userTimeSeconds;
116 }
117 
IsDirectory(const char * filename)118 bool IsDirectory(const char *filename)
119 {
120     WIN32_FILE_ATTRIBUTE_DATA fileInformation;
121 
122     BOOL result =
123         GetFileAttributesExW(Widen(filename).c_str(), GetFileExInfoStandard, &fileInformation);
124     if (result)
125     {
126         DWORD attribs = fileInformation.dwFileAttributes;
127         return (attribs != INVALID_FILE_ATTRIBUTES) && ((attribs & FILE_ATTRIBUTE_DIRECTORY) > 0);
128     }
129 
130     return false;
131 }
132 
IsDebuggerAttached()133 bool IsDebuggerAttached()
134 {
135     return !!::IsDebuggerPresent();
136 }
137 
BreakDebugger()138 void BreakDebugger()
139 {
140     __debugbreak();
141 }
142 
GetExecutableExtension()143 const char *GetExecutableExtension()
144 {
145     return ".exe";
146 }
147 
GetPathSeparator()148 char GetPathSeparator()
149 {
150     return '\\';
151 }
152 
GetModuleDirectory()153 std::string GetModuleDirectory()
154 {
155 // GetModuleHandleEx is unavailable on UWP
156 #if !defined(ANGLE_IS_WINUWP)
157     static int placeholderSymbol = 0;
158     HMODULE module               = nullptr;
159     if (GetModuleHandleExW(
160             GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
161             reinterpret_cast<LPCWSTR>(&placeholderSymbol), &module))
162     {
163         return GetDirectory(module);
164     }
165 #endif
166     return GetDirectory(nullptr);
167 }
168 
GetRootDirectory()169 std::string GetRootDirectory()
170 {
171     return "C:\\";
172 }
173 
CreateDirectories(const std::string & path)174 bool CreateDirectories(const std::string &path)
175 {
176     // First sanitize path so we can use "/" as universal path separator
177     std::string sanitizedPath(path);
178     MakeForwardSlashThePathSeparator(sanitizedPath);
179 
180     size_t pos = 0;
181     do
182     {
183         pos = sanitizedPath.find("/", pos);
184         std::string checkPath(sanitizedPath.substr(0, pos));
185         if (!checkPath.empty() && !IsDirectory(checkPath.c_str()))
186         {
187             if (!CreateDirectoryW(Widen(checkPath).c_str(), nullptr))
188             {
189                 return false;
190             }
191         }
192         if (pos == std::string::npos)
193         {
194             break;
195         }
196         ++pos;
197     } while (true);
198     return true;
199 }
200 
MakeForwardSlashThePathSeparator(std::string & path)201 void MakeForwardSlashThePathSeparator(std::string &path)
202 {
203     std::replace(path.begin(), path.end(), '\\', '/');
204     return;
205 }
206 
GetTempDirectory()207 Optional<std::string> GetTempDirectory()
208 {
209     char tempDirOut[MAX_PATH + 1];
210     GetTempPathA(MAX_PATH + 1, tempDirOut);
211     std::string tempDir = std::string(tempDirOut);
212 
213     if (tempDir.length() < 0 || tempDir.length() > MAX_PATH)
214     {
215         return Optional<std::string>::Invalid();
216     }
217 
218     if (tempDir.length() > 0 && tempDir.back() == '\\')
219     {
220         tempDir.pop_back();
221     }
222 
223     return tempDir;
224 }
225 
CreateTemporaryFileInDirectory(const std::string & directory)226 Optional<std::string> CreateTemporaryFileInDirectory(const std::string &directory)
227 {
228     char fileName[MAX_PATH + 1];
229     if (GetTempFileNameA(directory.c_str(), "ANGLE", 0, fileName) == 0)
230         return Optional<std::string>::Invalid();
231 
232     return std::string(fileName);
233 }
234 
GetLibraryPath(void * libraryHandle)235 std::string GetLibraryPath(void *libraryHandle)
236 {
237     if (!libraryHandle)
238     {
239         return "";
240     }
241 
242     std::array<wchar_t, MAX_PATH> buffer;
243     if (GetModuleFileNameW(reinterpret_cast<HMODULE>(libraryHandle), buffer.data(),
244                            buffer.size()) == 0)
245     {
246         return "";
247     }
248 
249     return Narrow(buffer.data());
250 }
251 
GetLibrarySymbol(void * libraryHandle,const char * symbolName)252 void *GetLibrarySymbol(void *libraryHandle, const char *symbolName)
253 {
254     if (!libraryHandle)
255     {
256         fprintf(stderr, "Module was not loaded\n");
257         return nullptr;
258     }
259 
260     return reinterpret_cast<void *>(
261         GetProcAddress(reinterpret_cast<HMODULE>(libraryHandle), symbolName));
262 }
263 
CloseSystemLibrary(void * libraryHandle)264 void CloseSystemLibrary(void *libraryHandle)
265 {
266     if (libraryHandle)
267     {
268         FreeLibrary(reinterpret_cast<HMODULE>(libraryHandle));
269     }
270 }
Narrow(const std::wstring_view & utf16)271 std::string Narrow(const std::wstring_view &utf16)
272 {
273     if (utf16.empty())
274     {
275         return {};
276     }
277     int requiredSize = WideCharToMultiByte(CP_UTF8, 0, utf16.data(), static_cast<int>(utf16.size()),
278                                            nullptr, 0, nullptr, nullptr);
279     std::string utf8(requiredSize, '\0');
280     WideCharToMultiByte(CP_UTF8, 0, utf16.data(), static_cast<int>(utf16.size()), &utf8[0],
281                         requiredSize, nullptr, nullptr);
282     return utf8;
283 }
284 
Widen(const std::string_view & utf8)285 std::wstring Widen(const std::string_view &utf8)
286 {
287     if (utf8.empty())
288     {
289         return {};
290     }
291     int requiredSize =
292         MultiByteToWideChar(CP_UTF8, 0, utf8.data(), static_cast<int>(utf8.size()), nullptr, 0);
293     std::wstring utf16(requiredSize, L'\0');
294     MultiByteToWideChar(CP_UTF8, 0, utf8.data(), static_cast<int>(utf8.size()), &utf16[0],
295                         requiredSize);
296     return utf16;
297 }
298 
SetCurrentThreadName(const char * name)299 void SetCurrentThreadName(const char *name)
300 {
301     // Not implemented
302 }
303 }  // namespace angle
304