VirtualBox

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

Last change on this file since 14398 was 14298, checked in by vboxsync, 16 years ago

Corrected a couple of grammos.

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