VirtualBox

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

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

IPRT: linux R0 threads

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 45.2 KB
Line 
1/* $Id: thread.cpp 36233 2011-03-09 17:05:12Z 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 */
129int 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 */
183void 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
267/**
268 * Adopts a non-IPRT thread.
269 *
270 * @returns IPRT status code.
271 * @param enmType The thread type.
272 * @param fFlags The thread flags. RTTHREADFLAGS_WAITABLE is not currently allowed.
273 * @param pszName The thread name. Optional.
274 * @param pThread Where to store the thread handle. Optional.
275 */
276RTDECL(int) RTThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, const char *pszName, PRTTHREAD pThread)
277{
278 int rc;
279 RTTHREAD Thread;
280
281 AssertReturn(!(fFlags & RTTHREADFLAGS_WAITABLE), VERR_INVALID_PARAMETER);
282 AssertReturn(!pszName || VALID_PTR(pszName), VERR_INVALID_POINTER);
283 AssertReturn(!pThread || VALID_PTR(pThread), VERR_INVALID_POINTER);
284
285 rc = VINF_SUCCESS;
286 Thread = RTThreadSelf();
287 if (Thread == NIL_RTTHREAD)
288 {
289 /* generate a name if none was given. */
290 char szName[RTTHREAD_NAME_LEN];
291 if (!pszName || !*pszName)
292 {
293 static uint32_t s_i32AlienId = 0;
294 uint32_t i32Id = ASMAtomicIncU32(&s_i32AlienId);
295 RTStrPrintf(szName, sizeof(szName), "ALIEN-%RX32", i32Id);
296 pszName = szName;
297 }
298
299 /* try adopt it */
300 rc = rtThreadAdopt(enmType, fFlags, 0, pszName);
301 Thread = RTThreadSelf();
302 Log(("RTThreadAdopt: %RTthrd %RTnthrd '%s' enmType=%d fFlags=%#x rc=%Rrc\n",
303 Thread, RTThreadNativeSelf(), pszName, enmType, fFlags, rc));
304 }
305 else
306 Log(("RTThreadAdopt: %RTthrd %RTnthrd '%s' enmType=%d fFlags=%#x - already adopted!\n",
307 Thread, RTThreadNativeSelf(), pszName, enmType, fFlags));
308
309 if (pThread)
310 *pThread = Thread;
311 return rc;
312}
313RT_EXPORT_SYMBOL(RTThreadAdopt);
314
315
316/**
317 * Get the thread handle of the current thread, automatically adopting alien
318 * threads.
319 *
320 * @returns Thread handle.
321 */
322RTDECL(RTTHREAD) RTThreadSelfAutoAdopt(void)
323{
324 RTTHREAD hSelf = RTThreadSelf();
325 if (RT_UNLIKELY(hSelf == NIL_RTTHREAD))
326 RTThreadAdopt(RTTHREADTYPE_DEFAULT, 0, NULL, &hSelf);
327 return hSelf;
328}
329RT_EXPORT_SYMBOL(RTThreadSelfAutoAdopt);
330
331
332/**
333 * Allocates a per thread data structure and initializes the basic fields.
334 *
335 * @returns Pointer to per thread data structure.
336 * This is reference once.
337 * @returns NULL on failure.
338 * @param enmType The thread type.
339 * @param fFlags The thread flags.
340 * @param fIntFlags The internal thread flags.
341 * @param pszName Pointer to the thread name.
342 */
343PRTTHREADINT rtThreadAlloc(RTTHREADTYPE enmType, unsigned fFlags, uint32_t fIntFlags, const char *pszName)
344{
345 PRTTHREADINT pThread = (PRTTHREADINT)RTMemAllocZ(sizeof(RTTHREADINT));
346 if (pThread)
347 {
348 size_t cchName;
349 int rc;
350
351 pThread->Core.Key = (void*)NIL_RTTHREAD;
352 pThread->u32Magic = RTTHREADINT_MAGIC;
353 cchName = strlen(pszName);
354 if (cchName >= RTTHREAD_NAME_LEN)
355 cchName = RTTHREAD_NAME_LEN - 1;
356 memcpy(pThread->szName, pszName, cchName);
357 pThread->szName[cchName] = '\0';
358 pThread->cRefs = 2 + !!(fFlags & RTTHREADFLAGS_WAITABLE); /* And extra reference if waitable. */
359 pThread->rc = VERR_PROCESS_RUNNING; /** @todo get a better error code! */
360 pThread->enmType = enmType;
361 pThread->fFlags = fFlags;
362 pThread->fIntFlags = fIntFlags;
363 pThread->enmState = RTTHREADSTATE_INITIALIZING;
364 pThread->fReallySleeping = false;
365#ifdef IN_RING3
366 rtLockValidatorInitPerThread(&pThread->LockValidator);
367#endif
368#ifdef RT_WITH_ICONV_CACHE
369 rtStrIconvCacheInit(pThread);
370#endif
371 rc = RTSemEventMultiCreate(&pThread->EventUser);
372 if (RT_SUCCESS(rc))
373 {
374 rc = RTSemEventMultiCreate(&pThread->EventTerminated);
375 if (RT_SUCCESS(rc))
376 return pThread;
377 RTSemEventMultiDestroy(pThread->EventUser);
378 }
379 RTMemFree(pThread);
380 }
381 return NULL;
382}
383
384
385/**
386 * Insert the per thread data structure into the tree.
387 *
388 * This can be called from both the thread it self and the parent,
389 * thus it must handle insertion failures in a nice manner.
390 *
391 * @param pThread Pointer to thread structure allocated by rtThreadAlloc().
392 * @param NativeThread The native thread id.
393 */
394void rtThreadInsert(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread)
395{
396 Assert(pThread);
397 Assert(pThread->u32Magic == RTTHREADINT_MAGIC);
398
399 {
400 RT_THREAD_LOCK_TMP(Tmp);
401 RT_THREAD_LOCK_RW(Tmp);
402
403 /*
404 * Do not insert a terminated thread.
405 *
406 * This may happen if the thread finishes before the RTThreadCreate call
407 * gets this far. Since the OS may quickly reuse the native thread ID
408 * it should not be reinserted at this point.
409 */
410 if (rtThreadGetState(pThread) != RTTHREADSTATE_TERMINATED)
411 {
412 /*
413 * Before inserting we must check if there is a thread with this id
414 * in the tree already. We're racing parent and child on insert here
415 * so that the handle is valid in both ends when they return / start.
416 *
417 * If it's not ourself we find, it's a dead alien thread and we will
418 * unlink it from the tree. Alien threads will be released at this point.
419 */
420 PRTTHREADINT pThreadOther = (PRTTHREADINT)RTAvlPVGet(&g_ThreadTree, (void *)NativeThread);
421 if (pThreadOther != pThread)
422 {
423 bool fRc;
424 /* remove dead alien if any */
425 if (pThreadOther)
426 {
427 AssertMsg(pThreadOther->fIntFlags & RTTHREADINT_FLAGS_ALIEN, ("%p:%s; %p:%s\n", pThread, pThread->szName, pThreadOther, pThreadOther->szName));
428 ASMAtomicBitClear(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT);
429 rtThreadRemoveLocked(pThreadOther);
430 if (pThreadOther->fIntFlags & RTTHREADINT_FLAGS_ALIEN)
431 rtThreadRelease(pThreadOther);
432 }
433
434 /* insert the thread */
435 ASMAtomicWritePtr(&pThread->Core.Key, (void *)NativeThread);
436 fRc = RTAvlPVInsert(&g_ThreadTree, &pThread->Core);
437 ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE);
438
439 AssertReleaseMsg(fRc, ("Lock problem? %p (%RTnthrd) %s\n", pThread, NativeThread, pThread->szName));
440 NOREF(fRc);
441 }
442 }
443
444 RT_THREAD_UNLOCK_RW(Tmp);
445 }
446}
447
448
449/**
450 * Removes the thread from the AVL tree, call owns the tree lock
451 * and has cleared the RTTHREADINT_FLAG_IN_TREE bit.
452 *
453 * @param pThread The thread to remove.
454 */
455static void rtThreadRemoveLocked(PRTTHREADINT pThread)
456{
457 PRTTHREADINT pThread2 = (PRTTHREADINT)RTAvlPVRemove(&g_ThreadTree, pThread->Core.Key);
458#if !defined(RT_OS_OS2) /** @todo this asserts for threads created by NSPR */
459 AssertMsg(pThread2 == pThread, ("%p(%s) != %p (%p/%s)\n", pThread2, pThread2 ? pThread2->szName : "<null>",
460 pThread, pThread->Core.Key, pThread->szName));
461#endif
462 NOREF(pThread2);
463}
464
465
466/**
467 * Removes the thread from the AVL tree.
468 *
469 * @param pThread The thread to remove.
470 */
471static void rtThreadRemove(PRTTHREADINT pThread)
472{
473 RT_THREAD_LOCK_TMP(Tmp);
474 RT_THREAD_LOCK_RW(Tmp);
475 if (ASMAtomicBitTestAndClear(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT))
476 rtThreadRemoveLocked(pThread);
477 RT_THREAD_UNLOCK_RW(Tmp);
478}
479
480
481/**
482 * Checks if a thread is alive or not.
483 *
484 * @returns true if the thread is alive (or we don't really know).
485 * @returns false if the thread has surely terminate.
486 */
487DECLINLINE(bool) rtThreadIsAlive(PRTTHREADINT pThread)
488{
489 return !(pThread->fIntFlags & RTTHREADINT_FLAGS_TERMINATED);
490}
491
492
493/**
494 * Gets a thread by it's native ID.
495 *
496 * @returns pointer to the thread structure.
497 * @returns NULL if not a thread IPRT knows.
498 * @param NativeThread The native thread id.
499 */
500PRTTHREADINT rtThreadGetByNative(RTNATIVETHREAD NativeThread)
501{
502 PRTTHREADINT pThread;
503 /*
504 * Simple tree lookup.
505 */
506 RT_THREAD_LOCK_TMP(Tmp);
507 RT_THREAD_LOCK_RD(Tmp);
508 pThread = (PRTTHREADINT)RTAvlPVGet(&g_ThreadTree, (void *)NativeThread);
509 RT_THREAD_UNLOCK_RD(Tmp);
510 return pThread;
511}
512
513
514/**
515 * Gets the per thread data structure for a thread handle.
516 *
517 * @returns Pointer to the per thread data structure for Thread.
518 * The caller must release the thread using rtThreadRelease().
519 * @returns NULL if Thread was not found.
520 * @param Thread Thread id which structure is to be returned.
521 */
522PRTTHREADINT rtThreadGet(RTTHREAD Thread)
523{
524 if ( Thread != NIL_RTTHREAD
525 && VALID_PTR(Thread))
526 {
527 PRTTHREADINT pThread = (PRTTHREADINT)Thread;
528 if ( pThread->u32Magic == RTTHREADINT_MAGIC
529 && pThread->cRefs > 0)
530 {
531 ASMAtomicIncU32(&pThread->cRefs);
532 return pThread;
533 }
534 }
535
536 AssertMsgFailed(("Thread=%RTthrd\n", Thread));
537 return NULL;
538}
539
540/**
541 * Release a per thread data structure.
542 *
543 * @returns New reference count.
544 * @param pThread The thread structure to release.
545 */
546uint32_t rtThreadRelease(PRTTHREADINT pThread)
547{
548 uint32_t cRefs;
549
550 Assert(pThread);
551 if (pThread->cRefs >= 1)
552 {
553 cRefs = ASMAtomicDecU32(&pThread->cRefs);
554 if (!cRefs)
555 rtThreadDestroy(pThread);
556 }
557 else
558 {
559 cRefs = 0;
560 AssertFailed();
561 }
562 return cRefs;
563}
564
565
566/**
567 * Destroys the per thread data.
568 *
569 * @param pThread The thread to destroy.
570 */
571static void rtThreadDestroy(PRTTHREADINT pThread)
572{
573 RTSEMEVENTMULTI hEvt1, hEvt2;
574 /*
575 * Remove it from the tree and mark it as dead.
576 *
577 * Threads that has seen rtThreadTerminate and should already have been
578 * removed from the tree. There is probably no thread that should
579 * require removing here. However, be careful making sure that cRefs
580 * isn't 0 if we do or we'll blow up because the strict locking code
581 * will be calling us back.
582 */
583 if (ASMBitTest(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT))
584 {
585 ASMAtomicIncU32(&pThread->cRefs);
586 rtThreadRemove(pThread);
587 ASMAtomicDecU32(&pThread->cRefs);
588 }
589
590 /*
591 * Invalidate the thread structure.
592 */
593#ifdef IN_RING3
594 rtLockValidatorSerializeDestructEnter();
595
596 rtLockValidatorDeletePerThread(&pThread->LockValidator);
597#endif
598#ifdef RT_WITH_ICONV_CACHE
599 rtStrIconvCacheDestroy(pThread);
600#endif
601 ASMAtomicXchgU32(&pThread->u32Magic, RTTHREADINT_MAGIC_DEAD);
602 ASMAtomicWritePtr(&pThread->Core.Key, (void *)NIL_RTTHREAD);
603 pThread->enmType = RTTHREADTYPE_INVALID;
604 hEvt1 = pThread->EventUser;
605 pThread->EventUser = NIL_RTSEMEVENTMULTI;
606 hEvt2 = pThread->EventTerminated;
607 pThread->EventTerminated = NIL_RTSEMEVENTMULTI;
608
609#ifdef IN_RING3
610 rtLockValidatorSerializeDestructLeave();
611#endif
612
613 /*
614 * Destroy semaphore resources and free the bugger.
615 */
616 RTSemEventMultiDestroy(hEvt1);
617 if (hEvt2 != NIL_RTSEMEVENTMULTI)
618 RTSemEventMultiDestroy(hEvt2);
619
620 rtThreadNativeDestroy(pThread);
621 RTMemFree(pThread);
622}
623
624
625/**
626 * Terminates the thread.
627 * Called by the thread wrapper function when the thread terminates.
628 *
629 * @param pThread The thread structure.
630 * @param rc The thread result code.
631 */
632void rtThreadTerminate(PRTTHREADINT pThread, int rc)
633{
634 Assert(pThread->cRefs >= 1);
635
636#ifdef IPRT_WITH_GENERIC_TLS
637 /*
638 * Destroy TLS entries.
639 */
640 rtThreadTlsDestruction(pThread);
641#endif /* IPRT_WITH_GENERIC_TLS */
642
643 /*
644 * Set the rc, mark it terminated and signal anyone waiting.
645 */
646 pThread->rc = rc;
647 rtThreadSetState(pThread, RTTHREADSTATE_TERMINATED);
648 ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAGS_TERMINATED);
649 if (pThread->EventTerminated != NIL_RTSEMEVENTMULTI)
650 RTSemEventMultiSignal(pThread->EventTerminated);
651
652 /*
653 * Remove the thread from the tree so that there will be no
654 * key clashes in the AVL tree and release our reference to ourself.
655 */
656 rtThreadRemove(pThread);
657 rtThreadRelease(pThread);
658}
659
660
661/**
662 * The common thread main function.
663 * This is called by rtThreadNativeMain().
664 *
665 * @returns The status code of the thread.
666 * pThread is dereference by the thread before returning!
667 * @param pThread The thread structure.
668 * @param NativeThread The native thread id.
669 * @param pszThreadName The name of the thread (purely a dummy for backtrace).
670 */
671int rtThreadMain(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread, const char *pszThreadName)
672{
673 int rc;
674 NOREF(pszThreadName);
675 rtThreadInsert(pThread, NativeThread);
676 Log(("rtThreadMain: Starting: pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
677 pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
678
679 /*
680 * Change the priority.
681 */
682 rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
683#ifdef IN_RING3
684 AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d enmPriority=%d rc=%Rrc\n",
685 pThread, NativeThread, pThread->szName, pThread->enmType, g_enmProcessPriority, rc));
686#else
687 AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d rc=%Rrc\n",
688 pThread, NativeThread, pThread->szName, pThread->enmType, rc));
689#endif
690
691 /*
692 * Call thread function and terminate when it returns.
693 */
694 rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
695 rc = pThread->pfnThread(pThread, pThread->pvUser);
696
697 /*
698 * Paranoia checks for leftover resources.
699 */
700#ifdef RTSEMRW_STRICT
701 int32_t cWrite = ASMAtomicReadS32(&pThread->cWriteLocks);
702 Assert(!cWrite);
703 int32_t cRead = ASMAtomicReadS32(&pThread->cReadLocks);
704 Assert(!cRead);
705#endif
706
707 Log(("rtThreadMain: Terminating: rc=%d pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
708 rc, pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
709 rtThreadTerminate(pThread, rc);
710 return rc;
711}
712
713
714/**
715 * Create a new thread.
716 *
717 * @returns iprt status code.
718 * @param pThread Where to store the thread handle to the new thread. (optional)
719 * @param pfnThread The thread function.
720 * @param pvUser User argument.
721 * @param cbStack The size of the stack for the new thread.
722 * Use 0 for the default stack size.
723 * @param enmType The thread type. Used for deciding scheduling attributes
724 * of the thread.
725 * @param fFlags Flags of the RTTHREADFLAGS type (ORed together).
726 * @param pszName Thread name.
727 */
728RTDECL(int) RTThreadCreate(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
729 RTTHREADTYPE enmType, unsigned fFlags, const char *pszName)
730{
731 int rc;
732 PRTTHREADINT pThreadInt;
733
734 LogFlow(("RTThreadCreate: pThread=%p pfnThread=%p pvUser=%p cbStack=%#x enmType=%d fFlags=%#x pszName=%p:{%s}\n",
735 pThread, pfnThread, pvUser, cbStack, enmType, fFlags, pszName, pszName));
736
737 /*
738 * Validate input.
739 */
740 if (!VALID_PTR(pThread) && pThread)
741 {
742 Assert(VALID_PTR(pThread));
743 return VERR_INVALID_PARAMETER;
744 }
745 if (!VALID_PTR(pfnThread))
746 {
747 Assert(VALID_PTR(pfnThread));
748 return VERR_INVALID_PARAMETER;
749 }
750 if (!pszName || !*pszName || strlen(pszName) >= RTTHREAD_NAME_LEN)
751 {
752 AssertMsgFailed(("pszName=%s (max len is %d because of logging)\n", pszName, RTTHREAD_NAME_LEN - 1));
753 return VERR_INVALID_PARAMETER;
754 }
755 if (fFlags & ~RTTHREADFLAGS_MASK)
756 {
757 AssertMsgFailed(("fFlags=%#x\n", fFlags));
758 return VERR_INVALID_PARAMETER;
759 }
760
761 /*
762 * Allocate thread argument.
763 */
764 pThreadInt = rtThreadAlloc(enmType, fFlags, 0, pszName);
765 if (pThreadInt)
766 {
767 RTNATIVETHREAD NativeThread;
768
769 pThreadInt->pfnThread = pfnThread;
770 pThreadInt->pvUser = pvUser;
771 pThreadInt->cbStack = cbStack;
772
773 rc = rtThreadNativeCreate(pThreadInt, &NativeThread);
774 if (RT_SUCCESS(rc))
775 {
776 rtThreadInsert(pThreadInt, NativeThread);
777 rtThreadRelease(pThreadInt);
778 Log(("RTThreadCreate: Created thread %p (%p) %s\n", pThreadInt, NativeThread, pszName));
779 if (pThread)
780 *pThread = pThreadInt;
781 return VINF_SUCCESS;
782 }
783
784 pThreadInt->cRefs = 1;
785 rtThreadRelease(pThreadInt);
786 }
787 else
788 rc = VERR_NO_TMP_MEMORY;
789 LogFlow(("RTThreadCreate: Failed to create thread, rc=%Rrc\n", rc));
790 AssertReleaseRC(rc);
791 return rc;
792}
793RT_EXPORT_SYMBOL(RTThreadCreate);
794
795
796/**
797 * Create a new thread.
798 *
799 * Same as RTThreadCreate except the name is given in the RTStrPrintfV 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 va Format arguments.
810 */
811RTDECL(int) RTThreadCreateV(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
812 RTTHREADTYPE enmType, uint32_t fFlags, const char *pszNameFmt, va_list va)
813{
814 char szName[RTTHREAD_NAME_LEN * 2];
815 RTStrPrintfV(szName, sizeof(szName), pszNameFmt, va);
816 return RTThreadCreate(pThread, pfnThread, pvUser, cbStack, enmType, fFlags, szName);
817}
818RT_EXPORT_SYMBOL(RTThreadCreateV);
819
820
821/**
822 * Create a new thread.
823 *
824 * Same as RTThreadCreate except the name is given in the RTStrPrintf form.
825 *
826 * @returns iprt status code.
827 * @param pThread See RTThreadCreate.
828 * @param pfnThread See RTThreadCreate.
829 * @param pvUser See RTThreadCreate.
830 * @param cbStack See RTThreadCreate.
831 * @param enmType See RTThreadCreate.
832 * @param fFlags See RTThreadCreate.
833 * @param pszNameFmt Thread name format.
834 * @param ... Format arguments.
835 */
836RTDECL(int) RTThreadCreateF(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
837 RTTHREADTYPE enmType, uint32_t fFlags, const char *pszNameFmt, ...)
838{
839 va_list va;
840 int rc;
841 va_start(va, pszNameFmt);
842 rc = RTThreadCreateV(pThread, pfnThread, pvUser, cbStack, enmType, fFlags, pszNameFmt, va);
843 va_end(va);
844 return rc;
845}
846RT_EXPORT_SYMBOL(RTThreadCreateF);
847
848
849/**
850 * Gets the native thread id of a IPRT thread.
851 *
852 * @returns The native thread id.
853 * @param Thread The IPRT thread.
854 */
855RTDECL(RTNATIVETHREAD) RTThreadGetNative(RTTHREAD Thread)
856{
857 PRTTHREADINT pThread = rtThreadGet(Thread);
858 if (pThread)
859 {
860 RTNATIVETHREAD NativeThread = (RTNATIVETHREAD)pThread->Core.Key;
861 rtThreadRelease(pThread);
862 return NativeThread;
863 }
864 return NIL_RTNATIVETHREAD;
865}
866RT_EXPORT_SYMBOL(RTThreadGetNative);
867
868
869/**
870 * Gets the IPRT thread of a native thread.
871 *
872 * @returns The IPRT thread handle
873 * @returns NIL_RTTHREAD if not a thread known to IPRT.
874 * @param NativeThread The native thread handle/id.
875 */
876RTDECL(RTTHREAD) RTThreadFromNative(RTNATIVETHREAD NativeThread)
877{
878 PRTTHREADINT pThread = rtThreadGetByNative(NativeThread);
879 if (pThread)
880 return pThread;
881 return NIL_RTTHREAD;
882}
883RT_EXPORT_SYMBOL(RTThreadFromNative);
884
885
886/**
887 * Gets the name of the current thread thread.
888 *
889 * @returns Pointer to readonly name string.
890 * @returns NULL on failure.
891 */
892RTDECL(const char *) RTThreadSelfName(void)
893{
894 RTTHREAD Thread = RTThreadSelf();
895 if (Thread != NIL_RTTHREAD)
896 {
897 PRTTHREADINT pThread = rtThreadGet(Thread);
898 if (pThread)
899 {
900 const char *szName = pThread->szName;
901 rtThreadRelease(pThread);
902 return szName;
903 }
904 }
905 return NULL;
906}
907RT_EXPORT_SYMBOL(RTThreadSelfName);
908
909
910/**
911 * Gets the name of a thread.
912 *
913 * @returns Pointer to readonly name string.
914 * @returns NULL on failure.
915 * @param Thread Thread handle of the thread to query the name of.
916 */
917RTDECL(const char *) RTThreadGetName(RTTHREAD Thread)
918{
919 PRTTHREADINT pThread;
920 if (Thread == NIL_RTTHREAD)
921 return NULL;
922 pThread = rtThreadGet(Thread);
923 if (pThread)
924 {
925 const char *szName = pThread->szName;
926 rtThreadRelease(pThread);
927 return szName;
928 }
929 return NULL;
930}
931RT_EXPORT_SYMBOL(RTThreadGetName);
932
933
934/**
935 * Sets the name of a thread.
936 *
937 * @returns iprt status code.
938 * @param Thread Thread handle of the thread to query the name of.
939 * @param pszName The thread name.
940 */
941RTDECL(int) RTThreadSetName(RTTHREAD Thread, const char *pszName)
942{
943 /*
944 * Validate input.
945 */
946 PRTTHREADINT pThread;
947 size_t cchName = strlen(pszName);
948 if (cchName >= RTTHREAD_NAME_LEN)
949 {
950 AssertMsgFailed(("pszName=%s is too long, max is %d\n", pszName, RTTHREAD_NAME_LEN - 1));
951 return VERR_INVALID_PARAMETER;
952 }
953 pThread = rtThreadGet(Thread);
954 if (!pThread)
955 return VERR_INVALID_HANDLE;
956
957 /*
958 * Update the name.
959 */
960 pThread->szName[cchName] = '\0'; /* paranoia */
961 memcpy(pThread->szName, pszName, cchName);
962 rtThreadRelease(pThread);
963 return VINF_SUCCESS;
964}
965RT_EXPORT_SYMBOL(RTThreadSetName);
966
967
968/**
969 * Checks if the specified thread is the main thread.
970 *
971 * @returns true if it is, false if it isn't.
972 *
973 * @param hThread The thread handle.
974 *
975 * @remarks This function may not return the correct value when RTR3Init was
976 * called on a thread of the than the main one. This could for
977 * instance happen when the DLL/DYLIB/SO containing IPRT is dynamically
978 * loaded at run time by a different thread.
979 */
980RTDECL(bool) RTThreadIsMain(RTTHREAD hThread)
981{
982 PRTTHREADINT pThread = rtThreadGet(hThread);
983 if (pThread)
984 {
985 bool fRc = !!(pThread->fIntFlags & RTTHREADINT_FLAGS_MAIN);
986 rtThreadRelease(pThread);
987 return fRc;
988 }
989 return false;
990}
991RT_EXPORT_SYMBOL(RTThreadIsMain);
992
993
994/**
995 * Signal the user event.
996 *
997 * @returns iprt status code.
998 */
999RTDECL(int) RTThreadUserSignal(RTTHREAD Thread)
1000{
1001 int rc;
1002 PRTTHREADINT pThread = rtThreadGet(Thread);
1003 if (pThread)
1004 {
1005 rc = RTSemEventMultiSignal(pThread->EventUser);
1006 rtThreadRelease(pThread);
1007 }
1008 else
1009 rc = VERR_INVALID_HANDLE;
1010 return rc;
1011}
1012RT_EXPORT_SYMBOL(RTThreadUserSignal);
1013
1014
1015/**
1016 * Wait for the user event, resume on interruption.
1017 *
1018 * @returns iprt status code.
1019 * @param Thread The thread to wait for.
1020 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1021 * an indefinite wait.
1022 */
1023RTDECL(int) RTThreadUserWait(RTTHREAD Thread, RTMSINTERVAL cMillies)
1024{
1025 int rc;
1026 PRTTHREADINT pThread = rtThreadGet(Thread);
1027 if (pThread)
1028 {
1029 rc = RTSemEventMultiWait(pThread->EventUser, cMillies);
1030 rtThreadRelease(pThread);
1031 }
1032 else
1033 rc = VERR_INVALID_HANDLE;
1034 return rc;
1035}
1036RT_EXPORT_SYMBOL(RTThreadUserWait);
1037
1038
1039/**
1040 * Wait for the user event, return on interruption.
1041 *
1042 * @returns iprt status code.
1043 * @param Thread The thread to wait for.
1044 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1045 * an indefinite wait.
1046 */
1047RTDECL(int) RTThreadUserWaitNoResume(RTTHREAD Thread, RTMSINTERVAL cMillies)
1048{
1049 int rc;
1050 PRTTHREADINT pThread = rtThreadGet(Thread);
1051 if (pThread)
1052 {
1053 rc = RTSemEventMultiWaitNoResume(pThread->EventUser, cMillies);
1054 rtThreadRelease(pThread);
1055 }
1056 else
1057 rc = VERR_INVALID_HANDLE;
1058 return rc;
1059}
1060RT_EXPORT_SYMBOL(RTThreadUserWaitNoResume);
1061
1062
1063/**
1064 * Reset the user event.
1065 *
1066 * @returns iprt status code.
1067 * @param Thread The thread to reset.
1068 */
1069RTDECL(int) RTThreadUserReset(RTTHREAD Thread)
1070{
1071 int rc;
1072 PRTTHREADINT pThread = rtThreadGet(Thread);
1073 if (pThread)
1074 {
1075 rc = RTSemEventMultiReset(pThread->EventUser);
1076 rtThreadRelease(pThread);
1077 }
1078 else
1079 rc = VERR_INVALID_HANDLE;
1080 return rc;
1081}
1082RT_EXPORT_SYMBOL(RTThreadUserReset);
1083
1084
1085/**
1086 * Wait for the thread to terminate.
1087 *
1088 * @returns iprt status code.
1089 * @param Thread The thread to wait for.
1090 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1091 * an indefinite wait.
1092 * @param prc Where to store the return code of the thread. Optional.
1093 * @param fAutoResume Whether or not to resume the wait on VERR_INTERRUPTED.
1094 */
1095static int rtThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc, bool fAutoResume)
1096{
1097 int rc = VERR_INVALID_HANDLE;
1098 if (Thread != NIL_RTTHREAD)
1099 {
1100 PRTTHREADINT pThread = rtThreadGet(Thread);
1101 if (pThread)
1102 {
1103 if (pThread->fFlags & RTTHREADFLAGS_WAITABLE)
1104 {
1105 if (fAutoResume)
1106 rc = RTSemEventMultiWait(pThread->EventTerminated, cMillies);
1107 else
1108 rc = RTSemEventMultiWaitNoResume(pThread->EventTerminated, cMillies);
1109 if (RT_SUCCESS(rc))
1110 {
1111 if (prc)
1112 *prc = pThread->rc;
1113
1114 /*
1115 * If the thread is marked as waitable, we'll do one additional
1116 * release in order to free up the thread structure (see how we
1117 * init cRef in rtThreadAlloc()).
1118 */
1119 if (ASMAtomicBitTestAndClear(&pThread->fFlags, RTTHREADFLAGS_WAITABLE_BIT))
1120 rtThreadRelease(pThread);
1121 }
1122 }
1123 else
1124 {
1125 rc = VERR_THREAD_NOT_WAITABLE;
1126 AssertRC(rc);
1127 }
1128 rtThreadRelease(pThread);
1129 }
1130 }
1131 return rc;
1132}
1133
1134
1135/**
1136 * Wait for the thread to terminate, resume on interruption.
1137 *
1138 * @returns iprt status code.
1139 * Will not return VERR_INTERRUPTED.
1140 * @param Thread The thread to wait for.
1141 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1142 * an indefinite wait.
1143 * @param prc Where to store the return code of the thread. Optional.
1144 */
1145RTDECL(int) RTThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc)
1146{
1147 int rc = rtThreadWait(Thread, cMillies, prc, true);
1148 Assert(rc != VERR_INTERRUPTED);
1149 return rc;
1150}
1151RT_EXPORT_SYMBOL(RTThreadWait);
1152
1153
1154/**
1155 * Wait for the thread to terminate, return on interruption.
1156 *
1157 * @returns iprt status code.
1158 * @param Thread The thread to wait for.
1159 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1160 * an indefinite wait.
1161 * @param prc Where to store the return code of the thread. Optional.
1162 */
1163RTDECL(int) RTThreadWaitNoResume(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc)
1164{
1165 return rtThreadWait(Thread, cMillies, prc, false);
1166}
1167RT_EXPORT_SYMBOL(RTThreadWaitNoResume);
1168
1169
1170/**
1171 * Changes the type of the specified thread.
1172 *
1173 * @returns iprt status code.
1174 * @param Thread The thread which type should be changed.
1175 * @param enmType The new thread type.
1176 */
1177RTDECL(int) RTThreadSetType(RTTHREAD Thread, RTTHREADTYPE enmType)
1178{
1179 /*
1180 * Validate input.
1181 */
1182 int rc;
1183 if ( enmType > RTTHREADTYPE_INVALID
1184 && enmType < RTTHREADTYPE_END)
1185 {
1186 PRTTHREADINT pThread = rtThreadGet(Thread);
1187 if (pThread)
1188 {
1189 if (rtThreadIsAlive(pThread))
1190 {
1191 /*
1192 * Do the job.
1193 */
1194 RT_THREAD_LOCK_TMP(Tmp);
1195 RT_THREAD_LOCK_RW(Tmp);
1196 rc = rtThreadNativeSetPriority(pThread, enmType);
1197 if (RT_SUCCESS(rc))
1198 ASMAtomicXchgSize(&pThread->enmType, enmType);
1199 RT_THREAD_UNLOCK_RW(Tmp);
1200 if (RT_FAILURE(rc))
1201 Log(("RTThreadSetType: failed on thread %p (%s), rc=%Rrc!!!\n", Thread, pThread->szName, rc));
1202 }
1203 else
1204 rc = VERR_THREAD_IS_DEAD;
1205 rtThreadRelease(pThread);
1206 }
1207 else
1208 rc = VERR_INVALID_HANDLE;
1209 }
1210 else
1211 {
1212 AssertMsgFailed(("enmType=%d\n", enmType));
1213 rc = VERR_INVALID_PARAMETER;
1214 }
1215 return rc;
1216}
1217RT_EXPORT_SYMBOL(RTThreadSetType);
1218
1219
1220/**
1221 * Gets the type of the specified thread.
1222 *
1223 * @returns The thread type.
1224 * @returns RTTHREADTYPE_INVALID if the thread handle is invalid.
1225 * @param Thread The thread in question.
1226 */
1227RTDECL(RTTHREADTYPE) RTThreadGetType(RTTHREAD Thread)
1228{
1229 RTTHREADTYPE enmType = RTTHREADTYPE_INVALID;
1230 PRTTHREADINT pThread = rtThreadGet(Thread);
1231 if (pThread)
1232 {
1233 enmType = pThread->enmType;
1234 rtThreadRelease(pThread);
1235 }
1236 return enmType;
1237}
1238RT_EXPORT_SYMBOL(RTThreadGetType);
1239
1240#ifdef IN_RING3
1241
1242/**
1243 * Recalculates scheduling attributes for the default process
1244 * priority using the specified priority type for the calling thread.
1245 *
1246 * The scheduling attributes are targeted at threads and they are protected
1247 * by the thread read-write semaphore, that's why RTProc is forwarding the
1248 * operation to RTThread.
1249 *
1250 * @returns iprt status code.
1251 * @remarks Will only work for strict builds.
1252 */
1253int rtThreadDoCalcDefaultPriority(RTTHREADTYPE enmType)
1254{
1255 RT_THREAD_LOCK_TMP(Tmp);
1256 RT_THREAD_LOCK_RW(Tmp);
1257 int rc = rtSchedNativeCalcDefaultPriority(enmType);
1258 RT_THREAD_UNLOCK_RW(Tmp);
1259 return rc;
1260}
1261
1262
1263/**
1264 * Thread enumerator - sets the priority of one thread.
1265 *
1266 * @returns 0 to continue.
1267 * @returns !0 to stop. In our case a VERR_ code.
1268 * @param pNode The thread node.
1269 * @param pvUser The new priority.
1270 */
1271static DECLCALLBACK(int) rtThreadSetPriorityOne(PAVLPVNODECORE pNode, void *pvUser)
1272{
1273 PRTTHREADINT pThread = (PRTTHREADINT)pNode;
1274 if (!rtThreadIsAlive(pThread))
1275 return VINF_SUCCESS;
1276 int rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
1277 if (RT_SUCCESS(rc)) /* hide any warnings */
1278 return VINF_SUCCESS;
1279 return rc;
1280}
1281
1282
1283/**
1284 * Attempts to alter the priority of the current process.
1285 *
1286 * The scheduling attributes are targeted at threads and they are protected
1287 * by the thread read-write semaphore, that's why RTProc is forwarding the
1288 * operation to RTThread. This operation also involves updating all thread
1289 * which is much faster done from RTThread.
1290 *
1291 * @returns iprt status code.
1292 * @param enmPriority The new priority.
1293 */
1294int rtThreadDoSetProcPriority(RTPROCPRIORITY enmPriority)
1295{
1296 LogFlow(("rtThreadDoSetProcPriority: enmPriority=%d\n", enmPriority));
1297
1298 /*
1299 * First validate that we're allowed by the OS to use all the
1300 * scheduling attributes defined by the specified process priority.
1301 */
1302 RT_THREAD_LOCK_TMP(Tmp);
1303 RT_THREAD_LOCK_RW(Tmp);
1304 int rc = rtProcNativeSetPriority(enmPriority);
1305 if (RT_SUCCESS(rc))
1306 {
1307 /*
1308 * Update the priority of existing thread.
1309 */
1310 rc = RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
1311 if (RT_SUCCESS(rc))
1312 ASMAtomicXchgSize(&g_enmProcessPriority, enmPriority);
1313 else
1314 {
1315 /*
1316 * Failed, restore the priority.
1317 */
1318 rtProcNativeSetPriority(g_enmProcessPriority);
1319 RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
1320 }
1321 }
1322 RT_THREAD_UNLOCK_RW(Tmp);
1323 LogFlow(("rtThreadDoSetProcPriority: returns %Rrc\n", rc));
1324 return rc;
1325}
1326
1327
1328/**
1329 * Change the thread state to blocking.
1330 *
1331 * @param hThread The current thread.
1332 * @param enmState The sleep state.
1333 * @param fReallySleeping Really going to sleep now.
1334 */
1335RTDECL(void) RTThreadBlocking(RTTHREAD hThread, RTTHREADSTATE enmState, bool fReallySleeping)
1336{
1337 Assert(RTTHREAD_IS_SLEEPING(enmState));
1338 PRTTHREADINT pThread = hThread;
1339 if (pThread != NIL_RTTHREAD)
1340 {
1341 Assert(pThread == RTThreadSelf());
1342 if (rtThreadGetState(pThread) == RTTHREADSTATE_RUNNING)
1343 rtThreadSetState(pThread, enmState);
1344 ASMAtomicWriteBool(&pThread->fReallySleeping, fReallySleeping);
1345 }
1346}
1347RT_EXPORT_SYMBOL(RTThreadBlocking);
1348
1349
1350/**
1351 * Unblocks a thread.
1352 *
1353 * This function is paired with rtThreadBlocking.
1354 *
1355 * @param hThread The current thread.
1356 * @param enmCurState The current state, used to check for nested blocking.
1357 * The new state will be running.
1358 */
1359RTDECL(void) RTThreadUnblocked(RTTHREAD hThread, RTTHREADSTATE enmCurState)
1360{
1361 PRTTHREADINT pThread = hThread;
1362 if (pThread != NIL_RTTHREAD)
1363 {
1364 Assert(pThread == RTThreadSelf());
1365 ASMAtomicWriteBool(&pThread->fReallySleeping, false);
1366
1367 RTTHREADSTATE enmActualState = rtThreadGetState(pThread);
1368 if (enmActualState == enmCurState)
1369 {
1370 rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
1371 if ( pThread->LockValidator.pRec
1372 && pThread->LockValidator.enmRecState == enmCurState)
1373 ASMAtomicWriteNullPtr(&pThread->LockValidator.pRec);
1374 }
1375 /* This is a bit ugly... :-/ */
1376 else if ( ( enmActualState == RTTHREADSTATE_TERMINATED
1377 || enmActualState == RTTHREADSTATE_INITIALIZING)
1378 && pThread->LockValidator.pRec)
1379 ASMAtomicWriteNullPtr(&pThread->LockValidator.pRec);
1380 Assert( pThread->LockValidator.pRec == NULL
1381 || RTTHREAD_IS_SLEEPING(enmActualState));
1382 }
1383}
1384RT_EXPORT_SYMBOL(RTThreadUnblocked);
1385
1386
1387/**
1388 * Get the current thread state.
1389 *
1390 * @returns The thread state.
1391 * @param hThread The thread.
1392 */
1393RTDECL(RTTHREADSTATE) RTThreadGetState(RTTHREAD hThread)
1394{
1395 RTTHREADSTATE enmState = RTTHREADSTATE_INVALID;
1396 PRTTHREADINT pThread = rtThreadGet(hThread);
1397 if (pThread)
1398 {
1399 enmState = rtThreadGetState(pThread);
1400 rtThreadRelease(pThread);
1401 }
1402 return enmState;
1403}
1404RT_EXPORT_SYMBOL(RTThreadGetState);
1405
1406
1407RTDECL(RTTHREADSTATE) RTThreadGetReallySleeping(RTTHREAD hThread)
1408{
1409 RTTHREADSTATE enmState = RTTHREADSTATE_INVALID;
1410 PRTTHREADINT pThread = rtThreadGet(hThread);
1411 if (pThread)
1412 {
1413 enmState = rtThreadGetState(pThread);
1414 if (!ASMAtomicUoReadBool(&pThread->fReallySleeping))
1415 enmState = RTTHREADSTATE_RUNNING;
1416 rtThreadRelease(pThread);
1417 }
1418 return enmState;
1419}
1420RT_EXPORT_SYMBOL(RTThreadGetReallySleeping);
1421
1422
1423/**
1424 * Translate a thread state into a string.
1425 *
1426 * @returns Pointer to a read-only string containing the state name.
1427 * @param enmState The state.
1428 */
1429RTDECL(const char *) RTThreadStateName(RTTHREADSTATE enmState)
1430{
1431 switch (enmState)
1432 {
1433 case RTTHREADSTATE_INVALID: return "INVALID";
1434 case RTTHREADSTATE_INITIALIZING: return "INITIALIZING";
1435 case RTTHREADSTATE_TERMINATED: return "TERMINATED";
1436 case RTTHREADSTATE_RUNNING: return "RUNNING";
1437 case RTTHREADSTATE_CRITSECT: return "CRITSECT";
1438 case RTTHREADSTATE_EVENT: return "EVENT";
1439 case RTTHREADSTATE_EVENT_MULTI: return "EVENT_MULTI";
1440 case RTTHREADSTATE_FAST_MUTEX: return "FAST_MUTEX";
1441 case RTTHREADSTATE_MUTEX: return "MUTEX";
1442 case RTTHREADSTATE_RW_READ: return "RW_READ";
1443 case RTTHREADSTATE_RW_WRITE: return "RW_WRITE";
1444 case RTTHREADSTATE_SLEEP: return "SLEEP";
1445 case RTTHREADSTATE_SPIN_MUTEX: return "SPIN_MUTEX";
1446 default: return "UnknownThreadState";
1447 }
1448}
1449RT_EXPORT_SYMBOL(RTThreadStateName);
1450
1451#endif /* IN_RING3 */
1452#ifdef IPRT_WITH_GENERIC_TLS
1453
1454/**
1455 * Thread enumerator - clears a TLS entry.
1456 *
1457 * @returns 0.
1458 * @param pNode The thread node.
1459 * @param pvUser The TLS index.
1460 */
1461static DECLCALLBACK(int) rtThreadClearTlsEntryCallback(PAVLPVNODECORE pNode, void *pvUser)
1462{
1463 PRTTHREADINT pThread = (PRTTHREADINT)pNode;
1464 RTTLS iTls = (RTTLS)(uintptr_t)pvUser;
1465 ASMAtomicWriteNullPtr(&pThread->apvTlsEntries[iTls]);
1466 return 0;
1467}
1468
1469
1470/**
1471 * Helper for the generic TLS implementation that clears a given TLS
1472 * entry on all threads.
1473 *
1474 * @param iTls The TLS entry. (valid)
1475 */
1476void rtThreadClearTlsEntry(RTTLS iTls)
1477{
1478 RT_THREAD_LOCK_TMP(Tmp);
1479 RT_THREAD_LOCK_RD(Tmp);
1480 RTAvlPVDoWithAll(&g_ThreadTree, true /* fFromLeft*/, rtThreadClearTlsEntryCallback, (void *)(uintptr_t)iTls);
1481 RT_THREAD_UNLOCK_RD(Tmp);
1482}
1483
1484#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