VirtualBox

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

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

iprt/thread.h: Added RTThreadIsInitialized, RTThreadIsSelfKnown and RTThreadIsSelfAlive.

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

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