VirtualBox

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

Last change on this file since 34917 was 34256, checked in by vboxsync, 14 years ago

IPRT: Must clear the TLS entry holding RTTHREAD before freeing the structure or the electric fence heap may cause a crash when blocking.

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