VirtualBox

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

Last change on this file since 20364 was 20273, checked in by vboxsync, 16 years ago

Runtime/thread: paranoia check in strict builds for held rwsem locks on thread termination

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

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