VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/thread.cpp@ 75482

Last change on this file since 75482 was 69590, checked in by vboxsync, 7 years ago

thread.cpp: fixed thread structure leak in VBoxC debug builds with lock validator enabled.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 49.0 KB
Line 
1/* $Id: thread.cpp 69590 2017-11-06 09:56:18Z vboxsync $ */
2/** @file
3 * IPRT - Threads, common routines.
4 */
5
6/*
7 * Copyright (C) 2006-2017 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/thread.h>
33#include "internal/iprt.h"
34
35#include <iprt/log.h>
36#include <iprt/avl.h>
37#include <iprt/alloc.h>
38#include <iprt/assert.h>
39#include <iprt/lockvalidator.h>
40#include <iprt/semaphore.h>
41#ifdef IN_RING0
42# include <iprt/spinlock.h>
43#endif
44#include <iprt/asm.h>
45#include <iprt/err.h>
46#include <iprt/string.h>
47#include "internal/magics.h"
48#include "internal/thread.h"
49#include "internal/sched.h"
50#include "internal/process.h"
51#ifdef RT_WITH_ICONV_CACHE
52# include "internal/string.h"
53#endif
54
55
56/*********************************************************************************************************************************
57* Defined Constants And Macros *
58*********************************************************************************************************************************/
59#ifdef IN_RING0
60# define RT_THREAD_LOCK_RW() RTSpinlockAcquire(g_ThreadSpinlock)
61# define RT_THREAD_UNLOCK_RW() RTSpinlockRelease(g_ThreadSpinlock)
62# define RT_THREAD_LOCK_RD() RTSpinlockAcquire(g_ThreadSpinlock)
63# define RT_THREAD_UNLOCK_RD() RTSpinlockRelease(g_ThreadSpinlock)
64#else
65# define RT_THREAD_LOCK_RW() rtThreadLockRW()
66# define RT_THREAD_UNLOCK_RW() rtThreadUnLockRW()
67# define RT_THREAD_LOCK_RD() rtThreadLockRD()
68# define RT_THREAD_UNLOCK_RD() rtThreadUnLockRD()
69#endif
70
71
72/*********************************************************************************************************************************
73* Global Variables *
74*********************************************************************************************************************************/
75/** The AVL thread containing the threads. */
76static PAVLPVNODECORE g_ThreadTree;
77/** The number of threads in the tree (for ring-0 termination kludge). */
78static uint32_t volatile g_cThreadInTree;
79#ifdef IN_RING3
80/** The RW lock protecting the tree. */
81static RTSEMRW g_ThreadRWSem = NIL_RTSEMRW;
82#else
83/** The spinlocks protecting the tree. */
84static RTSPINLOCK g_ThreadSpinlock = NIL_RTSPINLOCK;
85#endif
86/** Indicates whether we've been initialized or not. */
87static bool g_frtThreadInitialized;
88
89
90/*********************************************************************************************************************************
91* Internal Functions *
92*********************************************************************************************************************************/
93static void rtThreadDestroy(PRTTHREADINT pThread);
94#ifdef IN_RING3
95static int rtThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, uint32_t fIntFlags, const char *pszName);
96#endif
97static void rtThreadRemoveLocked(PRTTHREADINT pThread);
98static PRTTHREADINT rtThreadAlloc(RTTHREADTYPE enmType, unsigned fFlags, uint32_t fIntFlags, const char *pszName);
99
100
101/** @page pg_rt_thread IPRT Thread Internals
102 *
103 * IPRT provides interface to whatever native threading that the host provides,
104 * preferably using a CRT level interface to better integrate with other libraries.
105 *
106 * Internally IPRT keeps track of threads by means of the RTTHREADINT structure.
107 * All the RTTHREADINT structures are kept in a AVL tree which is protected by a
108 * read/write lock for efficient access. A thread is inserted into the tree in
109 * three places in the code. The main thread is 'adopted' by IPRT on rtR3Init()
110 * by rtThreadAdopt(). When creating a new thread there the child and the parent
111 * race inserting the thread, this is rtThreadMain() and RTThreadCreate.
112 *
113 * RTTHREADINT objects are using reference counting as a mean of sticking around
114 * till no-one needs them any longer. Waitable threads is created with one extra
115 * reference so they won't go away until they are waited on. This introduces a
116 * major problem if we use the host thread identifier as key in the AVL tree - the
117 * host may reuse the thread identifier before the thread was waited on. So, on
118 * most platforms we are using the RTTHREADINT pointer as key and not the
119 * thread id. RTThreadSelf() then have to be implemented using a pointer stored
120 * in thread local storage (TLS).
121 *
122 * In Ring-0 we only try keep track of kernel threads created by RTThreadCreate
123 * at the moment. There we really only need the 'join' feature, but doing things
124 * the same way allow us to name threads and similar stuff.
125 */
126
127
128/**
129 * Initializes the thread database.
130 *
131 * @returns iprt status code.
132 */
133DECLHIDDEN(int) rtThreadInit(void)
134{
135#ifdef IN_RING3
136 int rc = VINF_ALREADY_INITIALIZED;
137 if (g_ThreadRWSem == NIL_RTSEMRW)
138 {
139 /*
140 * We assume the caller is the 1st thread, which we'll call 'main'.
141 * But first, we'll create the semaphore.
142 */
143 rc = RTSemRWCreateEx(&g_ThreadRWSem, RTSEMRW_FLAGS_NO_LOCK_VAL, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
144 if (RT_SUCCESS(rc))
145 {
146 rc = rtThreadNativeInit();
147 if (RT_SUCCESS(rc))
148 rc = rtThreadAdopt(RTTHREADTYPE_DEFAULT, 0, RTTHREADINT_FLAGS_MAIN, "main");
149 if (RT_SUCCESS(rc))
150 rc = rtSchedNativeCalcDefaultPriority(RTTHREADTYPE_DEFAULT);
151 if (RT_SUCCESS(rc))
152 {
153 g_frtThreadInitialized = true;
154 return VINF_SUCCESS;
155 }
156
157 /* failed, clear out */
158 RTSemRWDestroy(g_ThreadRWSem);
159 g_ThreadRWSem = NIL_RTSEMRW;
160 }
161 }
162
163#elif defined(IN_RING0)
164 int rc;
165 /*
166 * Create the spinlock and to native init.
167 */
168 Assert(g_ThreadSpinlock == NIL_RTSPINLOCK);
169 rc = RTSpinlockCreate(&g_ThreadSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "RTThread");
170 if (RT_SUCCESS(rc))
171 {
172 rc = rtThreadNativeInit();
173 if (RT_SUCCESS(rc))
174 {
175 g_frtThreadInitialized = true;
176 return VINF_SUCCESS;
177 }
178
179 /* failed, clear out */
180 RTSpinlockDestroy(g_ThreadSpinlock);
181 g_ThreadSpinlock = NIL_RTSPINLOCK;
182 }
183#else
184# error "!IN_RING0 && !IN_RING3"
185#endif
186 return rc;
187}
188
189
190#ifdef IN_RING3
191/**
192 * Called when IPRT was first initialized in unobtrusive mode and later changed
193 * to obtrustive.
194 *
195 * This is only applicable in ring-3.
196 */
197DECLHIDDEN(void) rtThreadReInitObtrusive(void)
198{
199 rtThreadNativeReInitObtrusive();
200}
201#endif
202
203
204/**
205 * Terminates the thread database.
206 */
207DECLHIDDEN(void) rtThreadTerm(void)
208{
209#ifdef IN_RING3
210 /* we don't cleanup here yet */
211
212#elif defined(IN_RING0)
213 /* just destroy the spinlock and assume the thread is fine... */
214 RTSpinlockDestroy(g_ThreadSpinlock);
215 g_ThreadSpinlock = NIL_RTSPINLOCK;
216 if (g_ThreadTree != NULL)
217 RTAssertMsg2Weak("WARNING: g_ThreadTree=%p\n", g_ThreadTree);
218#endif
219}
220
221
222#ifdef IN_RING3
223
224DECLINLINE(void) rtThreadLockRW(void)
225{
226 if (g_ThreadRWSem == NIL_RTSEMRW)
227 rtThreadInit();
228 int rc = RTSemRWRequestWrite(g_ThreadRWSem, RT_INDEFINITE_WAIT);
229 AssertReleaseRC(rc);
230}
231
232
233DECLINLINE(void) rtThreadLockRD(void)
234{
235 if (g_ThreadRWSem == NIL_RTSEMRW)
236 rtThreadInit();
237 int rc = RTSemRWRequestRead(g_ThreadRWSem, RT_INDEFINITE_WAIT);
238 AssertReleaseRC(rc);
239}
240
241
242DECLINLINE(void) rtThreadUnLockRW(void)
243{
244 int rc = RTSemRWReleaseWrite(g_ThreadRWSem);
245 AssertReleaseRC(rc);
246}
247
248
249DECLINLINE(void) rtThreadUnLockRD(void)
250{
251 int rc = RTSemRWReleaseRead(g_ThreadRWSem);
252 AssertReleaseRC(rc);
253}
254
255
256/**
257 * Adopts the calling thread.
258 * No locks are taken or released by this function.
259 */
260static int rtThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, uint32_t fIntFlags, const char *pszName)
261{
262 int rc;
263 PRTTHREADINT pThread;
264 Assert(!(fFlags & RTTHREADFLAGS_WAITABLE));
265 fFlags &= ~RTTHREADFLAGS_WAITABLE;
266
267 /*
268 * Allocate and insert the thread.
269 * (It is vital that rtThreadNativeAdopt updates the TLS before
270 * we try inserting the thread because of locking.)
271 */
272 rc = VERR_NO_MEMORY;
273 pThread = rtThreadAlloc(enmType, fFlags, RTTHREADINT_FLAGS_ALIEN | fIntFlags, pszName);
274 if (pThread)
275 {
276 RTNATIVETHREAD NativeThread = RTThreadNativeSelf();
277 rc = rtThreadNativeAdopt(pThread);
278 if (RT_SUCCESS(rc))
279 {
280 rtThreadInsert(pThread, NativeThread);
281 rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
282 rtThreadRelease(pThread);
283 }
284 else
285 rtThreadDestroy(pThread);
286 }
287 return rc;
288}
289
290/**
291 * Adopts a non-IPRT thread.
292 *
293 * @returns IPRT status code.
294 * @param enmType The thread type.
295 * @param fFlags The thread flags. RTTHREADFLAGS_WAITABLE is not currently allowed.
296 * @param pszName The thread name. Optional.
297 * @param pThread Where to store the thread handle. Optional.
298 */
299RTDECL(int) RTThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, const char *pszName, PRTTHREAD pThread)
300{
301 int rc;
302 RTTHREAD Thread;
303
304 AssertReturn(!(fFlags & RTTHREADFLAGS_WAITABLE), VERR_INVALID_PARAMETER);
305 AssertReturn(!pszName || VALID_PTR(pszName), VERR_INVALID_POINTER);
306 AssertReturn(!pThread || VALID_PTR(pThread), VERR_INVALID_POINTER);
307
308 rc = VINF_SUCCESS;
309 Thread = RTThreadSelf();
310 if (Thread == NIL_RTTHREAD)
311 {
312 /* generate a name if none was given. */
313 char szName[RTTHREAD_NAME_LEN];
314 if (!pszName || !*pszName)
315 {
316 static uint32_t s_i32AlienId = 0;
317 uint32_t i32Id = ASMAtomicIncU32(&s_i32AlienId);
318 RTStrPrintf(szName, sizeof(szName), "ALIEN-%RX32", i32Id);
319 pszName = szName;
320 }
321
322 /* try adopt it */
323 rc = rtThreadAdopt(enmType, fFlags, 0, pszName);
324 Thread = RTThreadSelf();
325 Log(("RTThreadAdopt: %RTthrd %RTnthrd '%s' enmType=%d fFlags=%#x rc=%Rrc\n",
326 Thread, RTThreadNativeSelf(), pszName, enmType, fFlags, rc));
327 }
328 else
329 Log(("RTThreadAdopt: %RTthrd %RTnthrd '%s' enmType=%d fFlags=%#x - already adopted!\n",
330 Thread, RTThreadNativeSelf(), pszName, enmType, fFlags));
331
332 if (pThread)
333 *pThread = Thread;
334 return rc;
335}
336RT_EXPORT_SYMBOL(RTThreadAdopt);
337
338
339/**
340 * Get the thread handle of the current thread, automatically adopting alien
341 * threads.
342 *
343 * @returns Thread handle.
344 */
345RTDECL(RTTHREAD) RTThreadSelfAutoAdopt(void)
346{
347 RTTHREAD hSelf = RTThreadSelf();
348 if (RT_UNLIKELY(hSelf == NIL_RTTHREAD))
349 RTThreadAdopt(RTTHREADTYPE_DEFAULT, 0, NULL, &hSelf);
350 return hSelf;
351}
352RT_EXPORT_SYMBOL(RTThreadSelfAutoAdopt);
353
354#endif /* IN_RING3 */
355
356/**
357 * Allocates a per thread data structure and initializes the basic fields.
358 *
359 * @returns Pointer to per thread data structure.
360 * This is reference once.
361 * @returns NULL on failure.
362 * @param enmType The thread type.
363 * @param fFlags The thread flags.
364 * @param fIntFlags The internal thread flags.
365 * @param pszName Pointer to the thread name.
366 */
367PRTTHREADINT rtThreadAlloc(RTTHREADTYPE enmType, unsigned fFlags, uint32_t fIntFlags, const char *pszName)
368{
369 PRTTHREADINT pThread = (PRTTHREADINT)RTMemAllocZ(sizeof(RTTHREADINT));
370 if (pThread)
371 {
372 size_t cchName;
373 int rc;
374
375 pThread->Core.Key = (void*)NIL_RTTHREAD;
376 pThread->u32Magic = RTTHREADINT_MAGIC;
377 cchName = strlen(pszName);
378 if (cchName >= RTTHREAD_NAME_LEN)
379 cchName = RTTHREAD_NAME_LEN - 1;
380 memcpy(pThread->szName, pszName, cchName);
381 pThread->szName[cchName] = '\0';
382 pThread->cRefs = 2 + !!(fFlags & RTTHREADFLAGS_WAITABLE); /* And extra reference if waitable. */
383 pThread->rc = VERR_PROCESS_RUNNING; /** @todo get a better error code! */
384 pThread->enmType = enmType;
385 pThread->fFlags = fFlags;
386 pThread->fIntFlags = fIntFlags;
387 pThread->enmState = RTTHREADSTATE_INITIALIZING;
388 pThread->fReallySleeping = false;
389#ifdef IN_RING3
390 rtLockValidatorInitPerThread(&pThread->LockValidator);
391#endif
392#ifdef RT_WITH_ICONV_CACHE
393 rtStrIconvCacheInit(pThread);
394#endif
395 rc = RTSemEventMultiCreate(&pThread->EventUser);
396 if (RT_SUCCESS(rc))
397 {
398 rc = RTSemEventMultiCreate(&pThread->EventTerminated);
399 if (RT_SUCCESS(rc))
400 return pThread;
401 RTSemEventMultiDestroy(pThread->EventUser);
402 }
403 RTMemFree(pThread);
404 }
405 return NULL;
406}
407
408
409/**
410 * Insert the per thread data structure into the tree.
411 *
412 * This can be called from both the thread it self and the parent,
413 * thus it must handle insertion failures in a nice manner.
414 *
415 * @param pThread Pointer to thread structure allocated by rtThreadAlloc().
416 * @param NativeThread The native thread id.
417 */
418DECLHIDDEN(void) rtThreadInsert(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread)
419{
420 Assert(pThread);
421 Assert(pThread->u32Magic == RTTHREADINT_MAGIC);
422
423 {
424 RT_THREAD_LOCK_RW();
425
426 /*
427 * Do not insert a terminated thread.
428 *
429 * This may happen if the thread finishes before the RTThreadCreate call
430 * gets this far. Since the OS may quickly reuse the native thread ID
431 * it should not be reinserted at this point.
432 */
433 if (rtThreadGetState(pThread) != RTTHREADSTATE_TERMINATED)
434 {
435 /*
436 * Before inserting we must check if there is a thread with this id
437 * in the tree already. We're racing parent and child on insert here
438 * so that the handle is valid in both ends when they return / start.
439 *
440 * If it's not ourself we find, it's a dead alien thread and we will
441 * unlink it from the tree. Alien threads will be released at this point.
442 */
443 PRTTHREADINT pThreadOther = (PRTTHREADINT)RTAvlPVGet(&g_ThreadTree, (void *)NativeThread);
444 if (pThreadOther != pThread)
445 {
446 bool fRc;
447 /* remove dead alien if any */
448 if (pThreadOther)
449 {
450 AssertMsg(pThreadOther->fIntFlags & RTTHREADINT_FLAGS_ALIEN, ("%p:%s; %p:%s\n", pThread, pThread->szName, pThreadOther, pThreadOther->szName));
451 ASMAtomicBitClear(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT);
452 rtThreadRemoveLocked(pThreadOther);
453 if (pThreadOther->fIntFlags & RTTHREADINT_FLAGS_ALIEN)
454 rtThreadRelease(pThreadOther);
455 }
456
457 /* insert the thread */
458 ASMAtomicWritePtr(&pThread->Core.Key, (void *)NativeThread);
459 fRc = RTAvlPVInsert(&g_ThreadTree, &pThread->Core);
460 ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE);
461 if (fRc)
462 ASMAtomicIncU32(&g_cThreadInTree);
463
464 AssertReleaseMsg(fRc, ("Lock problem? %p (%RTnthrd) %s\n", pThread, NativeThread, pThread->szName));
465 NOREF(fRc);
466 }
467 }
468
469 RT_THREAD_UNLOCK_RW();
470 }
471}
472
473
474/**
475 * Removes the thread from the AVL tree, call owns the tree lock
476 * and has cleared the RTTHREADINT_FLAG_IN_TREE bit.
477 *
478 * @param pThread The thread to remove.
479 */
480static void rtThreadRemoveLocked(PRTTHREADINT pThread)
481{
482 PRTTHREADINT pThread2 = (PRTTHREADINT)RTAvlPVRemove(&g_ThreadTree, pThread->Core.Key);
483#if !defined(RT_OS_OS2) /** @todo this asserts for threads created by NSPR */
484 AssertMsg(pThread2 == pThread, ("%p(%s) != %p (%p/%s)\n", pThread2, pThread2 ? pThread2->szName : "<null>",
485 pThread, pThread->Core.Key, pThread->szName));
486#endif
487 if (pThread2)
488 ASMAtomicDecU32(&g_cThreadInTree);
489}
490
491
492/**
493 * Removes the thread from the AVL tree.
494 *
495 * @param pThread The thread to remove.
496 */
497static void rtThreadRemove(PRTTHREADINT pThread)
498{
499 RT_THREAD_LOCK_RW();
500 if (ASMAtomicBitTestAndClear(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT))
501 rtThreadRemoveLocked(pThread);
502 RT_THREAD_UNLOCK_RW();
503}
504
505
506/**
507 * Checks if a thread is alive or not.
508 *
509 * @returns true if the thread is alive (or we don't really know).
510 * @returns false if the thread has surely terminate.
511 */
512DECLINLINE(bool) rtThreadIsAlive(PRTTHREADINT pThread)
513{
514 return !(pThread->fIntFlags & RTTHREADINT_FLAGS_TERMINATED);
515}
516
517
518/**
519 * Gets a thread by it's native ID.
520 *
521 * @returns pointer to the thread structure.
522 * @returns NULL if not a thread IPRT knows.
523 * @param NativeThread The native thread id.
524 */
525DECLHIDDEN(PRTTHREADINT) rtThreadGetByNative(RTNATIVETHREAD NativeThread)
526{
527 PRTTHREADINT pThread;
528 /*
529 * Simple tree lookup.
530 */
531 RT_THREAD_LOCK_RD();
532 pThread = (PRTTHREADINT)RTAvlPVGet(&g_ThreadTree, (void *)NativeThread);
533 RT_THREAD_UNLOCK_RD();
534 return pThread;
535}
536
537
538/**
539 * Gets the per thread data structure for a thread handle.
540 *
541 * @returns Pointer to the per thread data structure for Thread.
542 * The caller must release the thread using rtThreadRelease().
543 * @returns NULL if Thread was not found.
544 * @param Thread Thread id which structure is to be returned.
545 */
546DECLHIDDEN(PRTTHREADINT) rtThreadGet(RTTHREAD Thread)
547{
548 if ( Thread != NIL_RTTHREAD
549 && VALID_PTR(Thread))
550 {
551 PRTTHREADINT pThread = (PRTTHREADINT)Thread;
552 if ( pThread->u32Magic == RTTHREADINT_MAGIC
553 && pThread->cRefs > 0)
554 {
555 ASMAtomicIncU32(&pThread->cRefs);
556 return pThread;
557 }
558 }
559
560 AssertMsgFailed(("Thread=%RTthrd\n", Thread));
561 return NULL;
562}
563
564/**
565 * Release a per thread data structure.
566 *
567 * @returns New reference count.
568 * @param pThread The thread structure to release.
569 */
570DECLHIDDEN(uint32_t) rtThreadRelease(PRTTHREADINT pThread)
571{
572 uint32_t cRefs;
573
574 Assert(pThread);
575 if (pThread->cRefs >= 1)
576 {
577 cRefs = ASMAtomicDecU32(&pThread->cRefs);
578 if (!cRefs)
579 rtThreadDestroy(pThread);
580 }
581 else
582 {
583 cRefs = 0;
584 AssertFailed();
585 }
586 return cRefs;
587}
588
589
590/**
591 * Destroys the per thread data.
592 *
593 * @param pThread The thread to destroy.
594 */
595static void rtThreadDestroy(PRTTHREADINT pThread)
596{
597 RTSEMEVENTMULTI hEvt1, hEvt2;
598 /*
599 * Remove it from the tree and mark it as dead.
600 *
601 * Threads that has seen rtThreadTerminate and should already have been
602 * removed from the tree. There is probably no thread that should
603 * require removing here. However, be careful making sure that cRefs
604 * isn't 0 if we do or we'll blow up because the strict locking code
605 * will be calling us back.
606 */
607 if (ASMBitTest(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT))
608 {
609 ASMAtomicIncU32(&pThread->cRefs);
610 rtThreadRemove(pThread);
611 ASMAtomicDecU32(&pThread->cRefs);
612 }
613
614 /*
615 * Invalidate the thread structure.
616 */
617#ifdef IN_RING3
618 rtLockValidatorSerializeDestructEnter();
619
620 rtLockValidatorDeletePerThread(&pThread->LockValidator);
621#endif
622#ifdef RT_WITH_ICONV_CACHE
623 rtStrIconvCacheDestroy(pThread);
624#endif
625 ASMAtomicXchgU32(&pThread->u32Magic, RTTHREADINT_MAGIC_DEAD);
626 ASMAtomicWritePtr(&pThread->Core.Key, (void *)NIL_RTTHREAD);
627 pThread->enmType = RTTHREADTYPE_INVALID;
628 hEvt1 = pThread->EventUser;
629 pThread->EventUser = NIL_RTSEMEVENTMULTI;
630 hEvt2 = pThread->EventTerminated;
631 pThread->EventTerminated = NIL_RTSEMEVENTMULTI;
632
633#ifdef IN_RING3
634 rtLockValidatorSerializeDestructLeave();
635#endif
636
637 /*
638 * Destroy semaphore resources and free the bugger.
639 */
640 RTSemEventMultiDestroy(hEvt1);
641 if (hEvt2 != NIL_RTSEMEVENTMULTI)
642 RTSemEventMultiDestroy(hEvt2);
643
644 rtThreadNativeDestroy(pThread);
645 RTMemFree(pThread);
646}
647
648
649/**
650 * Terminates the thread.
651 * Called by the thread wrapper function when the thread terminates.
652 *
653 * @param pThread The thread structure.
654 * @param rc The thread result code.
655 */
656DECLHIDDEN(void) rtThreadTerminate(PRTTHREADINT pThread, int rc)
657{
658 Assert(pThread->cRefs >= 1);
659
660#ifdef IPRT_WITH_GENERIC_TLS
661 /*
662 * Destroy TLS entries.
663 */
664 rtThreadTlsDestruction(pThread);
665#endif /* IPRT_WITH_GENERIC_TLS */
666
667 /*
668 * Set the rc, mark it terminated and signal anyone waiting.
669 */
670 pThread->rc = rc;
671 rtThreadSetState(pThread, RTTHREADSTATE_TERMINATED);
672 ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAGS_TERMINATED);
673 if (pThread->EventTerminated != NIL_RTSEMEVENTMULTI)
674 RTSemEventMultiSignal(pThread->EventTerminated);
675
676 /*
677 * Remove the thread from the tree so that there will be no
678 * key clashes in the AVL tree and release our reference to ourself.
679 */
680 rtThreadRemove(pThread);
681 rtThreadRelease(pThread);
682}
683
684
685/**
686 * The common thread main function.
687 * This is called by rtThreadNativeMain().
688 *
689 * @returns The status code of the thread.
690 * pThread is dereference by the thread before returning!
691 * @param pThread The thread structure.
692 * @param NativeThread The native thread id.
693 * @param pszThreadName The name of the thread (purely a dummy for backtrace).
694 */
695DECLCALLBACK(DECLHIDDEN(int)) rtThreadMain(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread, const char *pszThreadName)
696{
697 int rc;
698 NOREF(pszThreadName);
699 rtThreadInsert(pThread, NativeThread);
700 Log(("rtThreadMain: Starting: pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
701 pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
702
703 /*
704 * Change the priority.
705 */
706 rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
707#ifdef IN_RING3
708 AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d enmPriority=%d rc=%Rrc\n",
709 pThread, NativeThread, pThread->szName, pThread->enmType, g_enmProcessPriority, rc));
710#else
711 AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d rc=%Rrc\n",
712 pThread, NativeThread, pThread->szName, pThread->enmType, rc));
713#endif
714
715 /*
716 * Call thread function and terminate when it returns.
717 */
718 rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
719 rc = pThread->pfnThread(pThread, pThread->pvUser);
720
721 /*
722 * Paranoia checks for leftover resources.
723 */
724#ifdef RTSEMRW_STRICT
725 int32_t cWrite = ASMAtomicReadS32(&pThread->cWriteLocks);
726 Assert(!cWrite);
727 int32_t cRead = ASMAtomicReadS32(&pThread->cReadLocks);
728 Assert(!cRead);
729#endif
730
731 Log(("rtThreadMain: Terminating: rc=%d pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
732 rc, pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
733 rtThreadTerminate(pThread, rc);
734 return rc;
735}
736
737
738/**
739 * Create a new thread.
740 *
741 * @returns iprt status code.
742 * @param pThread Where to store the thread handle to the new thread. (optional)
743 * @param pfnThread The thread function.
744 * @param pvUser User argument.
745 * @param cbStack The size of the stack for the new thread.
746 * Use 0 for the default stack size.
747 * @param enmType The thread type. Used for deciding scheduling attributes
748 * of the thread.
749 * @param fFlags Flags of the RTTHREADFLAGS type (ORed together).
750 * @param pszName Thread name.
751 */
752RTDECL(int) RTThreadCreate(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
753 RTTHREADTYPE enmType, unsigned fFlags, const char *pszName)
754{
755 int rc;
756 PRTTHREADINT pThreadInt;
757
758 LogFlow(("RTThreadCreate: pThread=%p pfnThread=%p pvUser=%p cbStack=%#x enmType=%d fFlags=%#x pszName=%p:{%s}\n",
759 pThread, pfnThread, pvUser, cbStack, enmType, fFlags, pszName, pszName));
760
761 /*
762 * Validate input.
763 */
764 if (!VALID_PTR(pThread) && pThread)
765 {
766 Assert(VALID_PTR(pThread));
767 return VERR_INVALID_PARAMETER;
768 }
769 if (!VALID_PTR(pfnThread))
770 {
771 Assert(VALID_PTR(pfnThread));
772 return VERR_INVALID_PARAMETER;
773 }
774 if (!pszName || !*pszName || strlen(pszName) >= RTTHREAD_NAME_LEN)
775 {
776 AssertMsgFailed(("pszName=%s (max len is %d because of logging)\n", pszName, RTTHREAD_NAME_LEN - 1));
777 return VERR_INVALID_PARAMETER;
778 }
779 if (fFlags & ~RTTHREADFLAGS_MASK)
780 {
781 AssertMsgFailed(("fFlags=%#x\n", fFlags));
782 return VERR_INVALID_PARAMETER;
783 }
784
785 /*
786 * Allocate thread argument.
787 */
788 pThreadInt = rtThreadAlloc(enmType, fFlags, 0, pszName);
789 if (pThreadInt)
790 {
791 RTNATIVETHREAD NativeThread;
792
793 pThreadInt->pfnThread = pfnThread;
794 pThreadInt->pvUser = pvUser;
795 pThreadInt->cbStack = cbStack;
796
797 rc = rtThreadNativeCreate(pThreadInt, &NativeThread);
798 if (RT_SUCCESS(rc))
799 {
800 rtThreadInsert(pThreadInt, NativeThread);
801 rtThreadRelease(pThreadInt);
802 Log(("RTThreadCreate: Created thread %p (%p) %s\n", pThreadInt, NativeThread, pszName));
803 if (pThread)
804 *pThread = pThreadInt;
805 return VINF_SUCCESS;
806 }
807
808 pThreadInt->cRefs = 1;
809 rtThreadRelease(pThreadInt);
810 }
811 else
812 rc = VERR_NO_TMP_MEMORY;
813 LogFlow(("RTThreadCreate: Failed to create thread, rc=%Rrc\n", rc));
814 AssertReleaseRC(rc);
815 return rc;
816}
817RT_EXPORT_SYMBOL(RTThreadCreate);
818
819
820/**
821 * Create a new thread.
822 *
823 * Same as RTThreadCreate except the name is given in the RTStrPrintfV form.
824 *
825 * @returns iprt status code.
826 * @param pThread See RTThreadCreate.
827 * @param pfnThread See RTThreadCreate.
828 * @param pvUser See RTThreadCreate.
829 * @param cbStack See RTThreadCreate.
830 * @param enmType See RTThreadCreate.
831 * @param fFlags See RTThreadCreate.
832 * @param pszNameFmt Thread name format.
833 * @param va Format arguments.
834 */
835RTDECL(int) RTThreadCreateV(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
836 RTTHREADTYPE enmType, uint32_t fFlags, const char *pszNameFmt, va_list va)
837{
838 char szName[RTTHREAD_NAME_LEN * 2];
839 RTStrPrintfV(szName, sizeof(szName), pszNameFmt, va);
840 return RTThreadCreate(pThread, pfnThread, pvUser, cbStack, enmType, fFlags, szName);
841}
842RT_EXPORT_SYMBOL(RTThreadCreateV);
843
844
845/**
846 * Create a new thread.
847 *
848 * Same as RTThreadCreate except the name is given in the RTStrPrintf form.
849 *
850 * @returns iprt status code.
851 * @param pThread See RTThreadCreate.
852 * @param pfnThread See RTThreadCreate.
853 * @param pvUser See RTThreadCreate.
854 * @param cbStack See RTThreadCreate.
855 * @param enmType See RTThreadCreate.
856 * @param fFlags See RTThreadCreate.
857 * @param pszNameFmt Thread name format.
858 * @param ... Format arguments.
859 */
860RTDECL(int) RTThreadCreateF(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
861 RTTHREADTYPE enmType, uint32_t fFlags, const char *pszNameFmt, ...)
862{
863 va_list va;
864 int rc;
865 va_start(va, pszNameFmt);
866 rc = RTThreadCreateV(pThread, pfnThread, pvUser, cbStack, enmType, fFlags, pszNameFmt, va);
867 va_end(va);
868 return rc;
869}
870RT_EXPORT_SYMBOL(RTThreadCreateF);
871
872
873/**
874 * Gets the native thread id of a IPRT thread.
875 *
876 * @returns The native thread id.
877 * @param Thread The IPRT thread.
878 */
879RTDECL(RTNATIVETHREAD) RTThreadGetNative(RTTHREAD Thread)
880{
881 PRTTHREADINT pThread = rtThreadGet(Thread);
882 if (pThread)
883 {
884 RTNATIVETHREAD NativeThread = (RTNATIVETHREAD)pThread->Core.Key;
885 rtThreadRelease(pThread);
886 return NativeThread;
887 }
888 return NIL_RTNATIVETHREAD;
889}
890RT_EXPORT_SYMBOL(RTThreadGetNative);
891
892
893/**
894 * Gets the IPRT thread of a native thread.
895 *
896 * @returns The IPRT thread handle
897 * @returns NIL_RTTHREAD if not a thread known to IPRT.
898 * @param NativeThread The native thread handle/id.
899 */
900RTDECL(RTTHREAD) RTThreadFromNative(RTNATIVETHREAD NativeThread)
901{
902 PRTTHREADINT pThread = rtThreadGetByNative(NativeThread);
903 if (pThread)
904 return pThread;
905 return NIL_RTTHREAD;
906}
907RT_EXPORT_SYMBOL(RTThreadFromNative);
908
909
910/**
911 * Gets the name of the current thread thread.
912 *
913 * @returns Pointer to readonly name string.
914 * @returns NULL on failure.
915 */
916RTDECL(const char *) RTThreadSelfName(void)
917{
918 RTTHREAD Thread = RTThreadSelf();
919 if (Thread != NIL_RTTHREAD)
920 {
921 PRTTHREADINT pThread = rtThreadGet(Thread);
922 if (pThread)
923 {
924 const char *szName = pThread->szName;
925 rtThreadRelease(pThread);
926 return szName;
927 }
928 }
929 return NULL;
930}
931RT_EXPORT_SYMBOL(RTThreadSelfName);
932
933
934/**
935 * Gets the name of a thread.
936 *
937 * @returns Pointer to readonly name string.
938 * @returns NULL on failure.
939 * @param Thread Thread handle of the thread to query the name of.
940 */
941RTDECL(const char *) RTThreadGetName(RTTHREAD Thread)
942{
943 PRTTHREADINT pThread;
944 if (Thread == NIL_RTTHREAD)
945 return NULL;
946 pThread = rtThreadGet(Thread);
947 if (pThread)
948 {
949 const char *szName = pThread->szName;
950 rtThreadRelease(pThread);
951 return szName;
952 }
953 return NULL;
954}
955RT_EXPORT_SYMBOL(RTThreadGetName);
956
957
958/**
959 * Sets the name of a thread.
960 *
961 * @returns iprt status code.
962 * @param Thread Thread handle of the thread to query the name of.
963 * @param pszName The thread name.
964 */
965RTDECL(int) RTThreadSetName(RTTHREAD Thread, const char *pszName)
966{
967 /*
968 * Validate input.
969 */
970 PRTTHREADINT pThread;
971 size_t cchName = strlen(pszName);
972 if (cchName >= RTTHREAD_NAME_LEN)
973 {
974 AssertMsgFailed(("pszName=%s is too long, max is %d\n", pszName, RTTHREAD_NAME_LEN - 1));
975 return VERR_INVALID_PARAMETER;
976 }
977 pThread = rtThreadGet(Thread);
978 if (!pThread)
979 return VERR_INVALID_HANDLE;
980
981 /*
982 * Update the name.
983 */
984 pThread->szName[cchName] = '\0'; /* paranoia */
985 memcpy(pThread->szName, pszName, cchName);
986 rtThreadRelease(pThread);
987 return VINF_SUCCESS;
988}
989RT_EXPORT_SYMBOL(RTThreadSetName);
990
991
992/**
993 * Checks if the specified thread is the main thread.
994 *
995 * @returns true if it is, false if it isn't.
996 *
997 * @param hThread The thread handle.
998 *
999 * @remarks This function may not return the correct value when rtR3Init was
1000 * called on a thread of the than the main one. This could for
1001 * instance happen when the DLL/DYLIB/SO containing IPRT is dynamically
1002 * loaded at run time by a different thread.
1003 */
1004RTDECL(bool) RTThreadIsMain(RTTHREAD hThread)
1005{
1006 PRTTHREADINT pThread = rtThreadGet(hThread);
1007 if (pThread)
1008 {
1009 bool fRc = !!(pThread->fIntFlags & RTTHREADINT_FLAGS_MAIN);
1010 rtThreadRelease(pThread);
1011 return fRc;
1012 }
1013 return false;
1014}
1015RT_EXPORT_SYMBOL(RTThreadIsMain);
1016
1017
1018RTDECL(bool) RTThreadIsSelfAlive(void)
1019{
1020 if (g_frtThreadInitialized)
1021 {
1022 RTTHREAD hSelf = RTThreadSelf();
1023 if (hSelf != NIL_RTTHREAD)
1024 {
1025 /*
1026 * Inspect the thread state. ASSUMES thread state order.
1027 */
1028 RTTHREADSTATE enmState = rtThreadGetState(hSelf);
1029 if ( enmState >= RTTHREADSTATE_RUNNING
1030 && enmState <= RTTHREADSTATE_END)
1031 return true;
1032 }
1033 }
1034 return false;
1035}
1036RT_EXPORT_SYMBOL(RTThreadIsSelfAlive);
1037
1038
1039RTDECL(bool) RTThreadIsSelfKnown(void)
1040{
1041 if (g_frtThreadInitialized)
1042 {
1043 RTTHREAD hSelf = RTThreadSelf();
1044 if (hSelf != NIL_RTTHREAD)
1045 return true;
1046 }
1047 return false;
1048}
1049RT_EXPORT_SYMBOL(RTThreadIsSelfKnown);
1050
1051
1052RTDECL(bool) RTThreadIsInitialized(void)
1053{
1054 return g_frtThreadInitialized;
1055}
1056RT_EXPORT_SYMBOL(RTThreadIsInitialized);
1057
1058
1059/**
1060 * Signal the user event.
1061 *
1062 * @returns iprt status code.
1063 */
1064RTDECL(int) RTThreadUserSignal(RTTHREAD Thread)
1065{
1066 int rc;
1067 PRTTHREADINT pThread = rtThreadGet(Thread);
1068 if (pThread)
1069 {
1070 rc = RTSemEventMultiSignal(pThread->EventUser);
1071 rtThreadRelease(pThread);
1072 }
1073 else
1074 rc = VERR_INVALID_HANDLE;
1075 return rc;
1076}
1077RT_EXPORT_SYMBOL(RTThreadUserSignal);
1078
1079
1080/**
1081 * Wait for the user event, resume on interruption.
1082 *
1083 * @returns iprt status code.
1084 * @param Thread The thread to wait for.
1085 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1086 * an indefinite wait.
1087 */
1088RTDECL(int) RTThreadUserWait(RTTHREAD Thread, RTMSINTERVAL cMillies)
1089{
1090 int rc;
1091 PRTTHREADINT pThread = rtThreadGet(Thread);
1092 if (pThread)
1093 {
1094 rc = RTSemEventMultiWait(pThread->EventUser, cMillies);
1095 rtThreadRelease(pThread);
1096 }
1097 else
1098 rc = VERR_INVALID_HANDLE;
1099 return rc;
1100}
1101RT_EXPORT_SYMBOL(RTThreadUserWait);
1102
1103
1104/**
1105 * Wait for the user event, return on interruption.
1106 *
1107 * @returns iprt status code.
1108 * @param Thread The thread to wait for.
1109 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1110 * an indefinite wait.
1111 */
1112RTDECL(int) RTThreadUserWaitNoResume(RTTHREAD Thread, RTMSINTERVAL cMillies)
1113{
1114 int rc;
1115 PRTTHREADINT pThread = rtThreadGet(Thread);
1116 if (pThread)
1117 {
1118 rc = RTSemEventMultiWaitNoResume(pThread->EventUser, cMillies);
1119 rtThreadRelease(pThread);
1120 }
1121 else
1122 rc = VERR_INVALID_HANDLE;
1123 return rc;
1124}
1125RT_EXPORT_SYMBOL(RTThreadUserWaitNoResume);
1126
1127
1128/**
1129 * Reset the user event.
1130 *
1131 * @returns iprt status code.
1132 * @param Thread The thread to reset.
1133 */
1134RTDECL(int) RTThreadUserReset(RTTHREAD Thread)
1135{
1136 int rc;
1137 PRTTHREADINT pThread = rtThreadGet(Thread);
1138 if (pThread)
1139 {
1140 rc = RTSemEventMultiReset(pThread->EventUser);
1141 rtThreadRelease(pThread);
1142 }
1143 else
1144 rc = VERR_INVALID_HANDLE;
1145 return rc;
1146}
1147RT_EXPORT_SYMBOL(RTThreadUserReset);
1148
1149
1150/**
1151 * Wait for the thread to terminate.
1152 *
1153 * @returns iprt status code.
1154 * @param Thread The thread to wait for.
1155 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1156 * an indefinite wait.
1157 * @param prc Where to store the return code of the thread. Optional.
1158 * @param fAutoResume Whether or not to resume the wait on VERR_INTERRUPTED.
1159 */
1160static int rtThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc, bool fAutoResume)
1161{
1162 int rc = VERR_INVALID_HANDLE;
1163 if (Thread != NIL_RTTHREAD)
1164 {
1165 PRTTHREADINT pThread = rtThreadGet(Thread);
1166 if (pThread)
1167 {
1168 if (pThread->fFlags & RTTHREADFLAGS_WAITABLE)
1169 {
1170#if defined(IN_RING3) && defined(RT_OS_WINDOWS)
1171 if (RT_LIKELY(rtThreadNativeIsAliveKludge(pThread)))
1172#endif
1173 {
1174 if (fAutoResume)
1175 rc = RTSemEventMultiWait(pThread->EventTerminated, cMillies);
1176 else
1177 rc = RTSemEventMultiWaitNoResume(pThread->EventTerminated, cMillies);
1178 }
1179#if defined(IN_RING3) && defined(RT_OS_WINDOWS)
1180 else
1181 {
1182 rc = VINF_SUCCESS;
1183 if (pThread->rc == VERR_PROCESS_RUNNING)
1184 pThread->rc = VERR_THREAD_IS_DEAD;
1185 }
1186#endif
1187 if (RT_SUCCESS(rc))
1188 {
1189 if (prc)
1190 *prc = pThread->rc;
1191
1192 /*
1193 * If the thread is marked as waitable, we'll do one additional
1194 * release in order to free up the thread structure (see how we
1195 * init cRef in rtThreadAlloc()).
1196 */
1197 if (ASMAtomicBitTestAndClear(&pThread->fFlags, RTTHREADFLAGS_WAITABLE_BIT))
1198 {
1199 rtThreadRelease(pThread);
1200#ifdef IN_RING0
1201 /*
1202 * IPRT termination kludge. Call native code to make sure
1203 * the last thread is really out of IPRT to prevent it from
1204 * crashing after we destroyed the spinlock in rtThreadTerm.
1205 */
1206 if ( ASMAtomicReadU32(&g_cThreadInTree) == 1
1207 && ASMAtomicReadU32(&pThread->cRefs) > 1)
1208 rtThreadNativeWaitKludge(pThread);
1209#endif
1210 }
1211 }
1212 }
1213 else
1214 {
1215 rc = VERR_THREAD_NOT_WAITABLE;
1216 AssertRC(rc);
1217 }
1218 rtThreadRelease(pThread);
1219 }
1220 }
1221 return rc;
1222}
1223
1224
1225/**
1226 * Wait for the thread to terminate, resume on interruption.
1227 *
1228 * @returns iprt status code.
1229 * Will not return VERR_INTERRUPTED.
1230 * @param Thread The thread to wait for.
1231 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1232 * an indefinite wait.
1233 * @param prc Where to store the return code of the thread. Optional.
1234 */
1235RTDECL(int) RTThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc)
1236{
1237 int rc = rtThreadWait(Thread, cMillies, prc, true);
1238 Assert(rc != VERR_INTERRUPTED);
1239 return rc;
1240}
1241RT_EXPORT_SYMBOL(RTThreadWait);
1242
1243
1244/**
1245 * Wait for the thread to terminate, return on interruption.
1246 *
1247 * @returns iprt status code.
1248 * @param Thread The thread to wait for.
1249 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1250 * an indefinite wait.
1251 * @param prc Where to store the return code of the thread. Optional.
1252 */
1253RTDECL(int) RTThreadWaitNoResume(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc)
1254{
1255 return rtThreadWait(Thread, cMillies, prc, false);
1256}
1257RT_EXPORT_SYMBOL(RTThreadWaitNoResume);
1258
1259
1260/**
1261 * Changes the type of the specified thread.
1262 *
1263 * @returns iprt status code.
1264 * @param Thread The thread which type should be changed.
1265 * @param enmType The new thread type.
1266 */
1267RTDECL(int) RTThreadSetType(RTTHREAD Thread, RTTHREADTYPE enmType)
1268{
1269 /*
1270 * Validate input.
1271 */
1272 int rc;
1273 if ( enmType > RTTHREADTYPE_INVALID
1274 && enmType < RTTHREADTYPE_END)
1275 {
1276 PRTTHREADINT pThread = rtThreadGet(Thread);
1277 if (pThread)
1278 {
1279 if (rtThreadIsAlive(pThread))
1280 {
1281 /*
1282 * Do the job.
1283 */
1284 RT_THREAD_LOCK_RW();
1285 rc = rtThreadNativeSetPriority(pThread, enmType);
1286 if (RT_SUCCESS(rc))
1287 ASMAtomicXchgSize(&pThread->enmType, enmType);
1288 RT_THREAD_UNLOCK_RW();
1289 if (RT_FAILURE(rc))
1290 Log(("RTThreadSetType: failed on thread %p (%s), rc=%Rrc!!!\n", Thread, pThread->szName, rc));
1291 }
1292 else
1293 rc = VERR_THREAD_IS_DEAD;
1294 rtThreadRelease(pThread);
1295 }
1296 else
1297 rc = VERR_INVALID_HANDLE;
1298 }
1299 else
1300 {
1301 AssertMsgFailed(("enmType=%d\n", enmType));
1302 rc = VERR_INVALID_PARAMETER;
1303 }
1304 return rc;
1305}
1306RT_EXPORT_SYMBOL(RTThreadSetType);
1307
1308
1309/**
1310 * Gets the type of the specified thread.
1311 *
1312 * @returns The thread type.
1313 * @returns RTTHREADTYPE_INVALID if the thread handle is invalid.
1314 * @param Thread The thread in question.
1315 */
1316RTDECL(RTTHREADTYPE) RTThreadGetType(RTTHREAD Thread)
1317{
1318 RTTHREADTYPE enmType = RTTHREADTYPE_INVALID;
1319 PRTTHREADINT pThread = rtThreadGet(Thread);
1320 if (pThread)
1321 {
1322 enmType = pThread->enmType;
1323 rtThreadRelease(pThread);
1324 }
1325 return enmType;
1326}
1327RT_EXPORT_SYMBOL(RTThreadGetType);
1328
1329#ifdef IN_RING3
1330
1331/**
1332 * Recalculates scheduling attributes for the default process
1333 * priority using the specified priority type for the calling thread.
1334 *
1335 * The scheduling attributes are targeted at threads and they are protected
1336 * by the thread read-write semaphore, that's why RTProc is forwarding the
1337 * operation to RTThread.
1338 *
1339 * @returns iprt status code.
1340 * @remarks Will only work for strict builds.
1341 */
1342int rtThreadDoCalcDefaultPriority(RTTHREADTYPE enmType)
1343{
1344 RT_THREAD_LOCK_RW();
1345 int rc = rtSchedNativeCalcDefaultPriority(enmType);
1346 RT_THREAD_UNLOCK_RW();
1347 return rc;
1348}
1349
1350
1351/**
1352 * Thread enumerator - sets the priority of one thread.
1353 *
1354 * @returns 0 to continue.
1355 * @returns !0 to stop. In our case a VERR_ code.
1356 * @param pNode The thread node.
1357 * @param pvUser The new priority.
1358 */
1359static DECLCALLBACK(int) rtThreadSetPriorityOne(PAVLPVNODECORE pNode, void *pvUser)
1360{
1361 PRTTHREADINT pThread = (PRTTHREADINT)pNode;
1362 if (!rtThreadIsAlive(pThread))
1363 return VINF_SUCCESS;
1364 int rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
1365 if (RT_SUCCESS(rc)) /* hide any warnings */
1366 return VINF_SUCCESS;
1367 NOREF(pvUser);
1368 return rc;
1369}
1370
1371
1372/**
1373 * Attempts to alter the priority of the current process.
1374 *
1375 * The scheduling attributes are targeted at threads and they are protected
1376 * by the thread read-write semaphore, that's why RTProc is forwarding the
1377 * operation to RTThread. This operation also involves updating all thread
1378 * which is much faster done from RTThread.
1379 *
1380 * @returns iprt status code.
1381 * @param enmPriority The new priority.
1382 */
1383DECLHIDDEN(int) rtThreadDoSetProcPriority(RTPROCPRIORITY enmPriority)
1384{
1385 LogFlow(("rtThreadDoSetProcPriority: enmPriority=%d\n", enmPriority));
1386
1387 /*
1388 * First validate that we're allowed by the OS to use all the
1389 * scheduling attributes defined by the specified process priority.
1390 */
1391 RT_THREAD_LOCK_RW();
1392 int rc = rtProcNativeSetPriority(enmPriority);
1393 if (RT_SUCCESS(rc))
1394 {
1395 /*
1396 * Update the priority of existing thread.
1397 */
1398 rc = RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
1399 if (RT_SUCCESS(rc))
1400 ASMAtomicXchgSize(&g_enmProcessPriority, enmPriority);
1401 else
1402 {
1403 /*
1404 * Failed, restore the priority.
1405 */
1406 rtProcNativeSetPriority(g_enmProcessPriority);
1407 RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
1408 }
1409 }
1410 RT_THREAD_UNLOCK_RW();
1411 LogFlow(("rtThreadDoSetProcPriority: returns %Rrc\n", rc));
1412 return rc;
1413}
1414
1415
1416/**
1417 * Change the thread state to blocking.
1418 *
1419 * @param hThread The current thread.
1420 * @param enmState The sleep state.
1421 * @param fReallySleeping Really going to sleep now.
1422 */
1423RTDECL(void) RTThreadBlocking(RTTHREAD hThread, RTTHREADSTATE enmState, bool fReallySleeping)
1424{
1425 Assert(RTTHREAD_IS_SLEEPING(enmState));
1426 PRTTHREADINT pThread = hThread;
1427 if (pThread != NIL_RTTHREAD)
1428 {
1429 Assert(pThread == RTThreadSelf());
1430 if (rtThreadGetState(pThread) == RTTHREADSTATE_RUNNING)
1431 rtThreadSetState(pThread, enmState);
1432 ASMAtomicWriteBool(&pThread->fReallySleeping, fReallySleeping);
1433 }
1434}
1435RT_EXPORT_SYMBOL(RTThreadBlocking);
1436
1437
1438/**
1439 * Unblocks a thread.
1440 *
1441 * This function is paired with rtThreadBlocking.
1442 *
1443 * @param hThread The current thread.
1444 * @param enmCurState The current state, used to check for nested blocking.
1445 * The new state will be running.
1446 */
1447RTDECL(void) RTThreadUnblocked(RTTHREAD hThread, RTTHREADSTATE enmCurState)
1448{
1449 PRTTHREADINT pThread = hThread;
1450 if (pThread != NIL_RTTHREAD)
1451 {
1452 Assert(pThread == RTThreadSelf());
1453 ASMAtomicWriteBool(&pThread->fReallySleeping, false);
1454
1455 RTTHREADSTATE enmActualState = rtThreadGetState(pThread);
1456 if (enmActualState == enmCurState)
1457 {
1458 rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
1459 if ( pThread->LockValidator.pRec
1460 && pThread->LockValidator.enmRecState == enmCurState)
1461 ASMAtomicWriteNullPtr(&pThread->LockValidator.pRec);
1462 }
1463 /* This is a bit ugly... :-/ */
1464 else if ( ( enmActualState == RTTHREADSTATE_TERMINATED
1465 || enmActualState == RTTHREADSTATE_INITIALIZING)
1466 && pThread->LockValidator.pRec)
1467 ASMAtomicWriteNullPtr(&pThread->LockValidator.pRec);
1468 Assert( pThread->LockValidator.pRec == NULL
1469 || RTTHREAD_IS_SLEEPING(enmActualState));
1470 }
1471}
1472RT_EXPORT_SYMBOL(RTThreadUnblocked);
1473
1474
1475/**
1476 * Get the current thread state.
1477 *
1478 * @returns The thread state.
1479 * @param hThread The thread.
1480 */
1481RTDECL(RTTHREADSTATE) RTThreadGetState(RTTHREAD hThread)
1482{
1483 RTTHREADSTATE enmState = RTTHREADSTATE_INVALID;
1484 PRTTHREADINT pThread = rtThreadGet(hThread);
1485 if (pThread)
1486 {
1487 enmState = rtThreadGetState(pThread);
1488 rtThreadRelease(pThread);
1489 }
1490 return enmState;
1491}
1492RT_EXPORT_SYMBOL(RTThreadGetState);
1493
1494
1495RTDECL(RTTHREADSTATE) RTThreadGetReallySleeping(RTTHREAD hThread)
1496{
1497 RTTHREADSTATE enmState = RTTHREADSTATE_INVALID;
1498 PRTTHREADINT pThread = rtThreadGet(hThread);
1499 if (pThread)
1500 {
1501 enmState = rtThreadGetState(pThread);
1502 if (!ASMAtomicUoReadBool(&pThread->fReallySleeping))
1503 enmState = RTTHREADSTATE_RUNNING;
1504 rtThreadRelease(pThread);
1505 }
1506 return enmState;
1507}
1508RT_EXPORT_SYMBOL(RTThreadGetReallySleeping);
1509
1510
1511/**
1512 * Translate a thread state into a string.
1513 *
1514 * @returns Pointer to a read-only string containing the state name.
1515 * @param enmState The state.
1516 */
1517RTDECL(const char *) RTThreadStateName(RTTHREADSTATE enmState)
1518{
1519 switch (enmState)
1520 {
1521 case RTTHREADSTATE_INVALID: return "INVALID";
1522 case RTTHREADSTATE_INITIALIZING: return "INITIALIZING";
1523 case RTTHREADSTATE_TERMINATED: return "TERMINATED";
1524 case RTTHREADSTATE_RUNNING: return "RUNNING";
1525 case RTTHREADSTATE_CRITSECT: return "CRITSECT";
1526 case RTTHREADSTATE_EVENT: return "EVENT";
1527 case RTTHREADSTATE_EVENT_MULTI: return "EVENT_MULTI";
1528 case RTTHREADSTATE_FAST_MUTEX: return "FAST_MUTEX";
1529 case RTTHREADSTATE_MUTEX: return "MUTEX";
1530 case RTTHREADSTATE_RW_READ: return "RW_READ";
1531 case RTTHREADSTATE_RW_WRITE: return "RW_WRITE";
1532 case RTTHREADSTATE_SLEEP: return "SLEEP";
1533 case RTTHREADSTATE_SPIN_MUTEX: return "SPIN_MUTEX";
1534 default: return "UnknownThreadState";
1535 }
1536}
1537RT_EXPORT_SYMBOL(RTThreadStateName);
1538
1539#endif /* IN_RING3 */
1540#ifdef IPRT_WITH_GENERIC_TLS
1541
1542/**
1543 * Thread enumerator - clears a TLS entry.
1544 *
1545 * @returns 0.
1546 * @param pNode The thread node.
1547 * @param pvUser The TLS index.
1548 */
1549static DECLCALLBACK(int) rtThreadClearTlsEntryCallback(PAVLPVNODECORE pNode, void *pvUser)
1550{
1551 PRTTHREADINT pThread = (PRTTHREADINT)pNode;
1552 RTTLS iTls = (RTTLS)(uintptr_t)pvUser;
1553 ASMAtomicWriteNullPtr(&pThread->apvTlsEntries[iTls]);
1554 return 0;
1555}
1556
1557
1558/**
1559 * Helper for the generic TLS implementation that clears a given TLS
1560 * entry on all threads.
1561 *
1562 * @param iTls The TLS entry. (valid)
1563 */
1564DECLHIDDEN(void) rtThreadClearTlsEntry(RTTLS iTls)
1565{
1566 RT_THREAD_LOCK_RD();
1567 RTAvlPVDoWithAll(&g_ThreadTree, true /* fFromLeft*/, rtThreadClearTlsEntryCallback, (void *)(uintptr_t)iTls);
1568 RT_THREAD_UNLOCK_RD();
1569}
1570
1571#endif /* IPRT_WITH_GENERIC_TLS */
1572
1573
1574#if defined(RT_OS_WINDOWS) && defined(IN_RING3)
1575
1576/**
1577 * Thread enumeration callback for RTThreadNameThreads
1578 */
1579static DECLCALLBACK(int) rtThreadNameThreadCallback(PAVLPVNODECORE pNode, void *pvUser)
1580{
1581 PRTTHREADINT pThread = (PRTTHREADINT)pNode;
1582 rtThreadNativeInformDebugger(pThread);
1583 RT_NOREF_PV(pvUser);
1584 return 0;
1585}
1586
1587/**
1588 * A function that can be called from the windows debugger to get the names of
1589 * all threads when attaching to a process.
1590 *
1591 * Usage: .call VBoxRT!RTThreadNameThreads()
1592 *
1593 * @returns 0
1594 * @remarks Do not call from source code as it skips locks.
1595 */
1596extern "C" RTDECL(int) RTThreadNameThreads(void);
1597RTDECL(int) RTThreadNameThreads(void)
1598{
1599 return RTAvlPVDoWithAll(&g_ThreadTree, true /* fFromLeft*/, rtThreadNameThreadCallback, NULL);
1600}
1601
1602#endif
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