VirtualBox

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

Last change on this file since 45221 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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