Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/swr/rasterizer/common/os.cpp
4574 views
1
/****************************************************************************
2
* Copyright (C) 2017 Intel Corporation. All Rights Reserved.
3
*
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
10
*
11
* The above copyright notice and this permission notice (including the next
12
* paragraph) shall be included in all copies or substantial portions of the
13
* Software.
14
*
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
* IN THE SOFTWARE.
22
****************************************************************************/
23
24
#include "common/os.h"
25
#include <vector>
26
#include <array>
27
#include <sstream>
28
29
#if defined(_WIN32)
30
#include <shlobj.h>
31
#endif // Windows
32
33
#if defined(__APPLE__) || defined(FORCE_LINUX) || defined(__linux__) || defined(__gnu_linux__)
34
#include <pthread.h>
35
#endif // Linux
36
37
#if defined(_MSC_VER)
38
static const DWORD MS_VC_EXCEPTION = 0x406D1388;
39
40
#pragma pack(push, 8)
41
typedef struct tagTHREADNAME_INFO
42
{
43
DWORD dwType; // Must be 0x1000.
44
LPCSTR szName; // Pointer to name (in user addr space).
45
DWORD dwThreadID; // Thread ID (-1=caller thread).
46
DWORD dwFlags; // Reserved for future use, must be zero.
47
} THREADNAME_INFO;
48
#pragma pack(pop)
49
50
void LegacySetThreadName(const char* pThreadName)
51
{
52
THREADNAME_INFO info;
53
info.dwType = 0x1000;
54
info.szName = pThreadName;
55
info.dwThreadID = GetCurrentThreadId();
56
info.dwFlags = 0;
57
58
if (!IsDebuggerPresent())
59
{
60
// No debugger attached to interpret exception, no need to actually do it
61
return;
62
}
63
64
#pragma warning(push)
65
#pragma warning(disable : 6320 6322)
66
__try
67
{
68
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
69
}
70
__except (EXCEPTION_EXECUTE_HANDLER)
71
{
72
}
73
#pragma warning(pop)
74
}
75
#endif // _WIN32
76
77
void SWR_API SetCurrentThreadName(const char* pThreadName)
78
{
79
#if defined(_MSC_VER)
80
// The SetThreadDescription API was brought in version 1607 of Windows 10.
81
typedef HRESULT(WINAPI * PFNSetThreadDescription)(HANDLE hThread, PCWSTR lpThreadDescription);
82
// The SetThreadDescription API works even if no debugger is attached.
83
auto pfnSetThreadDescription = reinterpret_cast<PFNSetThreadDescription>(
84
GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetThreadDescription"));
85
86
if (!pfnSetThreadDescription)
87
{
88
// try KernelBase.dll
89
pfnSetThreadDescription = reinterpret_cast<PFNSetThreadDescription>(
90
GetProcAddress(GetModuleHandleA("KernelBase.dll"), "SetThreadDescription"));
91
}
92
93
if (pfnSetThreadDescription)
94
{
95
std::string utf8Name = pThreadName;
96
std::wstring wideName;
97
wideName.resize(utf8Name.size() + 1);
98
swprintf_s(&(wideName.front()), wideName.size(), L"%S", utf8Name.c_str());
99
HRESULT hr = pfnSetThreadDescription(GetCurrentThread(), wideName.c_str());
100
SWR_ASSERT(SUCCEEDED(hr), "Failed to set thread name to %s", pThreadName);
101
102
// Fall through - it seems like some debuggers only recognize the exception
103
}
104
105
// Fall back to exception based hack
106
LegacySetThreadName(pThreadName);
107
#endif // _WIN32
108
109
#if defined(FORCE_LINUX) || defined(__linux__) || defined(__gnu_linux__)
110
pthread_setname_np(pthread_self(), pThreadName);
111
#endif // Linux
112
}
113
114
#if defined(__APPLE__) || defined(FORCE_LINUX) || defined(__linux__) || defined(__gnu_linux__)
115
static void
116
SplitString(std::vector<std::string>& out_segments, const std::string& input, char splitToken)
117
{
118
out_segments.clear();
119
120
std::istringstream f(input);
121
std::string s;
122
while (std::getline(f, s, splitToken))
123
{
124
if (s.size())
125
{
126
out_segments.push_back(s);
127
}
128
}
129
}
130
#endif // Unix
131
132
void SWR_API CreateDirectoryPath(const std::string& path)
133
{
134
#if defined(_WIN32)
135
SHCreateDirectoryExA(nullptr, path.c_str(), nullptr);
136
#endif // Windows
137
138
#if defined(__APPLE__) || defined(FORCE_LINUX) || defined(__linux__) || defined(__gnu_linux__)
139
std::vector<std::string> pathSegments;
140
SplitString(pathSegments, path, '/');
141
142
std::string tmpPath;
143
for (auto const& segment : pathSegments)
144
{
145
tmpPath.push_back('/');
146
tmpPath += segment;
147
148
int result = mkdir(tmpPath.c_str(), 0777);
149
if (result == -1 && errno != EEXIST)
150
{
151
break;
152
}
153
}
154
#endif // Unix
155
}
156
157
/// Execute Command (block until finished)
158
/// @returns process exit value
159
int SWR_API ExecCmd(const std::string& cmd, ///< (In) Command line string
160
const char* pOptEnvStrings, ///< (Optional In) Environment block for new process
161
std::string* pOptStdOut, ///< (Optional Out) Standard Output text
162
std::string* pOptStdErr, ///< (Optional Out) Standard Error text
163
const std::string* pOptStdIn) ///< (Optional In) Standard Input text
164
{
165
int rvalue = -1;
166
167
#if defined(_WIN32)
168
struct WinPipe
169
{
170
HANDLE hRead;
171
HANDLE hWrite;
172
};
173
std::array<WinPipe, 3> hPipes = {};
174
175
SECURITY_ATTRIBUTES saAttr = {sizeof(SECURITY_ATTRIBUTES)};
176
saAttr.bInheritHandle = TRUE; // Pipe handles are inherited by child process.
177
saAttr.lpSecurityDescriptor = NULL;
178
179
{
180
bool bFail = false;
181
for (WinPipe& p : hPipes)
182
{
183
if (!CreatePipe(&p.hRead, &p.hWrite, &saAttr, 0))
184
{
185
bFail = true;
186
}
187
}
188
189
if (bFail)
190
{
191
for (WinPipe& p : hPipes)
192
{
193
CloseHandle(p.hRead);
194
CloseHandle(p.hWrite);
195
}
196
return rvalue;
197
}
198
}
199
200
STARTUPINFOA StartupInfo{};
201
StartupInfo.cb = sizeof(STARTUPINFOA);
202
StartupInfo.dwFlags = STARTF_USESTDHANDLES;
203
StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
204
StartupInfo.wShowWindow = SW_HIDE;
205
if (pOptStdIn)
206
{
207
StartupInfo.hStdInput = hPipes[0].hRead;
208
}
209
StartupInfo.hStdOutput = hPipes[1].hWrite;
210
StartupInfo.hStdError = hPipes[2].hWrite;
211
PROCESS_INFORMATION procInfo{};
212
213
// CreateProcess can modify the string
214
std::string local_cmd = cmd;
215
216
BOOL ProcessValue = CreateProcessA(NULL,
217
(LPSTR)local_cmd.c_str(),
218
NULL,
219
NULL,
220
TRUE,
221
0,
222
(LPVOID)pOptEnvStrings,
223
NULL,
224
&StartupInfo,
225
&procInfo);
226
227
if (ProcessValue && procInfo.hProcess)
228
{
229
auto ReadFromPipe = [](HANDLE hPipe, std::string* pOutStr) {
230
char buf[1024];
231
DWORD dwRead = 0;
232
DWORD dwAvail = 0;
233
while (true)
234
{
235
if (!::PeekNamedPipe(hPipe, NULL, 0, NULL, &dwAvail, NULL))
236
{
237
break;
238
}
239
240
if (!dwAvail) // no data available, return
241
{
242
break;
243
}
244
245
if (!::ReadFile(hPipe,
246
buf,
247
std::min<size_t>(sizeof(buf) - 1, size_t(dwAvail)),
248
&dwRead,
249
NULL) ||
250
!dwRead)
251
{
252
// error, the child process might ended
253
break;
254
}
255
256
buf[dwRead] = 0;
257
if (pOutStr)
258
{
259
(*pOutStr) += buf;
260
}
261
}
262
};
263
bool bProcessEnded = false;
264
size_t bytesWritten = 0;
265
do
266
{
267
if (pOptStdIn && (pOptStdIn->size() > bytesWritten))
268
{
269
DWORD bytesToWrite = static_cast<DWORD>(pOptStdIn->size()) - bytesWritten;
270
if (!::WriteFile(hPipes[0].hWrite,
271
pOptStdIn->data() + bytesWritten,
272
bytesToWrite,
273
&bytesToWrite,
274
nullptr))
275
{
276
// Failed to write to pipe
277
break;
278
}
279
bytesWritten += bytesToWrite;
280
}
281
282
// Give some timeslice (50ms), so we won't waste 100% cpu.
283
bProcessEnded = (WaitForSingleObject(procInfo.hProcess, 50) == WAIT_OBJECT_0);
284
285
ReadFromPipe(hPipes[1].hRead, pOptStdOut);
286
ReadFromPipe(hPipes[2].hRead, pOptStdErr);
287
} while (!bProcessEnded);
288
289
DWORD exitVal = 0;
290
if (!GetExitCodeProcess(procInfo.hProcess, &exitVal))
291
{
292
exitVal = 1;
293
}
294
295
CloseHandle(procInfo.hProcess);
296
CloseHandle(procInfo.hThread);
297
298
rvalue = exitVal;
299
}
300
301
for (WinPipe& p : hPipes)
302
{
303
CloseHandle(p.hRead);
304
CloseHandle(p.hWrite);
305
}
306
307
#else
308
309
// Non-Windows implementation
310
311
#endif
312
313
return rvalue;
314
}
315
316