VirtualBox

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

Last change on this file since 78052 was 77982, checked in by vboxsync, 6 years ago

IPRT: Addressed todo in rtSchedNativeCheckThreadTypes (sched-linux.cpp) about limiting the transition checking to thread types that are actually in use. bugref:7929

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