VirtualBox

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

Last change on this file since 25660 was 25660, checked in by vboxsync, 15 years ago

thread.cpp: Fixed case of accessing RTTHRADINT after it was freed.

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

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