VirtualBox

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

Last change on this file was 99775, checked in by vboxsync, 12 months ago

*: Mark functions as static if not used outside of a given compilation unit. Enables the compiler to optimize inlining, reduces the symbol tables, exposes unused functions and in some rare cases exposes mismtaches between function declarations and definitions, but most importantly reduces the number of parfait reports for the extern-function-no-forward-declaration category. This should not result in any functional changes, bugref:3409

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

© 2023 Oracle
ContactPrivacy policyTerms of Use