VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 44.6 KB
Line 
1/* $Id: thread.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - Threads, common routines.
4 */
5
6/*
7 * Copyright (C) 2006-2024 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.

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