VirtualBox

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

Last change on this file since 96120 was 96052, checked in by vboxsync, 3 years ago

IPRT/nocrt: Added no-CRT per-thread data like errno and strtok state. Implemented strtol and errno accessor. bugref:10261

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