VirtualBox

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

Last change on this file since 25368 was 25368, checked in by vboxsync, 15 years ago

RTCritSect,PDMCritSect,iprt/lockvalidator.h: Reworked the deadlocking detection for critical sections and preparing for lock order validation. This change generalizes the RTCRITSECT::Strict data and moves it out of the RTCRITSECT, leaving a pointer behind. This saves a bit of space in release builds.

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