VirtualBox

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

Last change on this file since 81106 was 79495, checked in by vboxsync, 5 years ago

IPRT/thread-win.cpp: Don't give windows a 64KB aligned stack size, because then we won't get any overflow protection.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.7 KB
Line 
1/* $Id: thread-win.cpp 79495 2019-07-03 12:52:53Z vboxsync $ */
2/** @file
3 * IPRT - Threads, Windows.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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 struct
137 {
138 uint32_t uType;
139 const char *pszName;
140 uint32_t idThread;
141 uint32_t fFlags;
142 } Pkg = { 0x1000, pszName, idThread, 0 };
143 __try
144 {
145 RaiseException(0x406d1388, 0, sizeof(Pkg)/sizeof(ULONG_PTR), (ULONG_PTR *)&Pkg);
146 }
147 __except(EXCEPTION_CONTINUE_EXECUTION)
148 {
149
150 }
151}
152
153
154/**
155 * Bitch about dangling COM and OLE references, dispose of them
156 * afterwards so we don't end up deadlocked somewhere below
157 * OLE32!DllMain.
158 */
159static void rtThreadNativeUninitComAndOle(void)
160{
161#if 1 /* experimental code */
162 /*
163 * Read the counters.
164 */
165 struct MySOleTlsData
166 {
167 void *apvReserved0[2]; /**< x86=0x00 W7/64=0x00 */
168 DWORD adwReserved0[3]; /**< x86=0x08 W7/64=0x10 */
169 void *apvReserved1[1]; /**< x86=0x14 W7/64=0x20 */
170 DWORD cComInits; /**< x86=0x18 W7/64=0x28 */
171 DWORD cOleInits; /**< x86=0x1c W7/64=0x2c */
172 DWORD dwReserved1; /**< x86=0x20 W7/64=0x30 */
173 void *apvReserved2[4]; /**< x86=0x24 W7/64=0x38 */
174 DWORD adwReserved2[1]; /**< x86=0x34 W7/64=0x58 */
175 void *pvCurrentCtx; /**< x86=0x38 W7/64=0x60 */
176 IUnknown *pCallState; /**< x86=0x3c W7/64=0x68 */
177 } *pOleTlsData = NULL; /* outside the try/except for debugging */
178 DWORD cComInits = 0;
179 DWORD cOleInits = 0;
180 __try
181 {
182 void *pvTeb = NtCurrentTeb();
183# ifdef RT_ARCH_AMD64
184 pOleTlsData = *(struct MySOleTlsData **)((uintptr_t)pvTeb + 0x1758); /*TEB.ReservedForOle*/
185# elif RT_ARCH_X86
186 pOleTlsData = *(struct MySOleTlsData **)((uintptr_t)pvTeb + 0x0f80); /*TEB.ReservedForOle*/
187# else
188# error "Port me!"
189# endif
190 if (pOleTlsData)
191 {
192 cComInits = pOleTlsData->cComInits;
193 cOleInits = pOleTlsData->cOleInits;
194 }
195 }
196 __except(EXCEPTION_EXECUTE_HANDLER)
197 {
198 AssertFailedReturnVoid();
199 }
200
201 /*
202 * Assert sanity. If any of these breaks, the structure layout above is
203 * probably not correct any longer.
204 */
205 AssertMsgReturnVoid(cComInits < 1000, ("%u (%#x)\n", cComInits, cComInits));
206 AssertMsgReturnVoid(cOleInits < 1000, ("%u (%#x)\n", cOleInits, cOleInits));
207 AssertMsgReturnVoid(cComInits >= cOleInits, ("cComInits=%#x cOleInits=%#x\n", cComInits, cOleInits));
208
209 /*
210 * Do the uninitializing.
211 */
212 if (cComInits)
213 {
214 AssertMsgFailed(("cComInits=%u (%#x) cOleInits=%u (%#x) - dangling COM/OLE inits!\n",
215 cComInits, cComInits, cOleInits, cOleInits));
216
217 HMODULE hOle32 = GetModuleHandle("ole32.dll");
218 AssertReturnVoid(hOle32 != NULL);
219
220 typedef void (WINAPI *PFNOLEUNINITIALIZE)(void);
221 PFNOLEUNINITIALIZE pfnOleUninitialize = (PFNOLEUNINITIALIZE)GetProcAddress(hOle32, "OleUninitialize");
222 AssertReturnVoid(pfnOleUninitialize);
223
224 typedef void (WINAPI *PFNCOUNINITIALIZE)(void);
225 PFNCOUNINITIALIZE pfnCoUninitialize = (PFNCOUNINITIALIZE)GetProcAddress(hOle32, "CoUninitialize");
226 AssertReturnVoid(pfnCoUninitialize);
227
228 while (cOleInits-- > 0)
229 {
230 pfnOleUninitialize();
231 cComInits--;
232 }
233
234 while (cComInits-- > 0)
235 pfnCoUninitialize();
236 }
237#endif
238}
239
240
241/**
242 * Wrapper which unpacks the param stuff and calls thread function.
243 */
244static unsigned __stdcall rtThreadNativeMain(void *pvArgs)
245{
246 DWORD dwThreadId = GetCurrentThreadId();
247 PRTTHREADINT pThread = (PRTTHREADINT)pvArgs;
248
249 if (!TlsSetValue(g_dwSelfTLS, pThread))
250 AssertReleaseMsgFailed(("failed to set self TLS. lasterr=%d thread '%s'\n", GetLastError(), pThread->szName));
251 if (IsDebuggerPresent())
252 rtThreadWinTellDebuggerThreadName(dwThreadId, &pThread->szName[0]);
253
254 int rc = rtThreadMain(pThread, dwThreadId, &pThread->szName[0]);
255
256 TlsSetValue(g_dwSelfTLS, NULL);
257 rtThreadNativeUninitComAndOle();
258 _endthreadex(rc);
259 return rc;
260}
261
262
263DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThread, PRTNATIVETHREAD pNativeThread)
264{
265 AssertReturn(pThread->cbStack < ~(unsigned)0, VERR_INVALID_PARAMETER);
266
267 /*
268 * If a stack size is given, make sure it's not a multiple of 64KB so that we
269 * get one or more pages for overflow protection. (ASSUMES 64KB alloc align.)
270 */
271 unsigned cbStack = (unsigned)pThread->cbStack;
272 if (cbStack > 0 && RT_ALIGN_T(cbStack, _64K, unsigned) == cbStack)
273 cbStack += PAGE_SIZE;
274
275 /*
276 * Create the thread.
277 */
278 pThread->hThread = (uintptr_t)INVALID_HANDLE_VALUE;
279 unsigned uThreadId = 0;
280 uintptr_t hThread = _beginthreadex(NULL, cbStack, rtThreadNativeMain, pThread, 0, &uThreadId);
281 if (hThread != 0 && hThread != ~0U)
282 {
283 pThread->hThread = hThread;
284 *pNativeThread = uThreadId;
285 return VINF_SUCCESS;
286 }
287 return RTErrConvertFromErrno(errno);
288}
289
290
291DECLHIDDEN(bool) rtThreadNativeIsAliveKludge(PRTTHREADINT pThread)
292{
293 PPEB_COMMON pPeb = NtCurrentPeb();
294 if (!pPeb || !pPeb->Ldr || !pPeb->Ldr->ShutdownInProgress)
295 return true;
296 DWORD rcWait = WaitForSingleObject((HANDLE)pThread->hThread, 0);
297 return rcWait != WAIT_OBJECT_0;
298}
299
300
301RTDECL(RTTHREAD) RTThreadSelf(void)
302{
303 PRTTHREADINT pThread = (PRTTHREADINT)TlsGetValue(g_dwSelfTLS);
304 /** @todo import alien threads ? */
305 return pThread;
306}
307
308
309#if 0 /* noone is using this ... */
310/**
311 * Returns the processor number the current thread was running on during this call
312 *
313 * @returns processor nr
314 */
315static int rtThreadGetCurrentProcessorNumber(void)
316{
317 static bool fInitialized = false;
318 static DWORD (WINAPI *pfnGetCurrentProcessorNumber)(void) = NULL;
319 if (!fInitialized)
320 {
321 HMODULE hmodKernel32 = GetModuleHandle("kernel32.dll");
322 if (hmodKernel32)
323 pfnGetCurrentProcessorNumber = (DWORD (WINAPI*)(void))GetProcAddress(hmodKernel32, "GetCurrentProcessorNumber");
324 fInitialized = true;
325 }
326 if (pfnGetCurrentProcessorNumber)
327 return pfnGetCurrentProcessorNumber();
328 return -1;
329}
330#endif
331
332
333RTR3DECL(int) RTThreadSetAffinity(PCRTCPUSET pCpuSet)
334{
335 DWORD_PTR fNewMask = pCpuSet ? RTCpuSetToU64(pCpuSet) : ~(DWORD_PTR)0;
336 DWORD_PTR dwRet = SetThreadAffinityMask(GetCurrentThread(), fNewMask);
337 if (dwRet)
338 return VINF_SUCCESS;
339
340 int iLastError = GetLastError();
341 AssertMsgFailed(("SetThreadAffinityMask failed, LastError=%d\n", iLastError));
342 return RTErrConvertFromWin32(iLastError);
343}
344
345
346RTR3DECL(int) RTThreadGetAffinity(PRTCPUSET pCpuSet)
347{
348 /*
349 * Haven't found no query api, but the set api returns the old mask, so let's use that.
350 */
351 DWORD_PTR dwIgnored;
352 DWORD_PTR dwProcAff = 0;
353 if (GetProcessAffinityMask(GetCurrentProcess(), &dwProcAff, &dwIgnored))
354 {
355 HANDLE hThread = GetCurrentThread();
356 DWORD_PTR dwRet = SetThreadAffinityMask(hThread, dwProcAff);
357 if (dwRet)
358 {
359 DWORD_PTR dwSet = SetThreadAffinityMask(hThread, dwRet);
360 Assert(dwSet == dwProcAff); NOREF(dwRet);
361
362 RTCpuSetFromU64(pCpuSet, (uint64_t)dwSet);
363 return VINF_SUCCESS;
364 }
365 }
366
367 int iLastError = GetLastError();
368 AssertMsgFailed(("SetThreadAffinityMask or GetProcessAffinityMask failed, LastError=%d\n", iLastError));
369 return RTErrConvertFromWin32(iLastError);
370}
371
372
373RTR3DECL(int) RTThreadGetExecutionTimeMilli(uint64_t *pKernelTime, uint64_t *pUserTime)
374{
375 uint64_t u64CreationTime, u64ExitTime, u64KernelTime, u64UserTime;
376
377 if (GetThreadTimes(GetCurrentThread(), (LPFILETIME)&u64CreationTime, (LPFILETIME)&u64ExitTime, (LPFILETIME)&u64KernelTime, (LPFILETIME)&u64UserTime))
378 {
379 *pKernelTime = u64KernelTime / 10000; /* GetThreadTimes returns time in 100 ns units */
380 *pUserTime = u64UserTime / 10000; /* GetThreadTimes returns time in 100 ns units */
381 return VINF_SUCCESS;
382 }
383
384 int iLastError = GetLastError();
385 AssertMsgFailed(("GetThreadTimes failed, LastError=%d\n", iLastError));
386 return RTErrConvertFromWin32(iLastError);
387}
388
389
390/**
391 * Gets the native thread handle for a IPRT thread.
392 *
393 * @returns The thread handle. INVALID_HANDLE_VALUE on failure.
394 * @param hThread The IPRT thread handle.
395 *
396 * @note Windows only.
397 * @note Only valid after parent returns from the thread creation call.
398 */
399RTDECL(uintptr_t) RTThreadGetNativeHandle(RTTHREAD hThread)
400{
401 PRTTHREADINT pThread = rtThreadGet(hThread);
402 if (pThread)
403 {
404 uintptr_t hHandle = pThread->hThread;
405 rtThreadRelease(pThread);
406 return hHandle;
407 }
408 return (uintptr_t)INVALID_HANDLE_VALUE;
409}
410RT_EXPORT_SYMBOL(RTThreadGetNativeHandle);
411
412
413RTDECL(int) RTThreadPoke(RTTHREAD hThread)
414{
415 AssertReturn(hThread != RTThreadSelf(), VERR_INVALID_PARAMETER);
416 if (g_pfnNtAlertThread)
417 {
418 PRTTHREADINT pThread = rtThreadGet(hThread);
419 AssertReturn(pThread, VERR_INVALID_HANDLE);
420
421 NTSTATUS rcNt = g_pfnNtAlertThread((HANDLE)pThread->hThread);
422
423 rtThreadRelease(pThread);
424 if (NT_SUCCESS(rcNt))
425 return VINF_SUCCESS;
426 return RTErrConvertFromNtStatus(rcNt);
427 }
428 return VERR_NOT_IMPLEMENTED;
429}
430
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