VirtualBox

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

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

IPRT: Fixed issue where RTCreateThread would race against the termination of the new thread, if RTCreateThread didn't manage to insert the thread before the new thread completed, we would be inserting a thread into the tree that was terminated and which native ID should not be in the tree. If the OS then reused the native thread ID immediately (OS/2 and now glibc/linux), we would end up with a duplicate in the tree and get all confused. The fix is to check the state in rtThreadInsert and never insert a terminated thread.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 45.6 KB
Line 
1/* $Id: thread.cpp 10792 2008-07-21 22:19:26Z vboxsync $ */
2/** @file
3 * IPRT - 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
201DECLINLINE(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
210DECLINLINE(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
219DECLINLINE(void) rtThreadUnLockRW(void)
220{
221 int rc = RTSemRWReleaseWrite(g_ThreadRWSem);
222 AssertReleaseRC(rc);
223}
224
225
226DECLINLINE(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 * (It is vital that rtThreadNativeAdopt updates the TLS before
247 * we try inserting the thread because of locking.)
248 */
249 int rc = VERR_NO_MEMORY;
250 PRTTHREADINT pThread = rtThreadAlloc(enmType, fFlags, RTTHREADINT_FLAGS_ALIEN, pszName);
251 if (pThread)
252 {
253 RTNATIVETHREAD NativeThread = RTThreadNativeSelf();
254 rc = rtThreadNativeAdopt(pThread);
255 if (RT_SUCCESS(rc))
256 {
257 rtThreadInsert(pThread, NativeThread);
258 ASMAtomicWriteSize(&pThread->enmState, RTTHREADSTATE_RUNNING);
259 rtThreadRelease(pThread);
260 }
261 }
262 return rc;
263}
264
265
266/**
267 * Adopts a non-IPRT thread.
268 *
269 * @returns IPRT status code.
270 * @param enmType The thread type.
271 * @param fFlags The thread flags. RTTHREADFLAGS_WAITABLE is not currently allowed.
272 * @param pszName The thread name. Optional.
273 * @param pThread Where to store the thread handle. Optional.
274 */
275RTDECL(int) RTThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, const char *pszName, PRTTHREAD pThread)
276{
277 AssertReturn(!(fFlags & RTTHREADFLAGS_WAITABLE), VERR_INVALID_PARAMETER);
278 AssertReturn(!pszName || VALID_PTR(pszName), VERR_INVALID_POINTER);
279 AssertReturn(!pThread || VALID_PTR(pThread), VERR_INVALID_POINTER);
280
281 int rc = VINF_SUCCESS;
282 RTTHREAD Thread = RTThreadSelf();
283 if (Thread == NIL_RTTHREAD)
284 {
285 /* generate a name if none was given. */
286 char szName[RTTHREAD_NAME_LEN];
287 if (!pszName || !*pszName)
288 {
289 static uint32_t s_i32AlienId = 0;
290 uint32_t i32Id = ASMAtomicIncU32(&s_i32AlienId);
291 RTStrPrintf(szName, sizeof(szName), "ALIEN-%RX32", i32Id);
292 pszName = szName;
293 }
294
295 /* try adopt it */
296 rc = rtThreadAdopt(enmType, fFlags, pszName);
297 Thread = RTThreadSelf();
298 Log(("RTThreadAdopt: %RTthrd %RTnthrd '%s' enmType=%d fFlags=%#x rc=%Rrc\n",
299 Thread, RTThreadNativeSelf(), pszName, enmType, fFlags, rc));
300 }
301 else
302 Log(("RTThreadAdopt: %RTthrd %RTnthrd '%s' enmType=%d fFlags=%#x - already adopted!\n",
303 Thread, RTThreadNativeSelf(), pszName, enmType, fFlags));
304
305 if (pThread)
306 *pThread = Thread;
307 return rc;
308}
309
310
311/**
312 * Allocates a per thread data structure and initializes the basic fields.
313 *
314 * @returns Pointer to per thread data structure.
315 * This is reference once.
316 * @returns NULL on failure.
317 * @param enmType The thread type.
318 * @param fFlags The thread flags.
319 * @param fIntFlags The internal thread flags.
320 * @param pszName Pointer to the thread name.
321 */
322PRTTHREADINT rtThreadAlloc(RTTHREADTYPE enmType, unsigned fFlags, unsigned fIntFlags, const char *pszName)
323{
324 PRTTHREADINT pThread = (PRTTHREADINT)RTMemAllocZ(sizeof(RTTHREADINT));
325 if (pThread)
326 {
327 pThread->Core.Key = (void*)NIL_RTTHREAD;
328 pThread->u32Magic = RTTHREADINT_MAGIC;
329 size_t cchName = strlen(pszName);
330 if (cchName >= RTTHREAD_NAME_LEN)
331 cchName = RTTHREAD_NAME_LEN - 1;
332 memcpy(pThread->szName, pszName, cchName);
333 pThread->szName[cchName] = '\0';
334 pThread->cRefs = 2 + !!(fFlags & RTTHREADFLAGS_WAITABLE); /* And extra reference if waitable. */
335 pThread->rc = VERR_PROCESS_RUNNING; /** @todo get a better error code! */
336 pThread->enmType = enmType;
337 pThread->fFlags = fFlags;
338 pThread->fIntFlags = fIntFlags;
339 pThread->enmState = RTTHREADSTATE_INITIALIZING;
340 int rc = RTSemEventMultiCreate(&pThread->EventUser);
341 if (RT_SUCCESS(rc))
342 {
343 rc = RTSemEventMultiCreate(&pThread->EventTerminated);
344 if (RT_SUCCESS(rc))
345 return pThread;
346 RTSemEventMultiDestroy(pThread->EventUser);
347 }
348 RTMemFree(pThread);
349 }
350 return NULL;
351}
352
353
354/**
355 * Insert the per thread data structure into the tree.
356 *
357 * This can be called from both the thread it self and the parent,
358 * thus it must handle insertion failures in a nice manner.
359 *
360 * @param pThread Pointer to thread structure allocated by rtThreadAlloc().
361 * @param NativeThread The native thread id.
362 */
363void rtThreadInsert(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread)
364{
365 Assert(pThread);
366 Assert(pThread->u32Magic == RTTHREADINT_MAGIC);
367
368 RT_THREAD_LOCK_TMP(Tmp);
369 RT_THREAD_LOCK_RW(Tmp);
370
371 /*
372 * Do not insert a terminated thread.
373 *
374 * This may happen if the thread finishes before the RTThreadCreate call
375 * gets this far. Since the OS may quickly reuse the native thread ID
376 * it should not be reinserted at this point.
377 */
378 if (pThread->enmState != RTTHREADSTATE_TERMINATED)
379 {
380 /*
381 * Before inserting we must check if there is a thread with this id
382 * in the tree already. We're racing parent and child on insert here
383 * so that the handle is valid in both ends when they return / start.
384 *
385 * If it's not ourself we find, it's a dead alien thread and we will
386 * unlink it from the tree. Alien threads will be released at this point.
387 */
388 PRTTHREADINT pThreadOther = (PRTTHREADINT)RTAvlPVGet(&g_ThreadTree, (void *)NativeThread);
389 if (pThreadOther != pThread)
390 {
391 /* remove dead alien if any */
392 if (pThreadOther)
393 {
394 AssertMsg(pThreadOther->fIntFlags & RTTHREADINT_FLAGS_ALIEN, ("%p:%s; %p:%s\n", pThread, pThread->szName, pThreadOther, pThreadOther->szName));
395 ASMAtomicBitClear(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT);
396 rtThreadRemoveLocked(pThreadOther);
397 if (pThreadOther->fIntFlags & RTTHREADINT_FLAGS_ALIEN)
398 rtThreadRelease(pThreadOther);
399 }
400
401 /* insert the thread */
402 ASMAtomicWritePtr(&pThread->Core.Key, (void *)NativeThread);
403 bool fRc = RTAvlPVInsert(&g_ThreadTree, &pThread->Core);
404 ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE);
405
406 AssertReleaseMsg(fRc, ("Lock problem? %p (%RTnthrd) %s\n", pThread, NativeThread, pThread->szName));
407 NOREF(fRc);
408 }
409 }
410
411 RT_THREAD_UNLOCK_RW(Tmp);
412}
413
414
415/**
416 * Removes the thread from the AVL tree, call owns the tree lock
417 * and has cleared the RTTHREADINT_FLAG_IN_TREE bit.
418 *
419 * @param pThread The thread to remove.
420 */
421static void rtThreadRemoveLocked(PRTTHREADINT pThread)
422{
423 PRTTHREADINT pThread2 = (PRTTHREADINT)RTAvlPVRemove(&g_ThreadTree, pThread->Core.Key);
424#ifndef RT_OS_OS2
425 /// @todo find out why it asserts on OS/2
426 AssertMsg(pThread2 == pThread, ("%p(%s) != %p (%p/%s)\n", pThread2, pThread2 ? pThread2->szName : "<null>",
427 pThread, pThread->Core.Key, pThread->szName));
428#endif
429 NOREF(pThread2);
430}
431
432
433/**
434 * Removes the thread from the AVL tree.
435 *
436 * @param pThread The thread to remove.
437 */
438static void rtThreadRemove(PRTTHREADINT pThread)
439{
440 RT_THREAD_LOCK_TMP(Tmp);
441 RT_THREAD_LOCK_RW(Tmp);
442 if (ASMAtomicBitTestAndClear(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT))
443 rtThreadRemoveLocked(pThread);
444 RT_THREAD_UNLOCK_RW(Tmp);
445}
446
447
448/**
449 * Checks if a thread is alive or not.
450 *
451 * @returns true if the thread is alive (or we don't really know).
452 * @returns false if the thread has surely terminate.
453 */
454DECLINLINE(bool) rtThreadIsAlive(PRTTHREADINT pThread)
455{
456 return !(pThread->fIntFlags & RTTHREADINT_FLAGS_TERMINATED);
457}
458
459
460/**
461 * Gets a thread by it's native ID.
462 *
463 * @returns pointer to the thread structure.
464 * @returns NULL if not a thread IPRT knows.
465 * @param NativeThread The native thread id.
466 */
467PRTTHREADINT rtThreadGetByNative(RTNATIVETHREAD NativeThread)
468{
469 /*
470 * Simple tree lookup.
471 */
472 RT_THREAD_LOCK_TMP(Tmp);
473 RT_THREAD_LOCK_RD(Tmp);
474 PRTTHREADINT pThread = (PRTTHREADINT)RTAvlPVGet(&g_ThreadTree, (void *)NativeThread);
475 RT_THREAD_UNLOCK_RD(Tmp);
476 return pThread;
477}
478
479
480/**
481 * Gets the per thread data structure for a thread handle.
482 *
483 * @returns Pointer to the per thread data structure for Thread.
484 * The caller must release the thread using rtThreadRelease().
485 * @returns NULL if Thread was not found.
486 * @param Thread Thread id which structure is to be returned.
487 */
488PRTTHREADINT rtThreadGet(RTTHREAD Thread)
489{
490 if ( Thread != NIL_RTTHREAD
491 && VALID_PTR(Thread))
492 {
493 PRTTHREADINT pThread = (PRTTHREADINT)Thread;
494 if ( pThread->u32Magic == RTTHREADINT_MAGIC
495 && pThread->cRefs > 0)
496 {
497 ASMAtomicIncU32(&pThread->cRefs);
498 return pThread;
499 }
500 }
501
502 AssertMsgFailed(("Thread=%RTthrd\n", Thread));
503 return NULL;
504}
505
506
507/**
508 * Release a per thread data structure.
509 *
510 * @returns New reference count.
511 * @param pThread The thread structure to release.
512 */
513uint32_t rtThreadRelease(PRTTHREADINT pThread)
514{
515 Assert(pThread);
516 uint32_t cRefs;
517 if (pThread->cRefs >= 1)
518 {
519 cRefs = ASMAtomicDecU32(&pThread->cRefs);
520 if (!cRefs)
521 rtThreadDestroy(pThread);
522 }
523 else
524 cRefs = 0;
525 return cRefs;
526}
527
528
529/**
530 * Destroys the per thread data.
531 *
532 * @param pThread The thread to destroy.
533 */
534static void rtThreadDestroy(PRTTHREADINT pThread)
535{
536 /*
537 * Remove it from the tree and mark it as dead.
538 *
539 * Threads that has seen rtThreadTerminate and should already have been
540 * removed from the tree. There is probably no thread that should
541 * require removing here. However, be careful making sure that cRefs
542 * isn't 0 if we do or we'll blow up because the strict locking code
543 * will be calling us back.
544 */
545 if (ASMBitTest(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT))
546 {
547 ASMAtomicIncU32(&pThread->cRefs);
548 rtThreadRemove(pThread);
549 ASMAtomicDecU32(&pThread->cRefs);
550 }
551 ASMAtomicXchgU32(&pThread->u32Magic, RTTHREADINT_MAGIC_DEAD);
552
553 /*
554 * Free resources.
555 */
556 ASMAtomicWritePtr(&pThread->Core.Key, (void *)NIL_RTTHREAD);
557 pThread->enmType = RTTHREADTYPE_INVALID;
558 RTSemEventMultiDestroy(pThread->EventUser);
559 pThread->EventUser = NIL_RTSEMEVENTMULTI;
560 if (pThread->EventTerminated != NIL_RTSEMEVENTMULTI)
561 {
562 RTSemEventMultiDestroy(pThread->EventTerminated);
563 pThread->EventTerminated = NIL_RTSEMEVENTMULTI;
564 }
565 RTMemFree(pThread);
566}
567
568
569/**
570 * Terminates the thread.
571 * Called by the thread wrapper function when the thread terminates.
572 *
573 * @param pThread The thread structure.
574 * @param rc The thread result code.
575 */
576void rtThreadTerminate(PRTTHREADINT pThread, int rc)
577{
578 Assert(pThread->cRefs >= 1);
579
580#ifdef IPRT_WITH_GENERIC_TLS
581 /*
582 * Destroy TLS entries.
583 */
584 rtThreadTlsDestruction(pThread);
585#endif /* IPRT_WITH_GENERIC_TLS */
586
587 /*
588 * Set the rc, mark it terminated and signal anyone waiting.
589 */
590 pThread->rc = rc;
591 ASMAtomicWriteSize(&pThread->enmState, RTTHREADSTATE_TERMINATED);
592 ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAGS_TERMINATED);
593 if (pThread->EventTerminated != NIL_RTSEMEVENTMULTI)
594 RTSemEventMultiSignal(pThread->EventTerminated);
595
596 /*
597 * Remove the thread from the tree so that there will be no
598 * key clashes in the AVL tree and release our reference to ourself.
599 */
600 rtThreadRemove(pThread);
601 rtThreadRelease(pThread);
602}
603
604
605/**
606 * The common thread main function.
607 * This is called by rtThreadNativeMain().
608 *
609 * @returns The status code of the thread.
610 * pThread is dereference by the thread before returning!
611 * @param pThread The thread structure.
612 * @param NativeThread The native thread id.
613 * @param pszThreadName The name of the thread (purely a dummy for backtrace).
614 */
615int rtThreadMain(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread, const char *pszThreadName)
616{
617 NOREF(pszThreadName);
618 rtThreadInsert(pThread, NativeThread);
619 Log(("rtThreadMain: Starting: pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
620 pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
621
622 /*
623 * Change the priority.
624 */
625 int rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
626#ifdef IN_RING3
627 AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d enmPriority=%d rc=%Vrc\n",
628 pThread, NativeThread, pThread->szName, pThread->enmType, g_enmProcessPriority, rc));
629#else
630 AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d rc=%Vrc\n",
631 pThread, NativeThread, pThread->szName, pThread->enmType, rc));
632#endif
633
634 /*
635 * Call thread function and terminate when it returns.
636 */
637 ASMAtomicWriteSize(&pThread->enmState, RTTHREADSTATE_RUNNING);
638 rc = pThread->pfnThread(pThread, pThread->pvUser);
639
640 Log(("rtThreadMain: Terminating: rc=%d pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
641 rc, pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
642 rtThreadTerminate(pThread, rc);
643 return rc;
644}
645
646
647/**
648 * Create a new thread.
649 *
650 * @returns iprt status code.
651 * @param pThread Where to store the thread handle to the new thread. (optional)
652 * @param pfnThread The thread function.
653 * @param pvUser User argument.
654 * @param cbStack The size of the stack for the new thread.
655 * Use 0 for the default stack size.
656 * @param enmType The thread type. Used for deciding scheduling attributes
657 * of the thread.
658 * @param fFlags Flags of the RTTHREADFLAGS type (ORed together).
659 * @param pszName Thread name.
660 */
661RTDECL(int) RTThreadCreate(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
662 RTTHREADTYPE enmType, unsigned fFlags, const char *pszName)
663{
664 LogFlow(("RTThreadCreate: pThread=%p pfnThread=%p pvUser=%p cbStack=%#x enmType=%d fFlags=%#x pszName=%p:{%s}\n",
665 pThread, pfnThread, pvUser, cbStack, enmType, fFlags, pszName, pszName));
666
667 /*
668 * Validate input.
669 */
670 if (!VALID_PTR(pThread) && pThread)
671 {
672 Assert(VALID_PTR(pThread));
673 return VERR_INVALID_PARAMETER;
674 }
675 if (!VALID_PTR(pfnThread))
676 {
677 Assert(VALID_PTR(pfnThread));
678 return VERR_INVALID_PARAMETER;
679 }
680 if (!pszName || !*pszName || strlen(pszName) >= RTTHREAD_NAME_LEN)
681 {
682 AssertMsgFailed(("pszName=%s (max len is %d because of logging)\n", pszName, RTTHREAD_NAME_LEN - 1));
683 return VERR_INVALID_PARAMETER;
684 }
685 if (fFlags & ~RTTHREADFLAGS_MASK)
686 {
687 AssertMsgFailed(("fFlags=%#x\n", fFlags));
688 return VERR_INVALID_PARAMETER;
689 }
690
691 /*
692 * Allocate thread argument.
693 */
694 int rc;
695 PRTTHREADINT pThreadInt = rtThreadAlloc(enmType, fFlags, 0, pszName);
696 if (pThreadInt)
697 {
698 pThreadInt->pfnThread = pfnThread;
699 pThreadInt->pvUser = pvUser;
700 pThreadInt->cbStack = cbStack;
701
702 RTNATIVETHREAD NativeThread;
703 rc = rtThreadNativeCreate(pThreadInt, &NativeThread);
704 if (RT_SUCCESS(rc))
705 {
706 rtThreadInsert(pThreadInt, NativeThread);
707 rtThreadRelease(pThreadInt);
708 Log(("RTThreadCreate: Created thread %p (%p) %s\n", pThreadInt, NativeThread, pszName));
709 if (pThread)
710 *pThread = pThreadInt;
711 return VINF_SUCCESS;
712 }
713
714 pThreadInt->cRefs = 1;
715 rtThreadRelease(pThreadInt);
716 }
717 else
718 rc = VERR_NO_TMP_MEMORY;
719 LogFlow(("RTThreadCreate: Failed to create thread, rc=%Vrc\n", rc));
720 AssertReleaseRC(rc);
721 return rc;
722}
723
724
725/**
726 * Gets the native thread id of a IPRT thread.
727 *
728 * @returns The native thread id.
729 * @param Thread The IPRT thread.
730 */
731RTDECL(RTNATIVETHREAD) RTThreadGetNative(RTTHREAD Thread)
732{
733 PRTTHREADINT pThread = rtThreadGet(Thread);
734 if (pThread)
735 {
736 RTNATIVETHREAD NativeThread = (RTNATIVETHREAD)pThread->Core.Key;
737 rtThreadRelease(pThread);
738 return NativeThread;
739 }
740 return NIL_RTNATIVETHREAD;
741}
742
743
744/**
745 * Gets the IPRT thread of a native thread.
746 *
747 * @returns The IPRT thread handle
748 * @returns NIL_RTTHREAD if not a thread known to IPRT.
749 * @param NativeThread The native thread handle/id.
750 */
751RTDECL(RTTHREAD) RTThreadFromNative(RTNATIVETHREAD NativeThread)
752{
753 PRTTHREADINT pThread = rtThreadGetByNative(NativeThread);
754 if (pThread)
755 return pThread;
756 return NIL_RTTHREAD;
757}
758
759
760/**
761 * Gets the name of the current thread thread.
762 *
763 * @returns Pointer to readonly name string.
764 * @returns NULL on failure.
765 */
766RTDECL(const char *) RTThreadSelfName(void)
767{
768 RTTHREAD Thread = RTThreadSelf();
769 if (Thread != NIL_RTTHREAD)
770 {
771 PRTTHREADINT pThread = rtThreadGet(Thread);
772 if (pThread)
773 {
774 const char *szName = pThread->szName;
775 rtThreadRelease(pThread);
776 return szName;
777 }
778 }
779 return NULL;
780}
781
782
783/**
784 * Gets the name of a thread.
785 *
786 * @returns Pointer to readonly name string.
787 * @returns NULL on failure.
788 * @param Thread Thread handle of the thread to query the name of.
789 */
790RTDECL(const char *) RTThreadGetName(RTTHREAD Thread)
791{
792 if (Thread == NIL_RTTHREAD)
793 return NULL;
794 PRTTHREADINT pThread = rtThreadGet(Thread);
795 if (pThread)
796 {
797 const char *szName = pThread->szName;
798 rtThreadRelease(pThread);
799 return szName;
800 }
801 return NULL;
802}
803
804
805/**
806 * Sets the name of a thread.
807 *
808 * @returns iprt status code.
809 * @param Thread Thread handle of the thread to query the name of.
810 * @param pszName The thread name.
811 */
812RTDECL(int) RTThreadSetName(RTTHREAD Thread, const char *pszName)
813{
814 /*
815 * Validate input.
816 */
817 size_t cchName = strlen(pszName);
818 if (cchName >= RTTHREAD_NAME_LEN)
819 {
820 AssertMsgFailed(("pszName=%s is too long, max is %d\n", pszName, RTTHREAD_NAME_LEN - 1));
821 return VERR_INVALID_PARAMETER;
822 }
823 PRTTHREADINT pThread = rtThreadGet(Thread);
824 if (!pThread)
825 return VERR_INVALID_HANDLE;
826
827 /*
828 * Update the name.
829 */
830 pThread->szName[cchName] = '\0'; /* paranoia */
831 memcpy(pThread->szName, pszName, cchName);
832 rtThreadRelease(pThread);
833 return VINF_SUCCESS;
834}
835
836
837/**
838 * Signal the user event.
839 *
840 * @returns iprt status code.
841 */
842RTDECL(int) RTThreadUserSignal(RTTHREAD Thread)
843{
844 int rc;
845 PRTTHREADINT pThread = rtThreadGet(Thread);
846 if (pThread)
847 {
848 rc = RTSemEventMultiSignal(pThread->EventUser);
849 rtThreadRelease(pThread);
850 }
851 else
852 rc = VERR_INVALID_HANDLE;
853 return rc;
854}
855
856
857/**
858 * Wait for the user event, resume 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) RTThreadUserWait(RTTHREAD Thread, unsigned cMillies)
866{
867 int rc;
868 PRTTHREADINT pThread = rtThreadGet(Thread);
869 if (pThread)
870 {
871 rc = RTSemEventMultiWait(pThread->EventUser, cMillies);
872 rtThreadRelease(pThread);
873 }
874 else
875 rc = VERR_INVALID_HANDLE;
876 return rc;
877}
878
879
880/**
881 * Wait for the user event, return on interruption.
882 *
883 * @returns iprt status code.
884 * @param Thread The thread to wait for.
885 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
886 * an indefinite wait.
887 */
888RTDECL(int) RTThreadUserWaitNoResume(RTTHREAD Thread, unsigned cMillies)
889{
890 int rc;
891 PRTTHREADINT pThread = rtThreadGet(Thread);
892 if (pThread)
893 {
894 rc = RTSemEventMultiWaitNoResume(pThread->EventUser, cMillies);
895 rtThreadRelease(pThread);
896 }
897 else
898 rc = VERR_INVALID_HANDLE;
899 return rc;
900}
901
902
903/**
904 * Reset the user event.
905 *
906 * @returns iprt status code.
907 * @param Thread The thread to reset.
908 */
909RTDECL(int) RTThreadUserReset(RTTHREAD Thread)
910{
911 int rc;
912 PRTTHREADINT pThread = rtThreadGet(Thread);
913 if (pThread)
914 {
915 rc = RTSemEventMultiReset(pThread->EventUser);
916 rtThreadRelease(pThread);
917 }
918 else
919 rc = VERR_INVALID_HANDLE;
920 return rc;
921}
922
923
924/**
925 * Wait for the thread to terminate.
926 *
927 * @returns iprt status code.
928 * @param Thread The thread to wait for.
929 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
930 * an indefinite wait.
931 * @param prc Where to store the return code of the thread. Optional.
932 * @param fAutoResume Whether or not to resume the wait on VERR_INTERRUPTED.
933 */
934static int rtThreadWait(RTTHREAD Thread, unsigned cMillies, int *prc, bool fAutoResume)
935{
936 int rc = VERR_INVALID_HANDLE;
937 if (Thread != NIL_RTTHREAD)
938 {
939 PRTTHREADINT pThread = rtThreadGet(Thread);
940 if (pThread)
941 {
942 if (pThread->fFlags & RTTHREADFLAGS_WAITABLE)
943 {
944 if (fAutoResume)
945 rc = RTSemEventMultiWait(pThread->EventTerminated, cMillies);
946 else
947 rc = RTSemEventMultiWaitNoResume(pThread->EventTerminated, cMillies);
948 if (RT_SUCCESS(rc))
949 {
950 if (prc)
951 *prc = pThread->rc;
952
953 /*
954 * If the thread is marked as waitable, we'll do one additional
955 * release in order to free up the thread structure (see how we
956 * init cRef in rtThreadAlloc()).
957 */
958 if (ASMAtomicBitTestAndClear(&pThread->fFlags, RTTHREADFLAGS_WAITABLE_BIT))
959 rtThreadRelease(pThread);
960 }
961 }
962 else
963 {
964 rc = VERR_THREAD_NOT_WAITABLE;
965 AssertRC(rc);
966 }
967 rtThreadRelease(pThread);
968 }
969 }
970 return rc;
971}
972
973
974/**
975 * Wait for the thread to terminate, resume on interruption.
976 *
977 * @returns iprt status code.
978 * Will not return VERR_INTERRUPTED.
979 * @param Thread The thread to wait for.
980 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
981 * an indefinite wait.
982 * @param prc Where to store the return code of the thread. Optional.
983 */
984RTDECL(int) RTThreadWait(RTTHREAD Thread, unsigned cMillies, int *prc)
985{
986 int rc = rtThreadWait(Thread, cMillies, prc, true);
987 Assert(rc != VERR_INTERRUPTED);
988 return rc;
989}
990
991
992/**
993 * Wait for the thread to terminate, return on interruption.
994 *
995 * @returns iprt status code.
996 * @param Thread The thread to wait for.
997 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
998 * an indefinite wait.
999 * @param prc Where to store the return code of the thread. Optional.
1000 */
1001RTDECL(int) RTThreadWaitNoResume(RTTHREAD Thread, unsigned cMillies, int *prc)
1002{
1003 return rtThreadWait(Thread, cMillies, prc, false);
1004}
1005
1006
1007/**
1008 * Changes the type of the specified thread.
1009 *
1010 * @returns iprt status code.
1011 * @param Thread The thread which type should be changed.
1012 * @param enmType The new thread type.
1013 */
1014RTDECL(int) RTThreadSetType(RTTHREAD Thread, RTTHREADTYPE enmType)
1015{
1016 /*
1017 * Validate input.
1018 */
1019 int rc;
1020 if ( enmType > RTTHREADTYPE_INVALID
1021 && enmType < RTTHREADTYPE_END)
1022 {
1023 PRTTHREADINT pThread = rtThreadGet(Thread);
1024 if (pThread)
1025 {
1026 if (rtThreadIsAlive(pThread))
1027 {
1028 /*
1029 * Do the job.
1030 */
1031 RT_THREAD_LOCK_TMP(Tmp);
1032 RT_THREAD_LOCK_RW(Tmp);
1033 rc = rtThreadNativeSetPriority(pThread, enmType);
1034 if (RT_SUCCESS(rc))
1035 ASMAtomicXchgSize(&pThread->enmType, enmType);
1036 RT_THREAD_UNLOCK_RW(Tmp);
1037 if (RT_FAILURE(rc))
1038 Log(("RTThreadSetType: failed on thread %p (%s), rc=%Vrc!!!\n", Thread, pThread->szName, rc));
1039 }
1040 else
1041 rc = VERR_THREAD_IS_DEAD;
1042 rtThreadRelease(pThread);
1043 }
1044 else
1045 rc = VERR_INVALID_HANDLE;
1046 }
1047 else
1048 {
1049 AssertMsgFailed(("enmType=%d\n", enmType));
1050 rc = VERR_INVALID_PARAMETER;
1051 }
1052 return rc;
1053}
1054
1055
1056/**
1057 * Gets the type of the specified thread.
1058 *
1059 * @returns The thread type.
1060 * @returns RTTHREADTYPE_INVALID if the thread handle is invalid.
1061 * @param Thread The thread in question.
1062 */
1063RTDECL(RTTHREADTYPE) RTThreadGetType(RTTHREAD Thread)
1064{
1065 RTTHREADTYPE enmType = RTTHREADTYPE_INVALID;
1066 PRTTHREADINT pThread = rtThreadGet(Thread);
1067 if (pThread)
1068 {
1069 enmType = pThread->enmType;
1070 rtThreadRelease(pThread);
1071 }
1072 return enmType;
1073}
1074
1075
1076#ifdef IN_RING3
1077
1078/**
1079 * Gets the number of write locks and critical sections the specified
1080 * thread owns.
1081 *
1082 * This number does not include any nested lock/critect entries.
1083 *
1084 * Note that it probably will return 0 for non-strict builds since
1085 * release builds doesn't do unnecessary diagnostic counting like this.
1086 *
1087 * @returns Number of locks on success (0+) and VERR_INVALID_HANDLER on failure
1088 * @param Thread The thread we're inquiring about.
1089 */
1090RTDECL(int32_t) RTThreadGetWriteLockCount(RTTHREAD Thread)
1091{
1092 if (Thread == NIL_RTTHREAD)
1093 return 0;
1094
1095 PRTTHREADINT pThread = rtThreadGet(Thread);
1096 if (!pThread)
1097 return VERR_INVALID_HANDLE;
1098 int32_t cWriteLocks = ASMAtomicReadS32(&pThread->cWriteLocks);
1099 rtThreadRelease(pThread);
1100 return cWriteLocks;
1101}
1102
1103
1104/**
1105 * Works the THREADINT::cWriteLocks member, mostly internal.
1106 *
1107 * @param Thread The current thread.
1108 */
1109RTDECL(void) RTThreadWriteLockInc(RTTHREAD Thread)
1110{
1111 PRTTHREADINT pThread = rtThreadGet(Thread);
1112 Assert(pThread);
1113 ASMAtomicIncS32(&pThread->cWriteLocks);
1114 rtThreadRelease(pThread);
1115}
1116
1117
1118/**
1119 * Works the THREADINT::cWriteLocks member, mostly internal.
1120 *
1121 * @param Thread The current thread.
1122 */
1123RTDECL(void) RTThreadWriteLockDec(RTTHREAD Thread)
1124{
1125 PRTTHREADINT pThread = rtThreadGet(Thread);
1126 Assert(pThread);
1127 ASMAtomicDecS32(&pThread->cWriteLocks);
1128 rtThreadRelease(pThread);
1129}
1130
1131
1132/**
1133 * Gets the number of read locks the specified thread owns.
1134 *
1135 * Note that nesting read lock entry will be included in the
1136 * total sum. And that it probably will return 0 for non-strict
1137 * builds since release builds doesn't do unnecessary diagnostic
1138 * counting like this.
1139 *
1140 * @returns Number of read locks on success (0+) and VERR_INVALID_HANDLER on failure
1141 * @param Thread The thread we're inquiring about.
1142 */
1143RTDECL(int32_t) RTThreadGetReadLockCount(RTTHREAD Thread)
1144{
1145 if (Thread == NIL_RTTHREAD)
1146 return 0;
1147
1148 PRTTHREADINT pThread = rtThreadGet(Thread);
1149 if (!pThread)
1150 return VERR_INVALID_HANDLE;
1151 int32_t cReadLocks = ASMAtomicReadS32(&pThread->cReadLocks);
1152 rtThreadRelease(pThread);
1153 return cReadLocks;
1154}
1155
1156
1157/**
1158 * Works the THREADINT::cReadLocks member.
1159 *
1160 * @param Thread The current thread.
1161 */
1162RTDECL(void) RTThreadReadLockInc(RTTHREAD Thread)
1163{
1164 PRTTHREADINT pThread = rtThreadGet(Thread);
1165 Assert(pThread);
1166 ASMAtomicIncS32(&pThread->cReadLocks);
1167 rtThreadRelease(pThread);
1168}
1169
1170
1171/**
1172 * Works the THREADINT::cReadLocks member.
1173 *
1174 * @param Thread The current thread.
1175 */
1176RTDECL(void) RTThreadReadLockDec(RTTHREAD Thread)
1177{
1178 PRTTHREADINT pThread = rtThreadGet(Thread);
1179 Assert(pThread);
1180 ASMAtomicDecS32(&pThread->cReadLocks);
1181 rtThreadRelease(pThread);
1182}
1183
1184
1185
1186
1187
1188/**
1189 * Recalculates scheduling attributes for the the default process
1190 * priority using the specified priority type for the calling thread.
1191 *
1192 * The scheduling attributes are targeted at threads and they are protected
1193 * by the thread read-write semaphore, that's why RTProc is forwarding the
1194 * operation to RTThread.
1195 *
1196 * @returns iprt status code.
1197 * @remarks Will only work for strict builds.
1198 */
1199int rtThreadDoCalcDefaultPriority(RTTHREADTYPE enmType)
1200{
1201 RT_THREAD_LOCK_TMP(Tmp);
1202 RT_THREAD_LOCK_RW(Tmp);
1203 int rc = rtSchedNativeCalcDefaultPriority(enmType);
1204 RT_THREAD_UNLOCK_RW(Tmp);
1205 return rc;
1206}
1207
1208
1209/**
1210 * Thread enumerator - sets the priority of one thread.
1211 *
1212 * @returns 0 to continue.
1213 * @returns !0 to stop. In our case a VERR_ code.
1214 * @param pNode The thread node.
1215 * @param pvUser The new priority.
1216 */
1217static DECLCALLBACK(int) rtThreadSetPriorityOne(PAVLPVNODECORE pNode, void *pvUser)
1218{
1219 PRTTHREADINT pThread = (PRTTHREADINT)pNode;
1220 if (!rtThreadIsAlive(pThread))
1221 return VINF_SUCCESS;
1222 int rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
1223 if (RT_SUCCESS(rc)) /* hide any warnings */
1224 return VINF_SUCCESS;
1225 return rc;
1226}
1227
1228
1229/**
1230 * Attempts to alter the priority of the current process.
1231 *
1232 * The scheduling attributes are targeted at threads and they are protected
1233 * by the thread read-write semaphore, that's why RTProc is forwarding the
1234 * operation to RTThread. This operation also involves updating all thread
1235 * which is much faster done from RTThread.
1236 *
1237 * @returns iprt status code.
1238 * @param enmPriority The new priority.
1239 */
1240int rtThreadDoSetProcPriority(RTPROCPRIORITY enmPriority)
1241{
1242 LogFlow(("rtThreadDoSetProcPriority: enmPriority=%d\n", enmPriority));
1243
1244 /*
1245 * First validate that we're allowed by the OS to use all the
1246 * scheduling attributes defined by the specified process priority.
1247 */
1248 RT_THREAD_LOCK_TMP(Tmp);
1249 RT_THREAD_LOCK_RW(Tmp);
1250 int rc = rtProcNativeSetPriority(enmPriority);
1251 if (RT_SUCCESS(rc))
1252 {
1253 /*
1254 * Update the priority of existing thread.
1255 */
1256 rc = RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
1257 if (RT_SUCCESS(rc))
1258 ASMAtomicXchgSize(&g_enmProcessPriority, enmPriority);
1259 else
1260 {
1261 /*
1262 * Failed, restore the priority.
1263 */
1264 rtProcNativeSetPriority(g_enmProcessPriority);
1265 RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
1266 }
1267 }
1268 RT_THREAD_UNLOCK_RW(Tmp);
1269 LogFlow(("rtThreadDoSetProcPriority: returns %Vrc\n", rc));
1270 return rc;
1271}
1272
1273
1274/**
1275 * Bitch about a deadlock.
1276 *
1277 * @param pThread This thread.
1278 * @param pCur The thread we're deadlocking with.
1279 * @param enmState The sleep state.
1280 * @param u64Block The block data. A pointer or handle.
1281 * @param pszFile Where we are gonna block.
1282 * @param uLine Where we are gonna block.
1283 * @param uId Where we are gonna block.
1284 */
1285static void rtThreadDeadlock(PRTTHREADINT pThread, PRTTHREADINT pCur, RTTHREADSTATE enmState, uint64_t u64Block,
1286 const char *pszFile, unsigned uLine, RTUINTPTR uId)
1287{
1288 AssertMsg1(pCur == pThread ? "!!Deadlock detected!!" : "!!Deadlock exists!!", uLine, pszFile, "");
1289
1290 /*
1291 * Print the threads and locks involved.
1292 */
1293 PRTTHREADINT apSeenThreads[8] = {0,0,0,0,0,0,0,0};
1294 unsigned iSeenThread = 0;
1295 pCur = pThread;
1296 for (unsigned iEntry = 0; pCur && iEntry < 256; iEntry++)
1297 {
1298 /*
1299 * Print info on pCur. Determin next while doing so.
1300 */
1301 AssertMsg2(" #%d: %RTthrd/%RTnthrd %s: %s(%u) %RTptr\n",
1302 iEntry, pCur, pCur->Core.Key, pCur->szName,
1303 pCur->pszBlockFile, pCur->uBlockLine, pCur->uBlockId);
1304 PRTTHREADINT pNext = NULL;
1305 switch (pCur->enmState)
1306 {
1307 case RTTHREADSTATE_CRITSECT:
1308 {
1309 PRTCRITSECT pCritSect = pCur->Block.pCritSect;
1310 if (pCur->enmState != RTTHREADSTATE_CRITSECT)
1311 {
1312 AssertMsg2("Impossible!!!\n");
1313 break;
1314 }
1315 if (VALID_PTR(pCritSect) && RTCritSectIsInitialized(pCritSect))
1316 {
1317 AssertMsg2(" Waiting on CRITSECT %p: Entered %s(%u) %RTptr\n",
1318 pCritSect, pCritSect->Strict.pszEnterFile,
1319 pCritSect->Strict.u32EnterLine, pCritSect->Strict.uEnterId);
1320 pNext = pCritSect->Strict.ThreadOwner;
1321 }
1322 else
1323 AssertMsg2(" Waiting on CRITSECT %p: invalid pointer or uninitialized critsect\n", pCritSect);
1324 break;
1325 }
1326
1327 default:
1328 AssertMsg2(" Impossible!!! enmState=%d\n", pCur->enmState);
1329 break;
1330 }
1331
1332 /*
1333 * Check for cycle.
1334 */
1335 if (iEntry && pCur == pThread)
1336 break;
1337 for (unsigned i = 0; i < ELEMENTS(apSeenThreads); i++)
1338 if (apSeenThreads[i] == pCur)
1339 {
1340 AssertMsg2(" Cycle!\n");
1341 pNext = NULL;
1342 break;
1343 }
1344
1345 /*
1346 * Advance to the next thread.
1347 */
1348 iSeenThread = (iSeenThread + 1) % ELEMENTS(apSeenThreads);
1349 apSeenThreads[iSeenThread] = pCur;
1350 pCur = pNext;
1351 }
1352 AssertBreakpoint();
1353}
1354
1355
1356/**
1357 * Change the thread state to blocking and do deadlock detection.
1358 *
1359 * This is a RT_STRICT method for debugging locks and detecting deadlocks.
1360 *
1361 * @param pThread This thread.
1362 * @param enmState The sleep state.
1363 * @param u64Block The block data. A pointer or handle.
1364 * @param pszFile Where we are blocking.
1365 * @param uLine Where we are blocking.
1366 * @param uId Where we are blocking.
1367 */
1368void rtThreadBlocking(PRTTHREADINT pThread, RTTHREADSTATE enmState, uint64_t u64Block,
1369 const char *pszFile, unsigned uLine, RTUINTPTR uId)
1370{
1371 Assert(RTTHREAD_IS_SLEEPING(enmState));
1372 if (pThread && pThread->enmState == RTTHREADSTATE_RUNNING)
1373 {
1374 /** @todo This has to be serialized! The deadlock detection isn't 100% safe!!! */
1375 pThread->Block.u64 = u64Block;
1376 pThread->pszBlockFile = pszFile;
1377 pThread->uBlockLine = uLine;
1378 pThread->uBlockId = uId;
1379 ASMAtomicWriteSize(&pThread->enmState, enmState);
1380
1381 /*
1382 * Do deadlock detection.
1383 *
1384 * Since we're missing proper serialization, we don't declare it a
1385 * deadlock until we've got three runs with the same list length.
1386 * While this isn't perfect, it should avoid out the most obvious
1387 * races on SMP boxes.
1388 */
1389 PRTTHREADINT pCur;
1390 unsigned cPrevLength = ~0U;
1391 unsigned cEqualRuns = 0;
1392 unsigned iParanoia = 256;
1393 do
1394 {
1395 unsigned cLength = 0;
1396 pCur = pThread;
1397 for (;;)
1398 {
1399 /*
1400 * Get the next thread.
1401 */
1402 for (;;)
1403 {
1404 switch (pCur->enmState)
1405 {
1406 case RTTHREADSTATE_CRITSECT:
1407 {
1408 PRTCRITSECT pCritSect = pCur->Block.pCritSect;
1409 if (pCur->enmState != RTTHREADSTATE_CRITSECT)
1410 continue;
1411 pCur = pCritSect->Strict.ThreadOwner;
1412 break;
1413 }
1414
1415 default:
1416 pCur = NULL;
1417 break;
1418 }
1419 break;
1420 }
1421 if (!pCur)
1422 return;
1423
1424 /*
1425 * If we've got back to the blocking thread id we've got a deadlock.
1426 * If we've got a chain of more than 256 items, there is some kind of cycle
1427 * in the list, which means that there is already a deadlock somewhere.
1428 */
1429 if (pCur == pThread || cLength >= 256)
1430 break;
1431 cLength++;
1432 }
1433
1434 /* compare with previous list run. */
1435 if (cLength != cPrevLength)
1436 {
1437 cPrevLength = cLength;
1438 cEqualRuns = 0;
1439 }
1440 else
1441 cEqualRuns++;
1442 } while (cEqualRuns < 3 && --iParanoia > 0);
1443
1444 /*
1445 * Ok, if we ever get here, it's most likely a genuine deadlock.
1446 */
1447 rtThreadDeadlock(pThread, pCur, enmState, u64Block, pszFile, uLine, uId);
1448 }
1449}
1450
1451
1452/**
1453 * Unblocks a thread.
1454 *
1455 * This function is paired with rtThreadBlocking.
1456 *
1457 * @param pThread The current thread.
1458 * @param enmCurState The current state, used to check for nested blocking.
1459 * The new state will be running.
1460 */
1461void rtThreadUnblocked(PRTTHREADINT pThread, RTTHREADSTATE enmCurState)
1462{
1463 if (pThread && pThread->enmState == enmCurState)
1464 ASMAtomicWriteSize(&pThread->enmState, RTTHREADSTATE_RUNNING);
1465}
1466
1467#endif /* IN_RING3 */
1468
1469
1470#ifdef IPRT_WITH_GENERIC_TLS
1471
1472/**
1473 * Thread enumerator - clears a TLS entry.
1474 *
1475 * @returns 0.
1476 * @param pNode The thread node.
1477 * @param pvUser The TLS index.
1478 */
1479static DECLCALLBACK(int) rtThreadClearTlsEntryCallback(PAVLPVNODECORE pNode, void *pvUser)
1480{
1481 PRTTHREADINT pThread = (PRTTHREADINT)pNode;
1482 RTTLS iTls = (RTTLS)(uintptr_t)pvUser;
1483 ASMAtomicWritePtr(&pThread->apvTlsEntries[iTls], NULL);
1484 return 0;
1485}
1486
1487
1488/**
1489 * Helper for the generic TLS implementation that clears a given TLS
1490 * entry on all threads.
1491 *
1492 * @param iTls The TLS entry. (valid)
1493 */
1494void rtThreadClearTlsEntry(RTTLS iTls)
1495{
1496 RT_THREAD_LOCK_TMP(Tmp);
1497 RT_THREAD_LOCK_RD(Tmp);
1498 RTAvlPVDoWithAll(&g_ThreadTree, true /* fFromLeft*/, rtThreadClearTlsEntryCallback, (void *)(uintptr_t)iTls);
1499 RT_THREAD_UNLOCK_RD(Tmp);
1500}
1501
1502#endif /* IPRT_WITH_GENERIC_TLS */
1503
Note: See TracBrowser for help on using the repository browser.

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