VirtualBox

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

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

iprt/lockvaldiator,++: owner record management and some other stuff. Disabled lock strictness for everyeone but me.

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