VirtualBox

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

最後變更 在這個檔案從7085是 6961,由 vboxsync 提交於 17 年 前

Generic implementation (in case it's needed).

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 41.4 KB
 
1/* $Id: thread.cpp 6961 2008-02-14 17:39:02Z vboxsync $ */
2/** @file
3 * innotek Portable Runtime - Threads, common routines.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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/*******************************************************************************
30* Header Files *
31*******************************************************************************/
32#define LOG_GROUP RTLOGGROUP_THREAD
33#include <iprt/thread.h>
34#include <iprt/log.h>
35#include <iprt/avl.h>
36#include <iprt/alloc.h>
37#include <iprt/assert.h>
38#include <iprt/semaphore.h>
39#ifdef IN_RING0
40# include <iprt/spinlock.h>
41#endif
42#include <iprt/asm.h>
43#include <iprt/err.h>
44#include <iprt/string.h>
45#include "internal/thread.h"
46#include "internal/sched.h"
47#include "internal/process.h"
48
49
50/*******************************************************************************
51* Defined Constants And Macros *
52*******************************************************************************/
53#ifdef IN_RING0
54# define RT_THREAD_LOCK_TMP(Tmp) RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER
55# define RT_THREAD_LOCK_RW(Tmp) RTSpinlockAcquireNoInts(g_ThreadSpinlock, &(Tmp))
56# define RT_THREAD_UNLOCK_RW(Tmp) RTSpinlockReleaseNoInts(g_ThreadSpinlock, &(Tmp))
57# define RT_THREAD_LOCK_RD(Tmp) RTSpinlockAcquireNoInts(g_ThreadSpinlock, &(Tmp))
58# define RT_THREAD_UNLOCK_RD(Tmp) RTSpinlockReleaseNoInts(g_ThreadSpinlock, &(Tmp))
59#else
60# define RT_THREAD_LOCK_TMP(Tmp)
61# define RT_THREAD_LOCK_RW(Tmp) rtThreadLockRW()
62# define RT_THREAD_UNLOCK_RW(Tmp) rtThreadUnLockRW()
63# define RT_THREAD_LOCK_RD(Tmp) rtThreadLockRD()
64# define RT_THREAD_UNLOCK_RD(Tmp) rtThreadUnLockRD()
65#endif
66
67
68/*******************************************************************************
69* Global Variables *
70*******************************************************************************/
71/** The AVL thread containing the threads. */
72static PAVLPVNODECORE g_ThreadTree;
73#ifdef IN_RING3
74/** The RW lock protecting the tree. */
75static RTSEMRW g_ThreadRWSem = NIL_RTSEMRW;
76#else
77/** The spinlocks protecting the tree. */
78static RTSPINLOCK g_ThreadSpinlock = NIL_RTSPINLOCK;
79#endif
80
81
82/*******************************************************************************
83* Internal Functions *
84*******************************************************************************/
85static void rtThreadDestroy(PRTTHREADINT pThread);
86static int rtThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, const char *pszName);
87static void rtThreadRemoveLocked(PRTTHREADINT pThread);
88static PRTTHREADINT rtThreadAlloc(RTTHREADTYPE enmType, unsigned fFlags, unsigned fIntFlags, const char *pszName);
89
90
91/** @page pg_rt_thread IPRT Thread Internals
92 *
93 * IPRT provides interface to whatever native threading that the host provides,
94 * preferably using a CRT level interface to better integrate with other libraries.
95 *
96 * Internally IPRT keeps track of threads by means of the RTTHREADINT structure.
97 * All the RTTHREADINT structures are kept in a AVL tree which is protected by a
98 * read/write lock for efficient access. A thread is inserted into the tree in
99 * three places in the code. The main thread is 'adopted' by IPRT on RTR3Init()
100 * by rtThreadAdopt(). When creating a new thread there the child and the parent
101 * race inserting the thread, this is rtThreadMain() and RTThreadCreate.
102 *
103 * RTTHREADINT objects are using reference counting as a mean of sticking around
104 * till no-one needs them any longer. Waitable threads is created with one extra
105 * reference so they won't go away until they are waited on. This introduces a
106 * major problem if we use the host thread identifier as key in the AVL tree - the
107 * host may reuse the thread identifier before the thread was waited on. So, on
108 * most platforms we are using the RTTHREADINT pointer as key and not the
109 * thread id. RTThreadSelf() then have to be implemented using a pointer stored
110 * in thread local storage (TLS).
111 *
112 * In Ring-0 we only try keep track of kernel threads created by RTCreateThread
113 * at the moment. There we really only need the 'join' feature, but doing things
114 * the same way allow us to name threads and similar stuff.
115 */
116
117
118/**
119 * Initializes the thread database.
120 *
121 * @returns iprt status code.
122 */
123int rtThreadInit(void)
124{
125#ifdef IN_RING3
126 int rc = VINF_ALREADY_INITIALIZED;
127 if (g_ThreadRWSem == NIL_RTSEMRW)
128 {
129 /*
130 * We assume the caller is the 1st thread, which we'll call 'main'.
131 * But first, we'll create the semaphore.
132 */
133 int rc = RTSemRWCreate(&g_ThreadRWSem);
134 if (RT_SUCCESS(rc))
135 {
136 rc = rtThreadNativeInit();
137#ifdef IN_RING3
138 if (RT_SUCCESS(rc))
139 rc = rtThreadAdopt(RTTHREADTYPE_DEFAULT, 0, "main");
140 if (RT_SUCCESS(rc))
141 rc = rtSchedNativeCalcDefaultPriority(RTTHREADTYPE_DEFAULT);
142#endif
143 if (RT_SUCCESS(rc))
144 return VINF_SUCCESS;
145
146 /* failed, clear out */
147 RTSemRWDestroy(g_ThreadRWSem);
148 g_ThreadRWSem = NIL_RTSEMRW;
149 }
150 }
151
152#elif defined(IN_RING0)
153
154 /*
155 * Create the spinlock and to native init.
156 */
157 Assert(g_ThreadSpinlock == NIL_RTSPINLOCK);
158 int rc = RTSpinlockCreate(&g_ThreadSpinlock);
159 if (RT_SUCCESS(rc))
160 {
161 rc = rtThreadNativeInit();
162 if (RT_SUCCESS(rc))
163 return VINF_SUCCESS;
164
165 /* failed, clear out */
166 RTSpinlockDestroy(g_ThreadSpinlock);
167 g_ThreadSpinlock = NIL_RTSPINLOCK;
168 }
169#else
170# error "!IN_RING0 && !IN_RING3"
171#endif
172 return rc;
173}
174
175
176/**
177 * Terminates the thread database.
178 */
179void rtThreadTerm(void)
180{
181#ifdef IN_RING3
182 /* we don't cleanup here yet */
183
184#elif defined(IN_RING0)
185 /* just destroy the spinlock and assume the thread is fine... */
186 RTSpinlockDestroy(g_ThreadSpinlock);
187 g_ThreadSpinlock = NIL_RTSPINLOCK;
188 if (g_ThreadTree != NULL)
189 AssertMsg2("WARNING: g_ThreadTree=%p\n", g_ThreadTree);
190#endif
191}
192
193
194
195#ifdef IN_RING3
196
197inline void rtThreadLockRW(void)
198{
199 if (g_ThreadRWSem == NIL_RTSEMRW)
200 rtThreadInit();
201 int rc = RTSemRWRequestWrite(g_ThreadRWSem, RT_INDEFINITE_WAIT);
202 AssertReleaseRC(rc);
203}
204
205
206inline void rtThreadLockRD(void)
207{
208 if (g_ThreadRWSem == NIL_RTSEMRW)
209 rtThreadInit();
210 int rc = RTSemRWRequestRead(g_ThreadRWSem, RT_INDEFINITE_WAIT);
211 AssertReleaseRC(rc);
212}
213
214
215inline void rtThreadUnLockRW(void)
216{
217 int rc = RTSemRWReleaseWrite(g_ThreadRWSem);
218 AssertReleaseRC(rc);
219}
220
221
222inline void rtThreadUnLockRD(void)
223{
224 int rc = RTSemRWReleaseRead(g_ThreadRWSem);
225 AssertReleaseRC(rc);
226}
227
228#endif /* IN_RING3 */
229
230
231/**
232 * Adopts the calling thread.
233 * No locks are taken or released by this function.
234 */
235static int rtThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, const char *pszName)
236{
237 Assert(!(fFlags & RTTHREADFLAGS_WAITABLE));
238 fFlags &= ~RTTHREADFLAGS_WAITABLE;
239
240 /*
241 * Allocate and insert the thread.
242 */
243 int rc = VERR_NO_MEMORY;
244 PRTTHREADINT pThread = rtThreadAlloc(enmType, fFlags, RTTHREADINT_FLAGS_ALIEN, pszName);
245 if (pThread)
246 {
247 RTNATIVETHREAD NativeThread = RTThreadNativeSelf();
248 rc = rtThreadNativeAdopt(pThread);
249 if (RT_SUCCESS(rc))
250 {
251 rtThreadInsert(pThread, NativeThread);
252 pThread->enmState = RTTHREADSTATE_RUNNING;
253 rtThreadRelease(pThread);
254 }
255 }
256 return rc;
257}
258
259
260/**
261 * Adopts a non-IPRT thread.
262 *
263 * @returns IPRT status code.
264 * @param enmType The thread type.
265 * @param fFlags The thread flags. RTTHREADFLAGS_WAITABLE is not currently allowed.
266 * @param pszName The thread name. Optional.
267 * @param pThread Where to store the thread handle. Optional.
268 */
269RTDECL(int) RTThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, const char *pszName, PRTTHREAD pThread)
270{
271 AssertReturn(!(fFlags & RTTHREADFLAGS_WAITABLE), VERR_INVALID_PARAMETER);
272 AssertReturn(!pszName || VALID_PTR(pszName), VERR_INVALID_POINTER);
273 AssertReturn(!pThread || VALID_PTR(pThread), VERR_INVALID_POINTER);
274
275 int rc = VINF_SUCCESS;
276 RTTHREAD Thread = RTThreadSelf();
277 if (Thread == NIL_RTTHREAD)
278 {
279 /* generate a name if none was given. */
280 char szName[RTTHREAD_NAME_LEN];
281 if (!pszName || !*pszName)
282 {
283 static uint32_t s_i32AlienId = 0;
284 uint32_t i32Id = ASMAtomicIncU32(&s_i32AlienId);
285 RTStrPrintf(szName, sizeof(szName), "ALIEN-%RX32", i32Id);
286 pszName = szName;
287 }
288
289 /* try adopt it */
290 rc = rtThreadAdopt(enmType, fFlags, pszName);
291 Thread = RTThreadSelf();
292 Log(("RTThreadAdopt: %RTthrd %RTnthrd '%s' enmType=%d fFlags=%#x rc=%Rrc\n",
293 Thread, RTThreadNativeSelf(), pszName, enmType, fFlags, rc));
294 }
295 else
296 Log(("RTThreadAdopt: %RTthrd %RTnthrd '%s' enmType=%d fFlags=%#x - already adopted!\n",
297 Thread, RTThreadNativeSelf(), pszName, enmType, fFlags));
298
299 if (pThread)
300 *pThread = Thread;
301 return rc;
302}
303
304
305/**
306 * Allocates a per thread data structure and initializes the basic fields.
307 *
308 * @returns Pointer to per thread data structure.
309 * This is reference once.
310 * @returns NULL on failure.
311 * @param enmType The thread type.
312 * @param fFlags The thread flags.
313 * @param fIntFlags The internal thread flags.
314 * @param pszName Pointer to the thread name.
315 */
316PRTTHREADINT rtThreadAlloc(RTTHREADTYPE enmType, unsigned fFlags, unsigned fIntFlags, const char *pszName)
317{
318 PRTTHREADINT pThread = (PRTTHREADINT)RTMemAllocZ(sizeof(RTTHREADINT));
319 if (pThread)
320 {
321 pThread->Core.Key = (void*)NIL_RTTHREAD;
322 pThread->u32Magic = RTTHREADINT_MAGIC;
323 size_t cchName = strlen(pszName);
324 if (cchName >= RTTHREAD_NAME_LEN)
325 cchName = RTTHREAD_NAME_LEN - 1;
326 memcpy(pThread->szName, pszName, cchName);
327 pThread->szName[cchName] = '\0';
328 pThread->cRefs = 2 + !!(fFlags & RTTHREADFLAGS_WAITABLE); /* And extra reference if waitable. */
329 pThread->rc = VERR_PROCESS_RUNNING; /** @todo get a better error code! */
330 pThread->enmType = enmType;
331 pThread->fFlags = fFlags;
332 pThread->fIntFlags = fIntFlags;
333 pThread->enmState = RTTHREADSTATE_INITIALIZING;
334 int rc = RTSemEventMultiCreate(&pThread->EventUser);
335 if (RT_SUCCESS(rc))
336 {
337 rc = RTSemEventMultiCreate(&pThread->EventTerminated);
338 if (RT_SUCCESS(rc))
339 return pThread;
340 RTSemEventMultiDestroy(pThread->EventUser);
341 }
342 RTMemFree(pThread);
343 }
344 return NULL;
345}
346
347
348/**
349 * Insert the per thread data structure into the tree.
350 *
351 * This can be called from both the thread it self and the parent,
352 * thus it must handle insertion failures in a nice manner.
353 *
354 * @param pThread Pointer to thread structure allocated by rtThreadAlloc().
355 * @param NativeThread The native thread id.
356 */
357void rtThreadInsert(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread)
358{
359 Assert(pThread);
360 Assert(pThread->u32Magic == RTTHREADINT_MAGIC);
361
362 RT_THREAD_LOCK_TMP(Tmp);
363 RT_THREAD_LOCK_RW(Tmp);
364
365 /*
366 * Before inserting we must check if there is a thread with this id
367 * in the tree already. We're racing parent and child on insert here
368 * so that the handle is valid in both ends when they return / start.
369 *
370 * If it's not ourself we find, it's a dead alien thread and we will
371 * unlink it from the tree. Alien threads will be released at this point.
372 */
373 PRTTHREADINT pThreadOther = (PRTTHREADINT)RTAvlPVGet(&g_ThreadTree, (void *)NativeThread);
374 if (pThreadOther != pThread)
375 {
376 /* remove dead alien if any */
377 if (pThreadOther)
378 {
379 Assert(pThreadOther->fIntFlags & RTTHREADINT_FLAGS_ALIEN);
380 ASMAtomicBitClear(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT);
381 rtThreadRemoveLocked(pThreadOther);
382 if (pThreadOther->fIntFlags & RTTHREADINT_FLAGS_ALIEN)
383 rtThreadRelease(pThreadOther);
384 }
385
386 /* insert the thread */
387 pThread->Core.Key = (void *)NativeThread;
388 bool fRc = RTAvlPVInsert(&g_ThreadTree, &pThread->Core);
389 ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE);
390
391 AssertReleaseMsg(fRc, ("Lock problem? %p (%RTnthrd) %s\n", pThread, NativeThread, pThread->szName));
392 NOREF(fRc);
393 }
394
395 RT_THREAD_UNLOCK_RW(Tmp);
396}
397
398
399/**
400 * Removes the thread from the AVL tree, call owns the tree lock
401 * and has cleared the RTTHREADINT_FLAG_IN_TREE bit.
402 *
403 * @param pThread The thread to remove.
404 */
405static void rtThreadRemoveLocked(PRTTHREADINT pThread)
406{
407 PRTTHREADINT pThread2 = (PRTTHREADINT)RTAvlPVRemove(&g_ThreadTree, pThread->Core.Key);
408 AssertMsg(pThread2 == pThread, ("%p(%s) != %p (%p/%s)\n", pThread2, pThread2 ? pThread2->szName : "<null>",
409 pThread, pThread->Core.Key, pThread->szName));
410 NOREF(pThread2);
411}
412
413
414/**
415 * Removes the thread from the AVL tree.
416 *
417 * @param pThread The thread to remove.
418 */
419static void rtThreadRemove(PRTTHREADINT pThread)
420{
421 RT_THREAD_LOCK_TMP(Tmp);
422 RT_THREAD_LOCK_RW(Tmp);
423 if (ASMAtomicBitTestAndClear(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT))
424 rtThreadRemoveLocked(pThread);
425 RT_THREAD_UNLOCK_RW(Tmp);
426}
427
428
429/**
430 * Checks if a thread is alive or not.
431 *
432 * @returns true if the thread is alive (or we don't really know).
433 * @returns false if the thread has surely terminate.
434 */
435DECLINLINE(bool) rtThreadIsAlive(PRTTHREADINT pThread)
436{
437 return !(pThread->fIntFlags & RTTHREADINT_FLAGS_TERMINATED);
438}
439
440
441/**
442 * Gets a thread by it's native ID.
443 *
444 * @returns pointer to the thread structure.
445 * @returns NULL if not a thread IPRT knows.
446 * @param NativeThread The native thread id.
447 */
448PRTTHREADINT rtThreadGetByNative(RTNATIVETHREAD NativeThread)
449{
450 /*
451 * Simple tree lookup.
452 */
453 RT_THREAD_LOCK_TMP(Tmp);
454 RT_THREAD_LOCK_RD(Tmp);
455 PRTTHREADINT pThread = (PRTTHREADINT)RTAvlPVGet(&g_ThreadTree, (void *)NativeThread);
456 RT_THREAD_UNLOCK_RD(Tmp);
457 return pThread;
458}
459
460
461/**
462 * Gets the per thread data structure for a thread handle.
463 *
464 * @returns Pointer to the per thread data structure for Thread.
465 * The caller must release the thread using rtThreadRelease().
466 * @returns NULL if Thread was not found.
467 * @param Thread Thread id which structure is to be returned.
468 */
469PRTTHREADINT rtThreadGet(RTTHREAD Thread)
470{
471 if ( Thread != NIL_RTTHREAD
472 && VALID_PTR(Thread))
473 {
474 PRTTHREADINT pThread = (PRTTHREADINT)Thread;
475 if ( pThread->u32Magic == RTTHREADINT_MAGIC
476 && pThread->cRefs > 0)
477 {
478 ASMAtomicIncU32(&pThread->cRefs);
479 return pThread;
480 }
481 }
482
483 AssertMsgFailed(("Thread=%RTthrd\n", Thread));
484 return NULL;
485}
486
487
488/**
489 * Release a per thread data structure.
490 *
491 * @returns New reference count.
492 * @param pThread The thread structure to release.
493 */
494uint32_t rtThreadRelease(PRTTHREADINT pThread)
495{
496 Assert(pThread);
497 uint32_t cRefs;
498 if (pThread->cRefs >= 1)
499 {
500 cRefs = ASMAtomicDecU32(&pThread->cRefs);
501 if (!cRefs)
502 rtThreadDestroy(pThread);
503 }
504 else
505 cRefs = 0;
506 return cRefs;
507}
508
509
510/**
511 * Destroys the per thread data.
512 *
513 * @param pThread The thread to destroy.
514 */
515static void rtThreadDestroy(PRTTHREADINT pThread)
516{
517 /*
518 * Mark it dead and remove it from the tree.
519 */
520 ASMAtomicXchgU32(&pThread->u32Magic, RTTHREADINT_MAGIC_DEAD);
521 rtThreadRemove(pThread);
522
523 /*
524 * Free resources.
525 */
526 pThread->Core.Key = (void *)NIL_RTTHREAD;
527 pThread->enmType = RTTHREADTYPE_INVALID;
528 RTSemEventMultiDestroy(pThread->EventUser);
529 pThread->EventUser = NIL_RTSEMEVENTMULTI;
530 if (pThread->EventTerminated != NIL_RTSEMEVENTMULTI)
531 {
532 RTSemEventMultiDestroy(pThread->EventTerminated);
533 pThread->EventTerminated = NIL_RTSEMEVENTMULTI;
534 }
535 RTMemFree(pThread);
536}
537
538
539/**
540 * Terminates the thread.
541 * Called by the thread wrapper function when the thread terminates.
542 *
543 * @param pThread The thread structure.
544 * @param rc The thread result code.
545 */
546void rtThreadTerminate(PRTTHREADINT pThread, int rc)
547{
548 Assert(pThread->cRefs >= 1);
549
550#ifdef IPRT_WITH_GENERIC_TLS
551 /*
552 * Destroy TLS entries.
553 */
554 rtThreadTlsDestruction(pThread);
555#endif /* IPRT_WITH_GENERIC_TLS */
556
557 /*
558 * Set the rc, mark it terminated and signal anyone waiting.
559 */
560 pThread->rc = rc;
561 ASMAtomicXchgSize(&pThread->enmState, RTTHREADSTATE_TERMINATED);
562 ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAGS_TERMINATED);
563 if (pThread->EventTerminated != NIL_RTSEMEVENTMULTI)
564 RTSemEventMultiSignal(pThread->EventTerminated);
565
566 /*
567 * Remove the thread from the tree so that there will be no
568 * key clashes in the AVL tree and release our reference to ourself.
569 */
570 rtThreadRemove(pThread);
571 rtThreadRelease(pThread);
572}
573
574
575/**
576 * The common thread main function.
577 * This is called by rtThreadNativeMain().
578 *
579 * @returns The status code of the thread.
580 * pThread is dereference by the thread before returning!
581 * @param pThread The thread structure.
582 * @param NativeThread The native thread id.
583 * @param pszThreadName The name of the thread (purely a dummy for backtrace).
584 */
585int rtThreadMain(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread, const char *pszThreadName)
586{
587 NOREF(pszThreadName);
588 rtThreadInsert(pThread, NativeThread);
589 Log(("rtThreadMain: Starting: pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
590 pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
591
592 /*
593 * Change the priority.
594 */
595 int rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
596#ifdef IN_RING3
597 AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d enmPriority=%d rc=%Vrc\n",
598 pThread, NativeThread, pThread->szName, pThread->enmType, g_enmProcessPriority, rc));
599#else
600 AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d rc=%Vrc\n",
601 pThread, NativeThread, pThread->szName, pThread->enmType, rc));
602#endif
603
604 /*
605 * Call thread function and terminate when it returns.
606 */
607 pThread->enmState = RTTHREADSTATE_RUNNING;
608 rc = pThread->pfnThread(pThread, pThread->pvUser);
609
610 Log(("rtThreadMain: Terminating: rc=%d pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
611 rc, pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
612 rtThreadTerminate(pThread, rc);
613 return rc;
614}
615
616
617/**
618 * Create a new thread.
619 *
620 * @returns iprt status code.
621 * @param pThread Where to store the thread handle to the new thread. (optional)
622 * @param pfnThread The thread function.
623 * @param pvUser User argument.
624 * @param cbStack The size of the stack for the new thread.
625 * Use 0 for the default stack size.
626 * @param enmType The thread type. Used for deciding scheduling attributes
627 * of the thread.
628 * @param fFlags Flags of the RTTHREADFLAGS type (ORed together).
629 * @param pszName Thread name.
630 */
631RTDECL(int) RTThreadCreate(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
632 RTTHREADTYPE enmType, unsigned fFlags, const char *pszName)
633{
634 LogFlow(("RTThreadCreate: pThread=%p pfnThread=%p pvUser=%p cbStack=%#x enmType=%d fFlags=%#x pszName=%p:{%s}\n",
635 pThread, pfnThread, pvUser, cbStack, enmType, fFlags, pszName, pszName));
636
637 /*
638 * Validate input.
639 */
640 if (!VALID_PTR(pThread) && pThread)
641 {
642 Assert(VALID_PTR(pThread));
643 return VERR_INVALID_PARAMETER;
644 }
645 if (!VALID_PTR(pfnThread))
646 {
647 Assert(VALID_PTR(pfnThread));
648 return VERR_INVALID_PARAMETER;
649 }
650 if (!pszName || !*pszName || strlen(pszName) >= RTTHREAD_NAME_LEN)
651 {
652 AssertMsgFailed(("pszName=%s (max len is %d because of logging)\n", pszName, RTTHREAD_NAME_LEN - 1));
653 return VERR_INVALID_PARAMETER;
654 }
655 if (fFlags & ~RTTHREADFLAGS_MASK)
656 {
657 AssertMsgFailed(("fFlags=%#x\n", fFlags));
658 return VERR_INVALID_PARAMETER;
659 }
660
661 /*
662 * Allocate thread argument.
663 */
664 int rc;
665 PRTTHREADINT pThreadInt = rtThreadAlloc(enmType, fFlags, 0, pszName);
666 if (pThreadInt)
667 {
668 pThreadInt->pfnThread = pfnThread;
669 pThreadInt->pvUser = pvUser;
670 pThreadInt->cbStack = cbStack;
671
672 RTNATIVETHREAD NativeThread;
673 rc = rtThreadNativeCreate(pThreadInt, &NativeThread);
674 if (RT_SUCCESS(rc))
675 {
676 rtThreadInsert(pThreadInt, NativeThread);
677 rtThreadRelease(pThreadInt);
678 Log(("RTThreadCreate: Created thread %p (%p) %s\n", pThreadInt, NativeThread, pszName));
679 if (pThread)
680 *pThread = pThreadInt;
681 return VINF_SUCCESS;
682 }
683
684 pThreadInt->cRefs = 1;
685 rtThreadRelease(pThreadInt);
686 }
687 else
688 rc = VERR_NO_TMP_MEMORY;
689 LogFlow(("RTThreadCreate: Failed to create thread, rc=%Vrc\n", rc));
690 AssertReleaseRC(rc);
691 return rc;
692}
693
694
695/**
696 * Gets the native thread id of a IPRT thread.
697 *
698 * @returns The native thread id.
699 * @param Thread The IPRT thread.
700 */
701RTDECL(RTNATIVETHREAD) RTThreadGetNative(RTTHREAD Thread)
702{
703 PRTTHREADINT pThread = rtThreadGet(Thread);
704 if (pThread)
705 {
706 RTNATIVETHREAD NativeThread = (RTNATIVETHREAD)pThread->Core.Key;
707 rtThreadRelease(pThread);
708 return NativeThread;
709 }
710 return NIL_RTNATIVETHREAD;
711}
712
713
714/**
715 * Gets the IPRT thread of a native thread.
716 *
717 * @returns The IPRT thread handle
718 * @returns NIL_RTTHREAD if not a thread known to IPRT.
719 * @param NativeThread The native thread handle/id.
720 */
721RTDECL(RTTHREAD) RTThreadFromNative(RTNATIVETHREAD NativeThread)
722{
723 PRTTHREADINT pThread = rtThreadGetByNative(NativeThread);
724 if (pThread)
725 return pThread;
726 return NIL_RTTHREAD;
727}
728
729
730/**
731 * Gets the name of the current thread thread.
732 *
733 * @returns Pointer to readonly name string.
734 * @returns NULL on failure.
735 */
736RTDECL(const char *) RTThreadSelfName(void)
737{
738 RTTHREAD Thread = RTThreadSelf();
739 if (Thread != NIL_RTTHREAD)
740 {
741 PRTTHREADINT pThread = rtThreadGet(Thread);
742 if (pThread)
743 {
744 const char *szName = pThread->szName;
745 rtThreadRelease(pThread);
746 return szName;
747 }
748 }
749 return NULL;
750}
751
752
753/**
754 * Gets the name of a thread.
755 *
756 * @returns Pointer to readonly name string.
757 * @returns NULL on failure.
758 * @param Thread Thread handle of the thread to query the name of.
759 */
760RTDECL(const char *) RTThreadGetName(RTTHREAD Thread)
761{
762 if (Thread == NIL_RTTHREAD)
763 return NULL;
764 PRTTHREADINT pThread = rtThreadGet(Thread);
765 if (pThread)
766 {
767 const char *szName = pThread->szName;
768 rtThreadRelease(pThread);
769 return szName;
770 }
771 return NULL;
772}
773
774
775/**
776 * Sets the name of a thread.
777 *
778 * @returns iprt status code.
779 * @param Thread Thread handle of the thread to query the name of.
780 * @param pszName The thread name.
781 */
782RTDECL(int) RTThreadSetName(RTTHREAD Thread, const char *pszName)
783{
784 /*
785 * Validate input.
786 */
787 size_t cchName = strlen(pszName);
788 if (cchName >= RTTHREAD_NAME_LEN)
789 {
790 AssertMsgFailed(("pszName=%s is too long, max is %d\n", pszName, RTTHREAD_NAME_LEN - 1));
791 return VERR_INVALID_PARAMETER;
792 }
793 PRTTHREADINT pThread = rtThreadGet(Thread);
794 if (!pThread)
795 return VERR_INVALID_HANDLE;
796
797 /*
798 * Update the name.
799 */
800 pThread->szName[cchName] = '\0'; /* paranoia */
801 memcpy(pThread->szName, pszName, cchName);
802 rtThreadRelease(pThread);
803 return VINF_SUCCESS;
804}
805
806
807/**
808 * Signal the user event.
809 *
810 * @returns iprt status code.
811 */
812RTDECL(int) RTThreadUserSignal(RTTHREAD Thread)
813{
814 int rc;
815 PRTTHREADINT pThread = rtThreadGet(Thread);
816 if (pThread)
817 {
818 rc = RTSemEventMultiSignal(pThread->EventUser);
819 rtThreadRelease(pThread);
820 }
821 else
822 rc = VERR_INVALID_HANDLE;
823 return rc;
824}
825
826
827/**
828 * Wait for the user event, resume on interruption.
829 *
830 * @returns iprt status code.
831 * @param Thread The thread to wait for.
832 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
833 * an indefinite wait.
834 */
835RTDECL(int) RTThreadUserWait(RTTHREAD Thread, unsigned cMillies)
836{
837 int rc;
838 PRTTHREADINT pThread = rtThreadGet(Thread);
839 if (pThread)
840 {
841 rc = RTSemEventMultiWait(pThread->EventUser, cMillies);
842 rtThreadRelease(pThread);
843 }
844 else
845 rc = VERR_INVALID_HANDLE;
846 return rc;
847}
848
849
850/**
851 * Wait for the user event, return on interruption.
852 *
853 * @returns iprt status code.
854 * @param Thread The thread to wait for.
855 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
856 * an indefinite wait.
857 */
858RTDECL(int) RTThreadUserWaitNoResume(RTTHREAD Thread, unsigned cMillies)
859{
860 int rc;
861 PRTTHREADINT pThread = rtThreadGet(Thread);
862 if (pThread)
863 {
864 rc = RTSemEventMultiWaitNoResume(pThread->EventUser, cMillies);
865 rtThreadRelease(pThread);
866 }
867 else
868 rc = VERR_INVALID_HANDLE;
869 return rc;
870}
871
872
873/**
874 * Reset the user event.
875 *
876 * @returns iprt status code.
877 * @param Thread The thread to reset.
878 */
879RTDECL(int) RTThreadUserReset(RTTHREAD Thread)
880{
881 int rc;
882 PRTTHREADINT pThread = rtThreadGet(Thread);
883 if (pThread)
884 {
885 rc = RTSemEventMultiReset(pThread->EventUser);
886 rtThreadRelease(pThread);
887 }
888 else
889 rc = VERR_INVALID_HANDLE;
890 return rc;
891}
892
893
894/**
895 * Wait for the thread to terminate.
896 *
897 * @returns iprt status code.
898 * @param Thread The thread to wait for.
899 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
900 * an indefinite wait.
901 * @param prc Where to store the return code of the thread. Optional.
902 * @param fAutoResume Whether or not to resume the wait on VERR_INTERRUPTED.
903 */
904static int rtThreadWait(RTTHREAD Thread, unsigned cMillies, int *prc, bool fAutoResume)
905{
906 int rc = VERR_INVALID_HANDLE;
907 if (Thread != NIL_RTTHREAD)
908 {
909 PRTTHREADINT pThread = rtThreadGet(Thread);
910 if (pThread)
911 {
912 if (pThread->fFlags & RTTHREADFLAGS_WAITABLE)
913 {
914 if (fAutoResume)
915 rc = RTSemEventMultiWait(pThread->EventTerminated, cMillies);
916 else
917 rc = RTSemEventMultiWaitNoResume(pThread->EventTerminated, cMillies);
918 if (RT_SUCCESS(rc))
919 {
920 if (prc)
921 *prc = pThread->rc;
922
923 /*
924 * If the thread is marked as waitable, we'll do one additional
925 * release in order to free up the thread structure (see how we
926 * init cRef in rtThreadAlloc()).
927 */
928 if (ASMAtomicBitTestAndClear(&pThread->fFlags, RTTHREADFLAGS_WAITABLE_BIT))
929 rtThreadRelease(pThread);
930 }
931 }
932 else
933 {
934 rc = VERR_THREAD_NOT_WAITABLE;
935 AssertRC(rc);
936 }
937 rtThreadRelease(pThread);
938 }
939 }
940 return rc;
941}
942
943
944/**
945 * Wait for the thread to terminate, resume on interruption.
946 *
947 * @returns iprt status code.
948 * Will not return VERR_INTERRUPTED.
949 * @param Thread The thread to wait for.
950 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
951 * an indefinite wait.
952 * @param prc Where to store the return code of the thread. Optional.
953 */
954RTDECL(int) RTThreadWait(RTTHREAD Thread, unsigned cMillies, int *prc)
955{
956 int rc = rtThreadWait(Thread, cMillies, prc, true);
957 Assert(rc != VERR_INTERRUPTED);
958 return rc;
959}
960
961
962/**
963 * Wait for the thread to terminate, return on interruption.
964 *
965 * @returns iprt status code.
966 * @param Thread The thread to wait for.
967 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
968 * an indefinite wait.
969 * @param prc Where to store the return code of the thread. Optional.
970 */
971RTDECL(int) RTThreadWaitNoResume(RTTHREAD Thread, unsigned cMillies, int *prc)
972{
973 return rtThreadWait(Thread, cMillies, prc, false);
974}
975
976
977/**
978 * Changes the type of the specified thread.
979 *
980 * @returns iprt status code.
981 * @param Thread The thread which type should be changed.
982 * @param enmType The new thread type.
983 */
984RTDECL(int) RTThreadSetType(RTTHREAD Thread, RTTHREADTYPE enmType)
985{
986 /*
987 * Validate input.
988 */
989 int rc;
990 if ( enmType > RTTHREADTYPE_INVALID
991 && enmType < RTTHREADTYPE_END)
992 {
993 PRTTHREADINT pThread = rtThreadGet(Thread);
994 if (pThread)
995 {
996 if (rtThreadIsAlive(pThread))
997 {
998 /*
999 * Do the job.
1000 */
1001 RT_THREAD_LOCK_TMP(Tmp);
1002 RT_THREAD_LOCK_RW(Tmp);
1003 rc = rtThreadNativeSetPriority(pThread, enmType);
1004 if (RT_SUCCESS(rc))
1005 ASMAtomicXchgSize(&pThread->enmType, enmType);
1006 RT_THREAD_UNLOCK_RW(Tmp);
1007 if (RT_FAILURE(rc))
1008 Log(("RTThreadSetType: failed on thread %p (%s), rc=%Vrc!!!\n", Thread, pThread->szName, rc));
1009 }
1010 else
1011 rc = VERR_THREAD_IS_DEAD;
1012 rtThreadRelease(pThread);
1013 }
1014 else
1015 rc = VERR_INVALID_HANDLE;
1016 }
1017 else
1018 {
1019 AssertMsgFailed(("enmType=%d\n", enmType));
1020 rc = VERR_INVALID_PARAMETER;
1021 }
1022 return rc;
1023}
1024
1025
1026/**
1027 * Gets the type of the specified thread.
1028 *
1029 * @returns The thread type.
1030 * @returns RTTHREADTYPE_INVALID if the thread handle is invalid.
1031 * @param Thread The thread in question.
1032 */
1033RTDECL(RTTHREADTYPE) RTThreadGetType(RTTHREAD Thread)
1034{
1035 RTTHREADTYPE enmType = RTTHREADTYPE_INVALID;
1036 PRTTHREADINT pThread = rtThreadGet(Thread);
1037 if (pThread)
1038 {
1039 enmType = pThread->enmType;
1040 rtThreadRelease(pThread);
1041 }
1042 return enmType;
1043}
1044
1045
1046#ifdef IN_RING3
1047
1048/**
1049 * Recalculates scheduling attributes for the the default process
1050 * priority using the specified priority type for the calling thread.
1051 *
1052 * The scheduling attributes are targeted at threads and they are protected
1053 * by the thread read-write semaphore, that's why RTProc is forwarding the
1054 * operation to RTThread.
1055 *
1056 * @returns iprt status code.
1057 */
1058int rtThreadDoCalcDefaultPriority(RTTHREADTYPE enmType)
1059{
1060 RT_THREAD_LOCK_TMP(Tmp);
1061 RT_THREAD_LOCK_RW(Tmp);
1062 int rc = rtSchedNativeCalcDefaultPriority(enmType);
1063 RT_THREAD_UNLOCK_RW(Tmp);
1064 return rc;
1065}
1066
1067
1068/**
1069 * Thread enumerator - sets the priority of one thread.
1070 *
1071 * @returns 0 to continue.
1072 * @returns !0 to stop. In our case a VERR_ code.
1073 * @param pNode The thread node.
1074 * @param pvUser The new priority.
1075 */
1076static DECLCALLBACK(int) rtThreadSetPriorityOne(PAVLPVNODECORE pNode, void *pvUser)
1077{
1078 PRTTHREADINT pThread = (PRTTHREADINT)pNode;
1079 if (!rtThreadIsAlive(pThread))
1080 return VINF_SUCCESS;
1081 int rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
1082 if (RT_SUCCESS(rc)) /* hide any warnings */
1083 return VINF_SUCCESS;
1084 return rc;
1085}
1086
1087
1088/**
1089 * Attempts to alter the priority of the current process.
1090 *
1091 * The scheduling attributes are targeted at threads and they are protected
1092 * by the thread read-write semaphore, that's why RTProc is forwarding the
1093 * operation to RTThread. This operation also involves updating all thread
1094 * which is much faster done from RTThread.
1095 *
1096 * @returns iprt status code.
1097 * @param enmPriority The new priority.
1098 */
1099int rtThreadDoSetProcPriority(RTPROCPRIORITY enmPriority)
1100{
1101 LogFlow(("rtThreadDoSetProcPriority: enmPriority=%d\n", enmPriority));
1102
1103 /*
1104 * First validate that we're allowed by the OS to use all the
1105 * scheduling attributes defined by the specified process priority.
1106 */
1107 RT_THREAD_LOCK_TMP(Tmp);
1108 RT_THREAD_LOCK_RW(Tmp);
1109 int rc = rtProcNativeSetPriority(enmPriority);
1110 if (RT_SUCCESS(rc))
1111 {
1112 /*
1113 * Update the priority of existing thread.
1114 */
1115 rc = RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
1116 if (RT_SUCCESS(rc))
1117 ASMAtomicXchgSize(&g_enmProcessPriority, enmPriority);
1118 else
1119 {
1120 /*
1121 * Failed, restore the priority.
1122 */
1123 rtProcNativeSetPriority(g_enmProcessPriority);
1124 RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
1125 }
1126 }
1127 RT_THREAD_UNLOCK_RW(Tmp);
1128 LogFlow(("rtThreadDoSetProcPriority: returns %Vrc\n", rc));
1129 return rc;
1130}
1131
1132
1133/**
1134 * Bitch about a deadlock.
1135 *
1136 * @param pThread This thread.
1137 * @param pCur The thread we're deadlocking with.
1138 * @param enmState The sleep state.
1139 * @param u64Block The block data. A pointer or handle.
1140 * @param pszFile Where we are gonna block.
1141 * @param uLine Where we are gonna block.
1142 * @param uId Where we are gonna block.
1143 */
1144static void rtThreadDeadlock(PRTTHREADINT pThread, PRTTHREADINT pCur, RTTHREADSTATE enmState, uint64_t u64Block,
1145 const char *pszFile, unsigned uLine, RTUINTPTR uId)
1146{
1147 AssertMsg1(pCur == pThread ? "!!Deadlock detected!!" : "!!Deadlock exists!!", uLine, pszFile, "");
1148
1149 /*
1150 * Print the threads and locks involved.
1151 */
1152 PRTTHREADINT apSeenThreads[8] = {0,0,0,0,0,0,0,0};
1153 unsigned iSeenThread = 0;
1154 pCur = pThread;
1155 for (unsigned iEntry = 0; pCur && iEntry < 256; iEntry++)
1156 {
1157 /*
1158 * Print info on pCur. Determin next while doing so.
1159 */
1160 AssertMsg2(" #%d: %RTthrd/%RTnthrd %s: %s(%u) %RTptr\n",
1161 iEntry, pCur, pCur->Core.Key, pCur->szName,
1162 pCur->pszBlockFile, pCur->uBlockLine, pCur->uBlockId);
1163 PRTTHREADINT pNext = NULL;
1164 switch (pCur->enmState)
1165 {
1166 case RTTHREADSTATE_CRITSECT:
1167 {
1168 PRTCRITSECT pCritSect = pCur->Block.pCritSect;
1169 if (pCur->enmState != RTTHREADSTATE_CRITSECT)
1170 {
1171 AssertMsg2("Impossible!!!\n");
1172 break;
1173 }
1174 if (VALID_PTR(pCritSect) && RTCritSectIsInitialized(pCritSect))
1175 {
1176 AssertMsg2(" Waiting on CRITSECT %p: Entered %s(%u) %RTptr\n",
1177 pCritSect, pCritSect->Strict.pszEnterFile,
1178 pCritSect->Strict.u32EnterLine, pCritSect->Strict.uEnterId);
1179 pNext = pCritSect->Strict.ThreadOwner;
1180 }
1181 else
1182 AssertMsg2(" Waiting on CRITSECT %p: invalid pointer or uninitialized critsect\n", pCritSect);
1183 break;
1184 }
1185
1186 default:
1187 AssertMsg2(" Impossible!!! enmState=%d\n", pCur->enmState);
1188 break;
1189 }
1190
1191 /*
1192 * Check for cycle.
1193 */
1194 if (iEntry && pCur == pThread)
1195 break;
1196 for (unsigned i = 0; i < ELEMENTS(apSeenThreads); i++)
1197 if (apSeenThreads[i] == pCur)
1198 {
1199 AssertMsg2(" Cycle!\n");
1200 pNext = NULL;
1201 break;
1202 }
1203
1204 /*
1205 * Advance to the next thread.
1206 */
1207 iSeenThread = (iSeenThread + 1) % ELEMENTS(apSeenThreads);
1208 apSeenThreads[iSeenThread] = pCur;
1209 pCur = pNext;
1210 }
1211 AssertBreakpoint();
1212}
1213
1214
1215/**
1216 * Change the thread state to blocking and do deadlock detection.
1217 *
1218 * This is a RT_STRICT method for debugging locks and detecting deadlocks.
1219 *
1220 * @param pThread This thread.
1221 * @param enmState The sleep state.
1222 * @param u64Block The block data. A pointer or handle.
1223 * @param pszFile Where we are blocking.
1224 * @param uLine Where we are blocking.
1225 * @param uId Where we are blocking.
1226 */
1227void rtThreadBlocking(PRTTHREADINT pThread, RTTHREADSTATE enmState, uint64_t u64Block,
1228 const char *pszFile, unsigned uLine, RTUINTPTR uId)
1229{
1230 Assert(RTTHREAD_IS_SLEEPING(enmState));
1231 if (pThread && pThread->enmState == RTTHREADSTATE_RUNNING)
1232 {
1233 /** @todo This has to be serialized! The deadlock detection isn't 100% safe!!! */
1234 pThread->Block.u64 = u64Block;
1235 pThread->pszBlockFile = pszFile;
1236 pThread->uBlockLine = uLine;
1237 pThread->uBlockId = uId;
1238 ASMAtomicXchgSize(&pThread->enmState, enmState);
1239
1240 /*
1241 * Do deadlock detection.
1242 *
1243 * Since we're missing proper serialization, we don't declare it a
1244 * deadlock until we've got three runs with the same list length.
1245 * While this isn't perfect, it should avoid out the most obvious
1246 * races on SMP boxes.
1247 */
1248 PRTTHREADINT pCur;
1249 unsigned cPrevLength = ~0U;
1250 unsigned cEqualRuns = 0;
1251 unsigned iParanoia = 256;
1252 do
1253 {
1254 unsigned cLength = 0;
1255 pCur = pThread;
1256 for (;;)
1257 {
1258 /*
1259 * Get the next thread.
1260 */
1261 for (;;)
1262 {
1263 switch (pCur->enmState)
1264 {
1265 case RTTHREADSTATE_CRITSECT:
1266 {
1267 PRTCRITSECT pCritSect = pCur->Block.pCritSect;
1268 if (pCur->enmState != RTTHREADSTATE_CRITSECT)
1269 continue;
1270 pCur = pCritSect->Strict.ThreadOwner;
1271 break;
1272 }
1273
1274 default:
1275 pCur = NULL;
1276 break;
1277 }
1278 break;
1279 }
1280 if (!pCur)
1281 return;
1282
1283 /*
1284 * If we've got back to the blocking thread id we've got a deadlock.
1285 * If we've got a chain of more than 256 items, there is some kind of cycle
1286 * in the list, which means that there is already a deadlock somewhere.
1287 */
1288 if (pCur == pThread || cLength >= 256)
1289 break;
1290 cLength++;
1291 }
1292
1293 /* compare with previous list run. */
1294 if (cLength != cPrevLength)
1295 {
1296 cPrevLength = cLength;
1297 cEqualRuns = 0;
1298 }
1299 else
1300 cEqualRuns++;
1301 } while (cEqualRuns < 3 && --iParanoia > 0);
1302
1303 /*
1304 * Ok, if we ever get here, it's most likely a genuine deadlock.
1305 */
1306 rtThreadDeadlock(pThread, pCur, enmState, u64Block, pszFile, uLine, uId);
1307 }
1308}
1309
1310
1311/**
1312 * Unblocks a thread.
1313 *
1314 * This function is paired with rtThreadBlocking.
1315 *
1316 * @param pThread The current thread.
1317 * @param enmCurState The current state, used to check for nested blocking.
1318 * The new state will be running.
1319 */
1320void rtThreadUnblocked(PRTTHREADINT pThread, RTTHREADSTATE enmCurState)
1321{
1322 if (pThread && pThread->enmState == enmCurState)
1323 ASMAtomicXchgSize(&pThread->enmState, RTTHREADSTATE_RUNNING);
1324}
1325
1326#endif /* IN_RING3 */
1327
1328
1329#ifdef IPRT_WITH_GENERIC_TLS
1330
1331/**
1332 * Thread enumerator - clears a TLS entry.
1333 *
1334 * @returns 0.
1335 * @param pNode The thread node.
1336 * @param pvUser The TLS index.
1337 */
1338static DECLCALLBACK(int) rtThreadClearTlsEntryCallback(PAVLPVNODECORE pNode, void *pvUser)
1339{
1340 PRTTHREADINT pThread = (PRTTHREADINT)pNode;
1341 RTTLS iTls = (RTTLS)(uintptr_t)pvUser;
1342 ASMAtomicWritePtr(&pThread->apvTlsEntries[iTls], NULL);
1343 return 0;
1344}
1345
1346
1347/**
1348 * Helper for the generic TLS implementation that clears a given TLS
1349 * entry on all threads.
1350 *
1351 * @param iTls The TLS entry. (valid)
1352 */
1353void rtThreadClearTlsEntry(RTTLS iTls)
1354{
1355 RT_THREAD_LOCK_TMP(Tmp);
1356 RT_THREAD_LOCK_RD(Tmp);
1357 RTAvlPVDoWithAll(&g_ThreadTree, true /* fFromLeft*/, rtThreadClearTlsEntryCallback, (void *)(uintptr_t)iTls);
1358 RT_THREAD_UNLOCK_RD(Tmp);
1359}
1360
1361#endif /* IPRT_WITH_GENERIC_TLS */
1362
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette