VirtualBox

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

Last change on this file since 37596 was 36951, checked in by vboxsync, 13 years ago

warnings

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