VirtualBox

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

Last change on this file since 99248 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

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