VirtualBox

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

Last change on this file since 50795 was 48935, checked in by vboxsync, 11 years ago

Runtime: Whitespace and svn:keyword cleanups by scm.

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