VirtualBox

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

Last change on this file since 8217 was 8196, checked in by vboxsync, 17 years ago

OS/2: Temporarily disabled assertion that crashes debug builds.

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