VirtualBox

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

Last change on this file since 85124 was 85124, checked in by vboxsync, 4 years ago

*: Use DECL_HIDDEN_DATA for data, DECLHIDDEN will soon be exclusively for functions. bugref:9794

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 49.3 KB
Line 
1/* $Id: thread.cpp 85124 2020-07-08 21:13:30Z vboxsync $ */
2/** @file
3 * IPRT - Threads, common routines.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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. */
89DECL_HIDDEN_DATA(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 /*
667 * Destroy TLS entries.
668 */
669#ifdef IPRT_WITH_GENERIC_TLS
670 rtThreadTlsDestruction(pThread);
671#elif defined(RT_OS_WINDOWS) && defined(IN_RING3)
672 rtThreadWinTlsDestruction();
673#endif
674
675 /*
676 * Set the rc, mark it terminated and signal anyone waiting.
677 */
678 pThread->rc = rc;
679 rtThreadSetState(pThread, RTTHREADSTATE_TERMINATED);
680 ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAGS_TERMINATED);
681 if (pThread->EventTerminated != NIL_RTSEMEVENTMULTI)
682 RTSemEventMultiSignal(pThread->EventTerminated);
683
684 /*
685 * Remove the thread from the tree so that there will be no
686 * key clashes in the AVL tree and release our reference to ourself.
687 */
688 rtThreadRemove(pThread);
689 rtThreadRelease(pThread);
690}
691
692
693/**
694 * The common thread main function.
695 * This is called by rtThreadNativeMain().
696 *
697 * @returns The status code of the thread.
698 * pThread is dereference by the thread before returning!
699 * @param pThread The thread structure.
700 * @param NativeThread The native thread id.
701 * @param pszThreadName The name of the thread (purely a dummy for backtrace).
702 */
703DECLCALLBACK(DECLHIDDEN(int)) rtThreadMain(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread, const char *pszThreadName)
704{
705 int rc;
706 NOREF(pszThreadName);
707 rtThreadInsert(pThread, NativeThread);
708 Log(("rtThreadMain: Starting: pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
709 pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
710
711 /*
712 * Change the priority.
713 */
714 rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
715#ifdef IN_RING3
716 AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d enmPriority=%d rc=%Rrc\n",
717 pThread, NativeThread, pThread->szName, pThread->enmType, g_enmProcessPriority, rc));
718#else
719 AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d rc=%Rrc\n",
720 pThread, NativeThread, pThread->szName, pThread->enmType, rc));
721#endif
722
723 /*
724 * Call thread function and terminate when it returns.
725 */
726 rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
727 rc = pThread->pfnThread(pThread, pThread->pvUser);
728
729 /*
730 * Paranoia checks for leftover resources.
731 */
732#ifdef RTSEMRW_STRICT
733 int32_t cWrite = ASMAtomicReadS32(&pThread->cWriteLocks);
734 Assert(!cWrite);
735 int32_t cRead = ASMAtomicReadS32(&pThread->cReadLocks);
736 Assert(!cRead);
737#endif
738
739 Log(("rtThreadMain: Terminating: rc=%d pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
740 rc, pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
741 rtThreadTerminate(pThread, rc);
742 return rc;
743}
744
745
746/**
747 * Create a new thread.
748 *
749 * @returns iprt status code.
750 * @param pThread Where to store the thread handle to the new thread. (optional)
751 * @param pfnThread The thread function.
752 * @param pvUser User argument.
753 * @param cbStack The size of the stack for the new thread.
754 * Use 0 for the default stack size.
755 * @param enmType The thread type. Used for deciding scheduling attributes
756 * of the thread.
757 * @param fFlags Flags of the RTTHREADFLAGS type (ORed together).
758 * @param pszName Thread name.
759 */
760RTDECL(int) RTThreadCreate(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
761 RTTHREADTYPE enmType, unsigned fFlags, const char *pszName)
762{
763 int rc;
764 PRTTHREADINT pThreadInt;
765
766 LogFlow(("RTThreadCreate: pThread=%p pfnThread=%p pvUser=%p cbStack=%#x enmType=%d fFlags=%#x pszName=%p:{%s}\n",
767 pThread, pfnThread, pvUser, cbStack, enmType, fFlags, pszName, pszName));
768
769 /*
770 * Validate input.
771 */
772 if (!VALID_PTR(pThread) && pThread)
773 {
774 Assert(VALID_PTR(pThread));
775 return VERR_INVALID_PARAMETER;
776 }
777 if (!VALID_PTR(pfnThread))
778 {
779 Assert(VALID_PTR(pfnThread));
780 return VERR_INVALID_PARAMETER;
781 }
782 if (!pszName || !*pszName || strlen(pszName) >= RTTHREAD_NAME_LEN)
783 {
784 AssertMsgFailed(("pszName=%s (max len is %d because of logging)\n", pszName, RTTHREAD_NAME_LEN - 1));
785 return VERR_INVALID_PARAMETER;
786 }
787 if (fFlags & ~RTTHREADFLAGS_MASK)
788 {
789 AssertMsgFailed(("fFlags=%#x\n", fFlags));
790 return VERR_INVALID_PARAMETER;
791 }
792
793 /*
794 * Allocate thread argument.
795 */
796 pThreadInt = rtThreadAlloc(enmType, fFlags, 0, pszName);
797 if (pThreadInt)
798 {
799 RTNATIVETHREAD NativeThread;
800
801 pThreadInt->pfnThread = pfnThread;
802 pThreadInt->pvUser = pvUser;
803 pThreadInt->cbStack = cbStack;
804
805 rc = rtThreadNativeCreate(pThreadInt, &NativeThread);
806 if (RT_SUCCESS(rc))
807 {
808 rtThreadInsert(pThreadInt, NativeThread);
809 rtThreadRelease(pThreadInt);
810 Log(("RTThreadCreate: Created thread %p (%p) %s\n", pThreadInt, NativeThread, pszName));
811 if (pThread)
812 *pThread = pThreadInt;
813 return VINF_SUCCESS;
814 }
815
816 pThreadInt->cRefs = 1;
817 rtThreadRelease(pThreadInt);
818 }
819 else
820 rc = VERR_NO_TMP_MEMORY;
821 LogFlow(("RTThreadCreate: Failed to create thread, rc=%Rrc\n", rc));
822 AssertReleaseRC(rc);
823 return rc;
824}
825RT_EXPORT_SYMBOL(RTThreadCreate);
826
827
828/**
829 * Create a new thread.
830 *
831 * Same as RTThreadCreate except the name is given in the RTStrPrintfV form.
832 *
833 * @returns iprt status code.
834 * @param pThread See RTThreadCreate.
835 * @param pfnThread See RTThreadCreate.
836 * @param pvUser See RTThreadCreate.
837 * @param cbStack See RTThreadCreate.
838 * @param enmType See RTThreadCreate.
839 * @param fFlags See RTThreadCreate.
840 * @param pszNameFmt Thread name format.
841 * @param va Format arguments.
842 */
843RTDECL(int) RTThreadCreateV(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
844 RTTHREADTYPE enmType, uint32_t fFlags, const char *pszNameFmt, va_list va)
845{
846 char szName[RTTHREAD_NAME_LEN * 2];
847 RTStrPrintfV(szName, sizeof(szName), pszNameFmt, va);
848 return RTThreadCreate(pThread, pfnThread, pvUser, cbStack, enmType, fFlags, szName);
849}
850RT_EXPORT_SYMBOL(RTThreadCreateV);
851
852
853/**
854 * Create a new thread.
855 *
856 * Same as RTThreadCreate except the name is given in the RTStrPrintf form.
857 *
858 * @returns iprt status code.
859 * @param pThread See RTThreadCreate.
860 * @param pfnThread See RTThreadCreate.
861 * @param pvUser See RTThreadCreate.
862 * @param cbStack See RTThreadCreate.
863 * @param enmType See RTThreadCreate.
864 * @param fFlags See RTThreadCreate.
865 * @param pszNameFmt Thread name format.
866 * @param ... Format arguments.
867 */
868RTDECL(int) RTThreadCreateF(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
869 RTTHREADTYPE enmType, uint32_t fFlags, const char *pszNameFmt, ...)
870{
871 va_list va;
872 int rc;
873 va_start(va, pszNameFmt);
874 rc = RTThreadCreateV(pThread, pfnThread, pvUser, cbStack, enmType, fFlags, pszNameFmt, va);
875 va_end(va);
876 return rc;
877}
878RT_EXPORT_SYMBOL(RTThreadCreateF);
879
880
881/**
882 * Gets the native thread id of a IPRT thread.
883 *
884 * @returns The native thread id.
885 * @param Thread The IPRT thread.
886 */
887RTDECL(RTNATIVETHREAD) RTThreadGetNative(RTTHREAD Thread)
888{
889 PRTTHREADINT pThread = rtThreadGet(Thread);
890 if (pThread)
891 {
892 RTNATIVETHREAD NativeThread = (RTNATIVETHREAD)pThread->Core.Key;
893 rtThreadRelease(pThread);
894 return NativeThread;
895 }
896 return NIL_RTNATIVETHREAD;
897}
898RT_EXPORT_SYMBOL(RTThreadGetNative);
899
900
901/**
902 * Gets the IPRT thread of a native thread.
903 *
904 * @returns The IPRT thread handle
905 * @returns NIL_RTTHREAD if not a thread known to IPRT.
906 * @param NativeThread The native thread handle/id.
907 */
908RTDECL(RTTHREAD) RTThreadFromNative(RTNATIVETHREAD NativeThread)
909{
910 PRTTHREADINT pThread = rtThreadGetByNative(NativeThread);
911 if (pThread)
912 return pThread;
913 return NIL_RTTHREAD;
914}
915RT_EXPORT_SYMBOL(RTThreadFromNative);
916
917
918/**
919 * Gets the name of the current thread thread.
920 *
921 * @returns Pointer to readonly name string.
922 * @returns NULL on failure.
923 */
924RTDECL(const char *) RTThreadSelfName(void)
925{
926 RTTHREAD Thread = RTThreadSelf();
927 if (Thread != NIL_RTTHREAD)
928 {
929 PRTTHREADINT pThread = rtThreadGet(Thread);
930 if (pThread)
931 {
932 const char *szName = pThread->szName;
933 rtThreadRelease(pThread);
934 return szName;
935 }
936 }
937 return NULL;
938}
939RT_EXPORT_SYMBOL(RTThreadSelfName);
940
941
942/**
943 * Gets the name of a thread.
944 *
945 * @returns Pointer to readonly name string.
946 * @returns NULL on failure.
947 * @param Thread Thread handle of the thread to query the name of.
948 */
949RTDECL(const char *) RTThreadGetName(RTTHREAD Thread)
950{
951 PRTTHREADINT pThread;
952 if (Thread == NIL_RTTHREAD)
953 return NULL;
954 pThread = rtThreadGet(Thread);
955 if (pThread)
956 {
957 const char *szName = pThread->szName;
958 rtThreadRelease(pThread);
959 return szName;
960 }
961 return NULL;
962}
963RT_EXPORT_SYMBOL(RTThreadGetName);
964
965
966/**
967 * Sets the name of a thread.
968 *
969 * @returns iprt status code.
970 * @param Thread Thread handle of the thread to query the name of.
971 * @param pszName The thread name.
972 */
973RTDECL(int) RTThreadSetName(RTTHREAD Thread, const char *pszName)
974{
975 /*
976 * Validate input.
977 */
978 PRTTHREADINT pThread;
979 size_t cchName = strlen(pszName);
980 if (cchName >= RTTHREAD_NAME_LEN)
981 {
982 AssertMsgFailed(("pszName=%s is too long, max is %d\n", pszName, RTTHREAD_NAME_LEN - 1));
983 return VERR_INVALID_PARAMETER;
984 }
985 pThread = rtThreadGet(Thread);
986 if (!pThread)
987 return VERR_INVALID_HANDLE;
988
989 /*
990 * Update the name.
991 */
992 pThread->szName[cchName] = '\0'; /* paranoia */
993 memcpy(pThread->szName, pszName, cchName);
994 rtThreadRelease(pThread);
995 return VINF_SUCCESS;
996}
997RT_EXPORT_SYMBOL(RTThreadSetName);
998
999
1000/**
1001 * Checks if the specified thread is the main thread.
1002 *
1003 * @returns true if it is, false if it isn't.
1004 *
1005 * @param hThread The thread handle.
1006 *
1007 * @remarks This function may not return the correct value when rtR3Init was
1008 * called on a thread of the than the main one. This could for
1009 * instance happen when the DLL/DYLIB/SO containing IPRT is dynamically
1010 * loaded at run time by a different thread.
1011 */
1012RTDECL(bool) RTThreadIsMain(RTTHREAD hThread)
1013{
1014 PRTTHREADINT pThread = rtThreadGet(hThread);
1015 if (pThread)
1016 {
1017 bool fRc = !!(pThread->fIntFlags & RTTHREADINT_FLAGS_MAIN);
1018 rtThreadRelease(pThread);
1019 return fRc;
1020 }
1021 return false;
1022}
1023RT_EXPORT_SYMBOL(RTThreadIsMain);
1024
1025
1026RTDECL(bool) RTThreadIsSelfAlive(void)
1027{
1028 if (g_frtThreadInitialized)
1029 {
1030 RTTHREAD hSelf = RTThreadSelf();
1031 if (hSelf != NIL_RTTHREAD)
1032 {
1033 /*
1034 * Inspect the thread state. ASSUMES thread state order.
1035 */
1036 RTTHREADSTATE enmState = rtThreadGetState(hSelf);
1037 if ( enmState >= RTTHREADSTATE_RUNNING
1038 && enmState <= RTTHREADSTATE_END)
1039 return true;
1040 }
1041 }
1042 return false;
1043}
1044RT_EXPORT_SYMBOL(RTThreadIsSelfAlive);
1045
1046
1047RTDECL(bool) RTThreadIsSelfKnown(void)
1048{
1049 if (g_frtThreadInitialized)
1050 {
1051 RTTHREAD hSelf = RTThreadSelf();
1052 if (hSelf != NIL_RTTHREAD)
1053 return true;
1054 }
1055 return false;
1056}
1057RT_EXPORT_SYMBOL(RTThreadIsSelfKnown);
1058
1059
1060RTDECL(bool) RTThreadIsInitialized(void)
1061{
1062 return g_frtThreadInitialized;
1063}
1064RT_EXPORT_SYMBOL(RTThreadIsInitialized);
1065
1066
1067/**
1068 * Signal the user event.
1069 *
1070 * @returns iprt status code.
1071 */
1072RTDECL(int) RTThreadUserSignal(RTTHREAD Thread)
1073{
1074 int rc;
1075 PRTTHREADINT pThread = rtThreadGet(Thread);
1076 if (pThread)
1077 {
1078 rc = RTSemEventMultiSignal(pThread->EventUser);
1079 rtThreadRelease(pThread);
1080 }
1081 else
1082 rc = VERR_INVALID_HANDLE;
1083 return rc;
1084}
1085RT_EXPORT_SYMBOL(RTThreadUserSignal);
1086
1087
1088/**
1089 * Wait for the user event, resume on interruption.
1090 *
1091 * @returns iprt status code.
1092 * @param Thread The thread to wait for.
1093 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1094 * an indefinite wait.
1095 */
1096RTDECL(int) RTThreadUserWait(RTTHREAD Thread, RTMSINTERVAL cMillies)
1097{
1098 int rc;
1099 PRTTHREADINT pThread = rtThreadGet(Thread);
1100 if (pThread)
1101 {
1102 rc = RTSemEventMultiWait(pThread->EventUser, cMillies);
1103 rtThreadRelease(pThread);
1104 }
1105 else
1106 rc = VERR_INVALID_HANDLE;
1107 return rc;
1108}
1109RT_EXPORT_SYMBOL(RTThreadUserWait);
1110
1111
1112/**
1113 * Wait for the user event, return on interruption.
1114 *
1115 * @returns iprt status code.
1116 * @param Thread The thread to wait for.
1117 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1118 * an indefinite wait.
1119 */
1120RTDECL(int) RTThreadUserWaitNoResume(RTTHREAD Thread, RTMSINTERVAL cMillies)
1121{
1122 int rc;
1123 PRTTHREADINT pThread = rtThreadGet(Thread);
1124 if (pThread)
1125 {
1126 rc = RTSemEventMultiWaitNoResume(pThread->EventUser, cMillies);
1127 rtThreadRelease(pThread);
1128 }
1129 else
1130 rc = VERR_INVALID_HANDLE;
1131 return rc;
1132}
1133RT_EXPORT_SYMBOL(RTThreadUserWaitNoResume);
1134
1135
1136/**
1137 * Reset the user event.
1138 *
1139 * @returns iprt status code.
1140 * @param Thread The thread to reset.
1141 */
1142RTDECL(int) RTThreadUserReset(RTTHREAD Thread)
1143{
1144 int rc;
1145 PRTTHREADINT pThread = rtThreadGet(Thread);
1146 if (pThread)
1147 {
1148 rc = RTSemEventMultiReset(pThread->EventUser);
1149 rtThreadRelease(pThread);
1150 }
1151 else
1152 rc = VERR_INVALID_HANDLE;
1153 return rc;
1154}
1155RT_EXPORT_SYMBOL(RTThreadUserReset);
1156
1157
1158/**
1159 * Wait for the thread to terminate.
1160 *
1161 * @returns iprt status code.
1162 * @param Thread The thread to wait for.
1163 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1164 * an indefinite wait.
1165 * @param prc Where to store the return code of the thread. Optional.
1166 * @param fAutoResume Whether or not to resume the wait on VERR_INTERRUPTED.
1167 */
1168static int rtThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc, bool fAutoResume)
1169{
1170 int rc = VERR_INVALID_HANDLE;
1171 if (Thread != NIL_RTTHREAD)
1172 {
1173 PRTTHREADINT pThread = rtThreadGet(Thread);
1174 if (pThread)
1175 {
1176 if (pThread->fFlags & RTTHREADFLAGS_WAITABLE)
1177 {
1178#if defined(IN_RING3) && defined(RT_OS_WINDOWS)
1179 if (RT_LIKELY(rtThreadNativeIsAliveKludge(pThread)))
1180#endif
1181 {
1182 if (fAutoResume)
1183 rc = RTSemEventMultiWait(pThread->EventTerminated, cMillies);
1184 else
1185 rc = RTSemEventMultiWaitNoResume(pThread->EventTerminated, cMillies);
1186 }
1187#if defined(IN_RING3) && defined(RT_OS_WINDOWS)
1188 else
1189 {
1190 rc = VINF_SUCCESS;
1191 if (pThread->rc == VERR_PROCESS_RUNNING)
1192 pThread->rc = VERR_THREAD_IS_DEAD;
1193 }
1194#endif
1195 if (RT_SUCCESS(rc))
1196 {
1197 if (prc)
1198 *prc = pThread->rc;
1199
1200 /*
1201 * If the thread is marked as waitable, we'll do one additional
1202 * release in order to free up the thread structure (see how we
1203 * init cRef in rtThreadAlloc()).
1204 */
1205 if (ASMAtomicBitTestAndClear(&pThread->fFlags, RTTHREADFLAGS_WAITABLE_BIT))
1206 {
1207 rtThreadRelease(pThread);
1208#ifdef IN_RING0
1209 /*
1210 * IPRT termination kludge. Call native code to make sure
1211 * the last thread is really out of IPRT to prevent it from
1212 * crashing after we destroyed the spinlock in rtThreadTerm.
1213 */
1214 if ( ASMAtomicReadU32(&g_cThreadInTree) == 1
1215 && ASMAtomicReadU32(&pThread->cRefs) > 1)
1216 rtThreadNativeWaitKludge(pThread);
1217#endif
1218 }
1219 }
1220 }
1221 else
1222 {
1223 rc = VERR_THREAD_NOT_WAITABLE;
1224 AssertRC(rc);
1225 }
1226 rtThreadRelease(pThread);
1227 }
1228 }
1229 return rc;
1230}
1231
1232
1233/**
1234 * Wait for the thread to terminate, resume on interruption.
1235 *
1236 * @returns iprt status code.
1237 * Will not return VERR_INTERRUPTED.
1238 * @param Thread The thread to wait for.
1239 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1240 * an indefinite wait.
1241 * @param prc Where to store the return code of the thread. Optional.
1242 */
1243RTDECL(int) RTThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc)
1244{
1245 int rc = rtThreadWait(Thread, cMillies, prc, true);
1246 Assert(rc != VERR_INTERRUPTED);
1247 return rc;
1248}
1249RT_EXPORT_SYMBOL(RTThreadWait);
1250
1251
1252/**
1253 * Wait for the thread to terminate, return on interruption.
1254 *
1255 * @returns iprt status code.
1256 * @param Thread The thread to wait for.
1257 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1258 * an indefinite wait.
1259 * @param prc Where to store the return code of the thread. Optional.
1260 */
1261RTDECL(int) RTThreadWaitNoResume(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc)
1262{
1263 return rtThreadWait(Thread, cMillies, prc, false);
1264}
1265RT_EXPORT_SYMBOL(RTThreadWaitNoResume);
1266
1267
1268/**
1269 * Changes the type of the specified thread.
1270 *
1271 * @returns iprt status code.
1272 * @param Thread The thread which type should be changed.
1273 * @param enmType The new thread type.
1274 */
1275RTDECL(int) RTThreadSetType(RTTHREAD Thread, RTTHREADTYPE enmType)
1276{
1277 /*
1278 * Validate input.
1279 */
1280 int rc;
1281 if ( enmType > RTTHREADTYPE_INVALID
1282 && enmType < RTTHREADTYPE_END)
1283 {
1284 PRTTHREADINT pThread = rtThreadGet(Thread);
1285 if (pThread)
1286 {
1287 if (rtThreadIsAlive(pThread))
1288 {
1289 /*
1290 * Do the job.
1291 */
1292 RT_THREAD_LOCK_RW();
1293 rc = rtThreadNativeSetPriority(pThread, enmType);
1294 if (RT_SUCCESS(rc))
1295 ASMAtomicXchgSize(&pThread->enmType, enmType);
1296 RT_THREAD_UNLOCK_RW();
1297 if (RT_FAILURE(rc))
1298 Log(("RTThreadSetType: failed on thread %p (%s), rc=%Rrc!!!\n", Thread, pThread->szName, rc));
1299 }
1300 else
1301 rc = VERR_THREAD_IS_DEAD;
1302 rtThreadRelease(pThread);
1303 }
1304 else
1305 rc = VERR_INVALID_HANDLE;
1306 }
1307 else
1308 {
1309 AssertMsgFailed(("enmType=%d\n", enmType));
1310 rc = VERR_INVALID_PARAMETER;
1311 }
1312 return rc;
1313}
1314RT_EXPORT_SYMBOL(RTThreadSetType);
1315
1316
1317/**
1318 * Gets the type of the specified thread.
1319 *
1320 * @returns The thread type.
1321 * @returns RTTHREADTYPE_INVALID if the thread handle is invalid.
1322 * @param Thread The thread in question.
1323 */
1324RTDECL(RTTHREADTYPE) RTThreadGetType(RTTHREAD Thread)
1325{
1326 RTTHREADTYPE enmType = RTTHREADTYPE_INVALID;
1327 PRTTHREADINT pThread = rtThreadGet(Thread);
1328 if (pThread)
1329 {
1330 enmType = pThread->enmType;
1331 rtThreadRelease(pThread);
1332 }
1333 return enmType;
1334}
1335RT_EXPORT_SYMBOL(RTThreadGetType);
1336
1337#ifdef IN_RING3
1338
1339/**
1340 * Recalculates scheduling attributes for the default process
1341 * priority using the specified priority type for the calling thread.
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.
1346 *
1347 * @returns iprt status code.
1348 * @remarks Will only work for strict builds.
1349 */
1350int rtThreadDoCalcDefaultPriority(RTTHREADTYPE enmType)
1351{
1352 RT_THREAD_LOCK_RW();
1353 int rc = rtSchedNativeCalcDefaultPriority(enmType);
1354 RT_THREAD_UNLOCK_RW();
1355 return rc;
1356}
1357
1358
1359/**
1360 * Thread enumerator - sets the priority of one thread.
1361 *
1362 * @returns 0 to continue.
1363 * @returns !0 to stop. In our case a VERR_ code.
1364 * @param pNode The thread node.
1365 * @param pvUser The new priority.
1366 */
1367static DECLCALLBACK(int) rtThreadSetPriorityOne(PAVLPVNODECORE pNode, void *pvUser)
1368{
1369 PRTTHREADINT pThread = (PRTTHREADINT)pNode;
1370 if (!rtThreadIsAlive(pThread))
1371 return VINF_SUCCESS;
1372 int rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
1373 if (RT_SUCCESS(rc)) /* hide any warnings */
1374 return VINF_SUCCESS;
1375 NOREF(pvUser);
1376 return rc;
1377}
1378
1379
1380/**
1381 * Attempts to alter the priority of the current process.
1382 *
1383 * The scheduling attributes are targeted at threads and they are protected
1384 * by the thread read-write semaphore, that's why RTProc is forwarding the
1385 * operation to RTThread. This operation also involves updating all thread
1386 * which is much faster done from RTThread.
1387 *
1388 * @returns iprt status code.
1389 * @param enmPriority The new priority.
1390 */
1391DECLHIDDEN(int) rtThreadDoSetProcPriority(RTPROCPRIORITY enmPriority)
1392{
1393 LogFlow(("rtThreadDoSetProcPriority: enmPriority=%d\n", enmPriority));
1394
1395 /*
1396 * First validate that we're allowed by the OS to use all the
1397 * scheduling attributes defined by the specified process priority.
1398 */
1399 RT_THREAD_LOCK_RW();
1400 int rc = rtProcNativeSetPriority(enmPriority);
1401 if (RT_SUCCESS(rc))
1402 {
1403 /*
1404 * Update the priority of existing thread.
1405 */
1406 rc = RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
1407 if (RT_SUCCESS(rc))
1408 ASMAtomicXchgSize(&g_enmProcessPriority, enmPriority);
1409 else
1410 {
1411 /*
1412 * Failed, restore the priority.
1413 */
1414 rtProcNativeSetPriority(g_enmProcessPriority);
1415 RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
1416 }
1417 }
1418 RT_THREAD_UNLOCK_RW();
1419 LogFlow(("rtThreadDoSetProcPriority: returns %Rrc\n", rc));
1420 return rc;
1421}
1422
1423
1424/**
1425 * Change the thread state to blocking.
1426 *
1427 * @param hThread The current thread.
1428 * @param enmState The sleep state.
1429 * @param fReallySleeping Really going to sleep now.
1430 */
1431RTDECL(void) RTThreadBlocking(RTTHREAD hThread, RTTHREADSTATE enmState, bool fReallySleeping)
1432{
1433 Assert(RTTHREAD_IS_SLEEPING(enmState));
1434 PRTTHREADINT pThread = hThread;
1435 if (pThread != NIL_RTTHREAD)
1436 {
1437 Assert(pThread == RTThreadSelf());
1438 if (rtThreadGetState(pThread) == RTTHREADSTATE_RUNNING)
1439 rtThreadSetState(pThread, enmState);
1440 ASMAtomicWriteBool(&pThread->fReallySleeping, fReallySleeping);
1441 }
1442}
1443RT_EXPORT_SYMBOL(RTThreadBlocking);
1444
1445
1446/**
1447 * Unblocks a thread.
1448 *
1449 * This function is paired with rtThreadBlocking.
1450 *
1451 * @param hThread The current thread.
1452 * @param enmCurState The current state, used to check for nested blocking.
1453 * The new state will be running.
1454 */
1455RTDECL(void) RTThreadUnblocked(RTTHREAD hThread, RTTHREADSTATE enmCurState)
1456{
1457 PRTTHREADINT pThread = hThread;
1458 if (pThread != NIL_RTTHREAD)
1459 {
1460 Assert(pThread == RTThreadSelf());
1461 ASMAtomicWriteBool(&pThread->fReallySleeping, false);
1462
1463 RTTHREADSTATE enmActualState = rtThreadGetState(pThread);
1464 if (enmActualState == enmCurState)
1465 {
1466 rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
1467 if ( pThread->LockValidator.pRec
1468 && pThread->LockValidator.enmRecState == enmCurState)
1469 ASMAtomicWriteNullPtr(&pThread->LockValidator.pRec);
1470 }
1471 /* This is a bit ugly... :-/ */
1472 else if ( ( enmActualState == RTTHREADSTATE_TERMINATED
1473 || enmActualState == RTTHREADSTATE_INITIALIZING)
1474 && pThread->LockValidator.pRec)
1475 ASMAtomicWriteNullPtr(&pThread->LockValidator.pRec);
1476 Assert( pThread->LockValidator.pRec == NULL
1477 || RTTHREAD_IS_SLEEPING(enmActualState));
1478 }
1479}
1480RT_EXPORT_SYMBOL(RTThreadUnblocked);
1481
1482
1483/**
1484 * Get the current thread state.
1485 *
1486 * @returns The thread state.
1487 * @param hThread The thread.
1488 */
1489RTDECL(RTTHREADSTATE) RTThreadGetState(RTTHREAD hThread)
1490{
1491 RTTHREADSTATE enmState = RTTHREADSTATE_INVALID;
1492 PRTTHREADINT pThread = rtThreadGet(hThread);
1493 if (pThread)
1494 {
1495 enmState = rtThreadGetState(pThread);
1496 rtThreadRelease(pThread);
1497 }
1498 return enmState;
1499}
1500RT_EXPORT_SYMBOL(RTThreadGetState);
1501
1502
1503RTDECL(RTTHREADSTATE) RTThreadGetReallySleeping(RTTHREAD hThread)
1504{
1505 RTTHREADSTATE enmState = RTTHREADSTATE_INVALID;
1506 PRTTHREADINT pThread = rtThreadGet(hThread);
1507 if (pThread)
1508 {
1509 enmState = rtThreadGetState(pThread);
1510 if (!ASMAtomicUoReadBool(&pThread->fReallySleeping))
1511 enmState = RTTHREADSTATE_RUNNING;
1512 rtThreadRelease(pThread);
1513 }
1514 return enmState;
1515}
1516RT_EXPORT_SYMBOL(RTThreadGetReallySleeping);
1517
1518
1519/**
1520 * Translate a thread state into a string.
1521 *
1522 * @returns Pointer to a read-only string containing the state name.
1523 * @param enmState The state.
1524 */
1525RTDECL(const char *) RTThreadStateName(RTTHREADSTATE enmState)
1526{
1527 switch (enmState)
1528 {
1529 case RTTHREADSTATE_INVALID: return "INVALID";
1530 case RTTHREADSTATE_INITIALIZING: return "INITIALIZING";
1531 case RTTHREADSTATE_TERMINATED: return "TERMINATED";
1532 case RTTHREADSTATE_RUNNING: return "RUNNING";
1533 case RTTHREADSTATE_CRITSECT: return "CRITSECT";
1534 case RTTHREADSTATE_EVENT: return "EVENT";
1535 case RTTHREADSTATE_EVENT_MULTI: return "EVENT_MULTI";
1536 case RTTHREADSTATE_FAST_MUTEX: return "FAST_MUTEX";
1537 case RTTHREADSTATE_MUTEX: return "MUTEX";
1538 case RTTHREADSTATE_RW_READ: return "RW_READ";
1539 case RTTHREADSTATE_RW_WRITE: return "RW_WRITE";
1540 case RTTHREADSTATE_SLEEP: return "SLEEP";
1541 case RTTHREADSTATE_SPIN_MUTEX: return "SPIN_MUTEX";
1542 default: return "UnknownThreadState";
1543 }
1544}
1545RT_EXPORT_SYMBOL(RTThreadStateName);
1546
1547#endif /* IN_RING3 */
1548#ifdef IPRT_WITH_GENERIC_TLS
1549
1550/**
1551 * Thread enumerator - clears a TLS entry.
1552 *
1553 * @returns 0.
1554 * @param pNode The thread node.
1555 * @param pvUser The TLS index.
1556 */
1557static DECLCALLBACK(int) rtThreadClearTlsEntryCallback(PAVLPVNODECORE pNode, void *pvUser)
1558{
1559 PRTTHREADINT pThread = (PRTTHREADINT)pNode;
1560 RTTLS iTls = (RTTLS)(uintptr_t)pvUser;
1561 ASMAtomicWriteNullPtr(&pThread->apvTlsEntries[iTls]);
1562 return 0;
1563}
1564
1565
1566/**
1567 * Helper for the generic TLS implementation that clears a given TLS
1568 * entry on all threads.
1569 *
1570 * @param iTls The TLS entry. (valid)
1571 */
1572DECLHIDDEN(void) rtThreadClearTlsEntry(RTTLS iTls)
1573{
1574 RT_THREAD_LOCK_RD();
1575 RTAvlPVDoWithAll(&g_ThreadTree, true /* fFromLeft*/, rtThreadClearTlsEntryCallback, (void *)(uintptr_t)iTls);
1576 RT_THREAD_UNLOCK_RD();
1577}
1578
1579#endif /* IPRT_WITH_GENERIC_TLS */
1580
1581
1582#if defined(RT_OS_WINDOWS) && defined(IN_RING3)
1583
1584/**
1585 * Thread enumeration callback for RTThreadNameThreads
1586 */
1587static DECLCALLBACK(int) rtThreadNameThreadCallback(PAVLPVNODECORE pNode, void *pvUser)
1588{
1589 PRTTHREADINT pThread = (PRTTHREADINT)pNode;
1590 rtThreadNativeInformDebugger(pThread);
1591 RT_NOREF_PV(pvUser);
1592 return 0;
1593}
1594
1595/**
1596 * A function that can be called from the windows debugger to get the names of
1597 * all threads when attaching to a process.
1598 *
1599 * Usage: .call VBoxRT!RTThreadNameThreads()
1600 *
1601 * @returns 0
1602 * @remarks Do not call from source code as it skips locks.
1603 */
1604extern "C" RTDECL(int) RTThreadNameThreads(void);
1605RTDECL(int) RTThreadNameThreads(void)
1606{
1607 return RTAvlPVDoWithAll(&g_ThreadTree, true /* fFromLeft*/, rtThreadNameThreadCallback, NULL);
1608}
1609
1610#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