VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/thread-win.cpp@ 84840

Last change on this file since 84840 was 84840, checked in by vboxsync, 4 years ago

IPRT/thread-win.cpp: Thread naming todo.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.8 KB
Line 
1/* $Id: thread-win.cpp 84840 2020-06-16 00:22:42Z vboxsync $ */
2/** @file
3 * IPRT - Threads, Windows.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_THREAD
32#include <iprt/nt/nt-and-windows.h>
33
34#include <errno.h>
35#include <process.h>
36
37#include <iprt/thread.h>
38#include "internal/iprt.h"
39
40#include <iprt/asm-amd64-x86.h>
41#include <iprt/assert.h>
42#include <iprt/cpuset.h>
43#include <iprt/err.h>
44#include <iprt/log.h>
45#include <iprt/mem.h>
46#include <iprt/param.h>
47#include "internal/thread.h"
48#include "internal-r3-win.h"
49
50
51/*********************************************************************************************************************************
52* Defined Constants And Macros *
53*********************************************************************************************************************************/
54/** The TLS index allocated for storing the RTTHREADINT pointer. */
55static DWORD g_dwSelfTLS = TLS_OUT_OF_INDEXES;
56
57
58/*********************************************************************************************************************************
59* Internal Functions *
60*********************************************************************************************************************************/
61static unsigned __stdcall rtThreadNativeMain(void *pvArgs);
62static void rtThreadWinTellDebuggerThreadName(uint32_t idThread, const char *pszName);
63
64
65DECLHIDDEN(int) rtThreadNativeInit(void)
66{
67 g_dwSelfTLS = TlsAlloc();
68 if (g_dwSelfTLS == TLS_OUT_OF_INDEXES)
69 return VERR_NO_TLS_FOR_SELF;
70 return VINF_SUCCESS;
71}
72
73
74DECLHIDDEN(void) rtThreadNativeReInitObtrusive(void)
75{
76 /* nothing to do here. */
77}
78
79
80DECLHIDDEN(void) rtThreadNativeDetach(void)
81{
82 /*
83 * Deal with alien threads.
84 */
85 PRTTHREADINT pThread = (PRTTHREADINT)TlsGetValue(g_dwSelfTLS);
86 if ( pThread
87 && (pThread->fIntFlags & RTTHREADINT_FLAGS_ALIEN))
88 {
89 rtThreadTerminate(pThread, 0);
90 TlsSetValue(g_dwSelfTLS, NULL);
91 }
92}
93
94
95DECLHIDDEN(void) rtThreadNativeDestroy(PRTTHREADINT pThread)
96{
97 if (pThread == (PRTTHREADINT)TlsGetValue(g_dwSelfTLS))
98 TlsSetValue(g_dwSelfTLS, NULL);
99
100 if ((HANDLE)pThread->hThread != INVALID_HANDLE_VALUE)
101 {
102 CloseHandle((HANDLE)pThread->hThread);
103 pThread->hThread = (uintptr_t)INVALID_HANDLE_VALUE;
104 }
105}
106
107
108DECLHIDDEN(int) rtThreadNativeAdopt(PRTTHREADINT pThread)
109{
110 if (!TlsSetValue(g_dwSelfTLS, pThread))
111 return VERR_FAILED_TO_SET_SELF_TLS;
112 if (IsDebuggerPresent())
113 rtThreadWinTellDebuggerThreadName(GetCurrentThreadId(), pThread->szName);
114 return VINF_SUCCESS;
115}
116
117
118DECLHIDDEN(void) rtThreadNativeInformDebugger(PRTTHREADINT pThread)
119{
120 rtThreadWinTellDebuggerThreadName((uint32_t)(uintptr_t)pThread->Core.Key, pThread->szName);
121}
122
123
124/**
125 * Communicates the thread name to the debugger, if we're begin debugged that
126 * is.
127 *
128 * See http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx for debugger
129 * interface details.
130 *
131 * @param idThread The thread ID. UINT32_MAX for current thread.
132 * @param pszName The name.
133 */
134static void rtThreadWinTellDebuggerThreadName(uint32_t idThread, const char *pszName)
135{
136 /// @todo check out SetThreadDescription from W10-1607
137 struct
138 {
139 uint32_t uType;
140 const char *pszName;
141 uint32_t idThread;
142 uint32_t fFlags;
143 } Pkg = { 0x1000, pszName, idThread, 0 };
144 __try
145 {
146 RaiseException(0x406d1388, 0, sizeof(Pkg)/sizeof(ULONG_PTR), (ULONG_PTR *)&Pkg);
147 }
148 __except(EXCEPTION_CONTINUE_EXECUTION)
149 {
150
151 }
152}
153
154
155/**
156 * Bitch about dangling COM and OLE references, dispose of them
157 * afterwards so we don't end up deadlocked somewhere below
158 * OLE32!DllMain.
159 */
160static void rtThreadNativeUninitComAndOle(void)
161{
162#if 1 /* experimental code */
163 /*
164 * Read the counters.
165 */
166 struct MySOleTlsData
167 {
168 void *apvReserved0[2]; /**< x86=0x00 W7/64=0x00 */
169 DWORD adwReserved0[3]; /**< x86=0x08 W7/64=0x10 */
170 void *apvReserved1[1]; /**< x86=0x14 W7/64=0x20 */
171 DWORD cComInits; /**< x86=0x18 W7/64=0x28 */
172 DWORD cOleInits; /**< x86=0x1c W7/64=0x2c */
173 DWORD dwReserved1; /**< x86=0x20 W7/64=0x30 */
174 void *apvReserved2[4]; /**< x86=0x24 W7/64=0x38 */
175 DWORD adwReserved2[1]; /**< x86=0x34 W7/64=0x58 */
176 void *pvCurrentCtx; /**< x86=0x38 W7/64=0x60 */
177 IUnknown *pCallState; /**< x86=0x3c W7/64=0x68 */
178 } *pOleTlsData = NULL; /* outside the try/except for debugging */
179 DWORD cComInits = 0;
180 DWORD cOleInits = 0;
181 __try
182 {
183 void *pvTeb = NtCurrentTeb();
184# ifdef RT_ARCH_AMD64
185 pOleTlsData = *(struct MySOleTlsData **)((uintptr_t)pvTeb + 0x1758); /*TEB.ReservedForOle*/
186# elif RT_ARCH_X86
187 pOleTlsData = *(struct MySOleTlsData **)((uintptr_t)pvTeb + 0x0f80); /*TEB.ReservedForOle*/
188# else
189# error "Port me!"
190# endif
191 if (pOleTlsData)
192 {
193 cComInits = pOleTlsData->cComInits;
194 cOleInits = pOleTlsData->cOleInits;
195 }
196 }
197 __except(EXCEPTION_EXECUTE_HANDLER)
198 {
199 AssertFailedReturnVoid();
200 }
201
202 /*
203 * Assert sanity. If any of these breaks, the structure layout above is
204 * probably not correct any longer.
205 */
206 AssertMsgReturnVoid(cComInits < 1000, ("%u (%#x)\n", cComInits, cComInits));
207 AssertMsgReturnVoid(cOleInits < 1000, ("%u (%#x)\n", cOleInits, cOleInits));
208 AssertMsgReturnVoid(cComInits >= cOleInits, ("cComInits=%#x cOleInits=%#x\n", cComInits, cOleInits));
209
210 /*
211 * Do the uninitializing.
212 */
213 if (cComInits)
214 {
215 AssertMsgFailed(("cComInits=%u (%#x) cOleInits=%u (%#x) - dangling COM/OLE inits!\n",
216 cComInits, cComInits, cOleInits, cOleInits));
217
218 HMODULE hOle32 = GetModuleHandle("ole32.dll");
219 AssertReturnVoid(hOle32 != NULL);
220
221 typedef void (WINAPI *PFNOLEUNINITIALIZE)(void);
222 PFNOLEUNINITIALIZE pfnOleUninitialize = (PFNOLEUNINITIALIZE)GetProcAddress(hOle32, "OleUninitialize");
223 AssertReturnVoid(pfnOleUninitialize);
224
225 typedef void (WINAPI *PFNCOUNINITIALIZE)(void);
226 PFNCOUNINITIALIZE pfnCoUninitialize = (PFNCOUNINITIALIZE)GetProcAddress(hOle32, "CoUninitialize");
227 AssertReturnVoid(pfnCoUninitialize);
228
229 while (cOleInits-- > 0)
230 {
231 pfnOleUninitialize();
232 cComInits--;
233 }
234
235 while (cComInits-- > 0)
236 pfnCoUninitialize();
237 }
238#endif
239}
240
241
242/**
243 * Wrapper which unpacks the param stuff and calls thread function.
244 */
245static unsigned __stdcall rtThreadNativeMain(void *pvArgs)
246{
247 DWORD dwThreadId = GetCurrentThreadId();
248 PRTTHREADINT pThread = (PRTTHREADINT)pvArgs;
249
250 if (!TlsSetValue(g_dwSelfTLS, pThread))
251 AssertReleaseMsgFailed(("failed to set self TLS. lasterr=%d thread '%s'\n", GetLastError(), pThread->szName));
252 if (IsDebuggerPresent())
253 rtThreadWinTellDebuggerThreadName(dwThreadId, &pThread->szName[0]);
254
255 int rc = rtThreadMain(pThread, dwThreadId, &pThread->szName[0]);
256
257 TlsSetValue(g_dwSelfTLS, NULL);
258 rtThreadNativeUninitComAndOle();
259 _endthreadex(rc);
260 return rc;
261}
262
263
264DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThread, PRTNATIVETHREAD pNativeThread)
265{
266 AssertReturn(pThread->cbStack < ~(unsigned)0, VERR_INVALID_PARAMETER);
267
268 /*
269 * If a stack size is given, make sure it's not a multiple of 64KB so that we
270 * get one or more pages for overflow protection. (ASSUMES 64KB alloc align.)
271 */
272 unsigned cbStack = (unsigned)pThread->cbStack;
273 if (cbStack > 0 && RT_ALIGN_T(cbStack, _64K, unsigned) == cbStack)
274 cbStack += PAGE_SIZE;
275
276 /*
277 * Create the thread.
278 */
279 pThread->hThread = (uintptr_t)INVALID_HANDLE_VALUE;
280 unsigned uThreadId = 0;
281 uintptr_t hThread = _beginthreadex(NULL, cbStack, rtThreadNativeMain, pThread, 0, &uThreadId);
282 if (hThread != 0 && hThread != ~0U)
283 {
284 pThread->hThread = hThread;
285 *pNativeThread = uThreadId;
286 return VINF_SUCCESS;
287 }
288 return RTErrConvertFromErrno(errno);
289}
290
291
292DECLHIDDEN(bool) rtThreadNativeIsAliveKludge(PRTTHREADINT pThread)
293{
294 PPEB_COMMON pPeb = NtCurrentPeb();
295 if (!pPeb || !pPeb->Ldr || !pPeb->Ldr->ShutdownInProgress)
296 return true;
297 DWORD rcWait = WaitForSingleObject((HANDLE)pThread->hThread, 0);
298 return rcWait != WAIT_OBJECT_0;
299}
300
301
302RTDECL(RTTHREAD) RTThreadSelf(void)
303{
304 PRTTHREADINT pThread = (PRTTHREADINT)TlsGetValue(g_dwSelfTLS);
305 /** @todo import alien threads ? */
306 return pThread;
307}
308
309
310#if 0 /* noone is using this ... */
311/**
312 * Returns the processor number the current thread was running on during this call
313 *
314 * @returns processor nr
315 */
316static int rtThreadGetCurrentProcessorNumber(void)
317{
318 static bool fInitialized = false;
319 static DWORD (WINAPI *pfnGetCurrentProcessorNumber)(void) = NULL;
320 if (!fInitialized)
321 {
322 HMODULE hmodKernel32 = GetModuleHandle("kernel32.dll");
323 if (hmodKernel32)
324 pfnGetCurrentProcessorNumber = (DWORD (WINAPI*)(void))GetProcAddress(hmodKernel32, "GetCurrentProcessorNumber");
325 fInitialized = true;
326 }
327 if (pfnGetCurrentProcessorNumber)
328 return pfnGetCurrentProcessorNumber();
329 return -1;
330}
331#endif
332
333
334RTR3DECL(int) RTThreadSetAffinity(PCRTCPUSET pCpuSet)
335{
336 DWORD_PTR fNewMask = pCpuSet ? RTCpuSetToU64(pCpuSet) : ~(DWORD_PTR)0;
337 DWORD_PTR dwRet = SetThreadAffinityMask(GetCurrentThread(), fNewMask);
338 if (dwRet)
339 return VINF_SUCCESS;
340
341 int iLastError = GetLastError();
342 AssertMsgFailed(("SetThreadAffinityMask failed, LastError=%d\n", iLastError));
343 return RTErrConvertFromWin32(iLastError);
344}
345
346
347RTR3DECL(int) RTThreadGetAffinity(PRTCPUSET pCpuSet)
348{
349 /*
350 * Haven't found no query api, but the set api returns the old mask, so let's use that.
351 */
352 DWORD_PTR dwIgnored;
353 DWORD_PTR dwProcAff = 0;
354 if (GetProcessAffinityMask(GetCurrentProcess(), &dwProcAff, &dwIgnored))
355 {
356 HANDLE hThread = GetCurrentThread();
357 DWORD_PTR dwRet = SetThreadAffinityMask(hThread, dwProcAff);
358 if (dwRet)
359 {
360 DWORD_PTR dwSet = SetThreadAffinityMask(hThread, dwRet);
361 Assert(dwSet == dwProcAff); NOREF(dwRet);
362
363 RTCpuSetFromU64(pCpuSet, (uint64_t)dwSet);
364 return VINF_SUCCESS;
365 }
366 }
367
368 int iLastError = GetLastError();
369 AssertMsgFailed(("SetThreadAffinityMask or GetProcessAffinityMask failed, LastError=%d\n", iLastError));
370 return RTErrConvertFromWin32(iLastError);
371}
372
373
374RTR3DECL(int) RTThreadGetExecutionTimeMilli(uint64_t *pKernelTime, uint64_t *pUserTime)
375{
376 uint64_t u64CreationTime, u64ExitTime, u64KernelTime, u64UserTime;
377
378 if (GetThreadTimes(GetCurrentThread(), (LPFILETIME)&u64CreationTime, (LPFILETIME)&u64ExitTime, (LPFILETIME)&u64KernelTime, (LPFILETIME)&u64UserTime))
379 {
380 *pKernelTime = u64KernelTime / 10000; /* GetThreadTimes returns time in 100 ns units */
381 *pUserTime = u64UserTime / 10000; /* GetThreadTimes returns time in 100 ns units */
382 return VINF_SUCCESS;
383 }
384
385 int iLastError = GetLastError();
386 AssertMsgFailed(("GetThreadTimes failed, LastError=%d\n", iLastError));
387 return RTErrConvertFromWin32(iLastError);
388}
389
390
391/**
392 * Gets the native thread handle for a IPRT thread.
393 *
394 * @returns The thread handle. INVALID_HANDLE_VALUE on failure.
395 * @param hThread The IPRT thread handle.
396 *
397 * @note Windows only.
398 * @note Only valid after parent returns from the thread creation call.
399 */
400RTDECL(uintptr_t) RTThreadGetNativeHandle(RTTHREAD hThread)
401{
402 PRTTHREADINT pThread = rtThreadGet(hThread);
403 if (pThread)
404 {
405 uintptr_t hHandle = pThread->hThread;
406 rtThreadRelease(pThread);
407 return hHandle;
408 }
409 return (uintptr_t)INVALID_HANDLE_VALUE;
410}
411RT_EXPORT_SYMBOL(RTThreadGetNativeHandle);
412
413
414RTDECL(int) RTThreadPoke(RTTHREAD hThread)
415{
416 AssertReturn(hThread != RTThreadSelf(), VERR_INVALID_PARAMETER);
417 if (g_pfnNtAlertThread)
418 {
419 PRTTHREADINT pThread = rtThreadGet(hThread);
420 AssertReturn(pThread, VERR_INVALID_HANDLE);
421
422 NTSTATUS rcNt = g_pfnNtAlertThread((HANDLE)pThread->hThread);
423
424 rtThreadRelease(pThread);
425 if (NT_SUCCESS(rcNt))
426 return VINF_SUCCESS;
427 return RTErrConvertFromNtStatus(rcNt);
428 }
429 return VERR_NOT_IMPLEMENTED;
430}
431
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette