VirtualBox

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

Last change on this file since 36555 was 36555, checked in by vboxsync, 14 years ago

Use DECLHIDDEN, especially in IPRT.

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