VirtualBox

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

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

iprt/asm.h,*: Added ASMAtomicWriteNullPtr and ASMAtomicUoWriteNullPtr to better deal with NULL being 0 in C++.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 44.8 KB
Line 
1/* $Id: thread.cpp 30112 2010-06-09 12:31:50Z 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 RTMemFree(pThread);
607}
608
609
610/**
611 * Terminates the thread.
612 * Called by the thread wrapper function when the thread terminates.
613 *
614 * @param pThread The thread structure.
615 * @param rc The thread result code.
616 */
617void rtThreadTerminate(PRTTHREADINT pThread, int rc)
618{
619 Assert(pThread->cRefs >= 1);
620
621#ifdef IPRT_WITH_GENERIC_TLS
622 /*
623 * Destroy TLS entries.
624 */
625 rtThreadTlsDestruction(pThread);
626#endif /* IPRT_WITH_GENERIC_TLS */
627
628 /*
629 * Set the rc, mark it terminated and signal anyone waiting.
630 */
631 pThread->rc = rc;
632 rtThreadSetState(pThread, RTTHREADSTATE_TERMINATED);
633 ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAGS_TERMINATED);
634 if (pThread->EventTerminated != NIL_RTSEMEVENTMULTI)
635 RTSemEventMultiSignal(pThread->EventTerminated);
636
637 /*
638 * Remove the thread from the tree so that there will be no
639 * key clashes in the AVL tree and release our reference to ourself.
640 */
641 rtThreadRemove(pThread);
642 rtThreadRelease(pThread);
643}
644
645
646/**
647 * The common thread main function.
648 * This is called by rtThreadNativeMain().
649 *
650 * @returns The status code of the thread.
651 * pThread is dereference by the thread before returning!
652 * @param pThread The thread structure.
653 * @param NativeThread The native thread id.
654 * @param pszThreadName The name of the thread (purely a dummy for backtrace).
655 */
656int rtThreadMain(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread, const char *pszThreadName)
657{
658 NOREF(pszThreadName);
659 rtThreadInsert(pThread, NativeThread);
660 Log(("rtThreadMain: Starting: pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
661 pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
662
663 /*
664 * Change the priority.
665 */
666 int rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
667#ifdef IN_RING3
668 AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d enmPriority=%d rc=%Rrc\n",
669 pThread, NativeThread, pThread->szName, pThread->enmType, g_enmProcessPriority, rc));
670#else
671 AssertMsgRC(rc, ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d rc=%Rrc\n",
672 pThread, NativeThread, pThread->szName, pThread->enmType, rc));
673#endif
674
675 /*
676 * Call thread function and terminate when it returns.
677 */
678 rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
679 rc = pThread->pfnThread(pThread, pThread->pvUser);
680
681 /*
682 * Paranoia checks for leftover resources.
683 */
684#ifdef RTSEMRW_STRICT
685 int32_t cWrite = ASMAtomicReadS32(&pThread->cWriteLocks);
686 Assert(!cWrite);
687 int32_t cRead = ASMAtomicReadS32(&pThread->cReadLocks);
688 Assert(!cRead);
689#endif
690
691 Log(("rtThreadMain: Terminating: rc=%d pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n",
692 rc, pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
693 rtThreadTerminate(pThread, rc);
694 return rc;
695}
696
697
698/**
699 * Create a new thread.
700 *
701 * @returns iprt status code.
702 * @param pThread Where to store the thread handle to the new thread. (optional)
703 * @param pfnThread The thread function.
704 * @param pvUser User argument.
705 * @param cbStack The size of the stack for the new thread.
706 * Use 0 for the default stack size.
707 * @param enmType The thread type. Used for deciding scheduling attributes
708 * of the thread.
709 * @param fFlags Flags of the RTTHREADFLAGS type (ORed together).
710 * @param pszName Thread name.
711 */
712RTDECL(int) RTThreadCreate(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
713 RTTHREADTYPE enmType, unsigned fFlags, const char *pszName)
714{
715 LogFlow(("RTThreadCreate: pThread=%p pfnThread=%p pvUser=%p cbStack=%#x enmType=%d fFlags=%#x pszName=%p:{%s}\n",
716 pThread, pfnThread, pvUser, cbStack, enmType, fFlags, pszName, pszName));
717
718 /*
719 * Validate input.
720 */
721 if (!VALID_PTR(pThread) && pThread)
722 {
723 Assert(VALID_PTR(pThread));
724 return VERR_INVALID_PARAMETER;
725 }
726 if (!VALID_PTR(pfnThread))
727 {
728 Assert(VALID_PTR(pfnThread));
729 return VERR_INVALID_PARAMETER;
730 }
731 if (!pszName || !*pszName || strlen(pszName) >= RTTHREAD_NAME_LEN)
732 {
733 AssertMsgFailed(("pszName=%s (max len is %d because of logging)\n", pszName, RTTHREAD_NAME_LEN - 1));
734 return VERR_INVALID_PARAMETER;
735 }
736 if (fFlags & ~RTTHREADFLAGS_MASK)
737 {
738 AssertMsgFailed(("fFlags=%#x\n", fFlags));
739 return VERR_INVALID_PARAMETER;
740 }
741
742 /*
743 * Allocate thread argument.
744 */
745 int rc;
746 PRTTHREADINT pThreadInt = rtThreadAlloc(enmType, fFlags, 0, pszName);
747 if (pThreadInt)
748 {
749 pThreadInt->pfnThread = pfnThread;
750 pThreadInt->pvUser = pvUser;
751 pThreadInt->cbStack = cbStack;
752
753 RTNATIVETHREAD NativeThread;
754 rc = rtThreadNativeCreate(pThreadInt, &NativeThread);
755 if (RT_SUCCESS(rc))
756 {
757 rtThreadInsert(pThreadInt, NativeThread);
758 rtThreadRelease(pThreadInt);
759 Log(("RTThreadCreate: Created thread %p (%p) %s\n", pThreadInt, NativeThread, pszName));
760 if (pThread)
761 *pThread = pThreadInt;
762 return VINF_SUCCESS;
763 }
764
765 pThreadInt->cRefs = 1;
766 rtThreadRelease(pThreadInt);
767 }
768 else
769 rc = VERR_NO_TMP_MEMORY;
770 LogFlow(("RTThreadCreate: Failed to create thread, rc=%Rrc\n", rc));
771 AssertReleaseRC(rc);
772 return rc;
773}
774RT_EXPORT_SYMBOL(RTThreadCreate);
775
776
777/**
778 * Create a new thread.
779 *
780 * Same as RTThreadCreate except the name is given in the RTStrPrintfV form.
781 *
782 * @returns iprt status code.
783 * @param pThread See RTThreadCreate.
784 * @param pfnThread See RTThreadCreate.
785 * @param pvUser See RTThreadCreate.
786 * @param cbStack See RTThreadCreate.
787 * @param enmType See RTThreadCreate.
788 * @param fFlags See RTThreadCreate.
789 * @param pszNameFmt Thread name format.
790 * @param va Format arguments.
791 */
792RTDECL(int) RTThreadCreateV(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
793 RTTHREADTYPE enmType, uint32_t fFlags, const char *pszNameFmt, va_list va)
794{
795 char szName[RTTHREAD_NAME_LEN * 2];
796 RTStrPrintfV(szName, sizeof(szName), pszNameFmt, va);
797 return RTThreadCreate(pThread, pfnThread, pvUser, cbStack, enmType, fFlags, szName);
798}
799RT_EXPORT_SYMBOL(RTThreadCreateV);
800
801
802/**
803 * Create a new thread.
804 *
805 * Same as RTThreadCreate except the name is given in the RTStrPrintf form.
806 *
807 * @returns iprt status code.
808 * @param pThread See RTThreadCreate.
809 * @param pfnThread See RTThreadCreate.
810 * @param pvUser See RTThreadCreate.
811 * @param cbStack See RTThreadCreate.
812 * @param enmType See RTThreadCreate.
813 * @param fFlags See RTThreadCreate.
814 * @param pszNameFmt Thread name format.
815 * @param ... Format arguments.
816 */
817RTDECL(int) RTThreadCreateF(PRTTHREAD pThread, PFNRTTHREAD pfnThread, void *pvUser, size_t cbStack,
818 RTTHREADTYPE enmType, uint32_t fFlags, const char *pszNameFmt, ...)
819{
820 va_list va;
821 va_start(va, pszNameFmt);
822 int rc = RTThreadCreateV(pThread, pfnThread, pvUser, cbStack, enmType, fFlags, pszNameFmt, va);
823 va_end(va);
824 return rc;
825}
826RT_EXPORT_SYMBOL(RTThreadCreateF);
827
828
829/**
830 * Gets the native thread id of a IPRT thread.
831 *
832 * @returns The native thread id.
833 * @param Thread The IPRT thread.
834 */
835RTDECL(RTNATIVETHREAD) RTThreadGetNative(RTTHREAD Thread)
836{
837 PRTTHREADINT pThread = rtThreadGet(Thread);
838 if (pThread)
839 {
840 RTNATIVETHREAD NativeThread = (RTNATIVETHREAD)pThread->Core.Key;
841 rtThreadRelease(pThread);
842 return NativeThread;
843 }
844 return NIL_RTNATIVETHREAD;
845}
846RT_EXPORT_SYMBOL(RTThreadGetNative);
847
848
849/**
850 * Gets the IPRT thread of a native thread.
851 *
852 * @returns The IPRT thread handle
853 * @returns NIL_RTTHREAD if not a thread known to IPRT.
854 * @param NativeThread The native thread handle/id.
855 */
856RTDECL(RTTHREAD) RTThreadFromNative(RTNATIVETHREAD NativeThread)
857{
858 PRTTHREADINT pThread = rtThreadGetByNative(NativeThread);
859 if (pThread)
860 return pThread;
861 return NIL_RTTHREAD;
862}
863RT_EXPORT_SYMBOL(RTThreadFromNative);
864
865
866/**
867 * Gets the name of the current thread thread.
868 *
869 * @returns Pointer to readonly name string.
870 * @returns NULL on failure.
871 */
872RTDECL(const char *) RTThreadSelfName(void)
873{
874 RTTHREAD Thread = RTThreadSelf();
875 if (Thread != NIL_RTTHREAD)
876 {
877 PRTTHREADINT pThread = rtThreadGet(Thread);
878 if (pThread)
879 {
880 const char *szName = pThread->szName;
881 rtThreadRelease(pThread);
882 return szName;
883 }
884 }
885 return NULL;
886}
887RT_EXPORT_SYMBOL(RTThreadSelfName);
888
889
890/**
891 * Gets the name of a thread.
892 *
893 * @returns Pointer to readonly name string.
894 * @returns NULL on failure.
895 * @param Thread Thread handle of the thread to query the name of.
896 */
897RTDECL(const char *) RTThreadGetName(RTTHREAD Thread)
898{
899 if (Thread == NIL_RTTHREAD)
900 return NULL;
901 PRTTHREADINT pThread = rtThreadGet(Thread);
902 if (pThread)
903 {
904 const char *szName = pThread->szName;
905 rtThreadRelease(pThread);
906 return szName;
907 }
908 return NULL;
909}
910RT_EXPORT_SYMBOL(RTThreadGetName);
911
912
913/**
914 * Sets the name of a thread.
915 *
916 * @returns iprt status code.
917 * @param Thread Thread handle of the thread to query the name of.
918 * @param pszName The thread name.
919 */
920RTDECL(int) RTThreadSetName(RTTHREAD Thread, const char *pszName)
921{
922 /*
923 * Validate input.
924 */
925 size_t cchName = strlen(pszName);
926 if (cchName >= RTTHREAD_NAME_LEN)
927 {
928 AssertMsgFailed(("pszName=%s is too long, max is %d\n", pszName, RTTHREAD_NAME_LEN - 1));
929 return VERR_INVALID_PARAMETER;
930 }
931 PRTTHREADINT pThread = rtThreadGet(Thread);
932 if (!pThread)
933 return VERR_INVALID_HANDLE;
934
935 /*
936 * Update the name.
937 */
938 pThread->szName[cchName] = '\0'; /* paranoia */
939 memcpy(pThread->szName, pszName, cchName);
940 rtThreadRelease(pThread);
941 return VINF_SUCCESS;
942}
943RT_EXPORT_SYMBOL(RTThreadSetName);
944
945
946/**
947 * Checks if the specified thread is the main thread.
948 *
949 * @returns true if it is, false if it isn't.
950 *
951 * @param hThread The thread handle.
952 *
953 * @remarks This function may not return the correct value when RTR3Init was
954 * called on a thread of the than the main one. This could for
955 * instance happen when the DLL/DYLIB/SO containing IPRT is dynamically
956 * loaded at run time by a different thread.
957 */
958RTDECL(bool) RTThreadIsMain(RTTHREAD hThread)
959{
960 PRTTHREADINT pThread = rtThreadGet(hThread);
961 if (pThread)
962 {
963 bool fRc = !!(pThread->fIntFlags & RTTHREADINT_FLAGS_MAIN);
964 rtThreadRelease(pThread);
965 return fRc;
966 }
967 return false;
968}
969RT_EXPORT_SYMBOL(RTThreadIsMain);
970
971
972/**
973 * Signal the user event.
974 *
975 * @returns iprt status code.
976 */
977RTDECL(int) RTThreadUserSignal(RTTHREAD Thread)
978{
979 int rc;
980 PRTTHREADINT pThread = rtThreadGet(Thread);
981 if (pThread)
982 {
983 rc = RTSemEventMultiSignal(pThread->EventUser);
984 rtThreadRelease(pThread);
985 }
986 else
987 rc = VERR_INVALID_HANDLE;
988 return rc;
989}
990RT_EXPORT_SYMBOL(RTThreadUserSignal);
991
992
993/**
994 * Wait for the user event, resume on interruption.
995 *
996 * @returns iprt status code.
997 * @param Thread The thread to wait for.
998 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
999 * an indefinite wait.
1000 */
1001RTDECL(int) RTThreadUserWait(RTTHREAD Thread, RTMSINTERVAL cMillies)
1002{
1003 int rc;
1004 PRTTHREADINT pThread = rtThreadGet(Thread);
1005 if (pThread)
1006 {
1007 rc = RTSemEventMultiWait(pThread->EventUser, cMillies);
1008 rtThreadRelease(pThread);
1009 }
1010 else
1011 rc = VERR_INVALID_HANDLE;
1012 return rc;
1013}
1014RT_EXPORT_SYMBOL(RTThreadUserWait);
1015
1016
1017/**
1018 * Wait for the user event, return on interruption.
1019 *
1020 * @returns iprt status code.
1021 * @param Thread The thread to wait for.
1022 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1023 * an indefinite wait.
1024 */
1025RTDECL(int) RTThreadUserWaitNoResume(RTTHREAD Thread, RTMSINTERVAL cMillies)
1026{
1027 int rc;
1028 PRTTHREADINT pThread = rtThreadGet(Thread);
1029 if (pThread)
1030 {
1031 rc = RTSemEventMultiWaitNoResume(pThread->EventUser, cMillies);
1032 rtThreadRelease(pThread);
1033 }
1034 else
1035 rc = VERR_INVALID_HANDLE;
1036 return rc;
1037}
1038RT_EXPORT_SYMBOL(RTThreadUserWaitNoResume);
1039
1040
1041/**
1042 * Reset the user event.
1043 *
1044 * @returns iprt status code.
1045 * @param Thread The thread to reset.
1046 */
1047RTDECL(int) RTThreadUserReset(RTTHREAD Thread)
1048{
1049 int rc;
1050 PRTTHREADINT pThread = rtThreadGet(Thread);
1051 if (pThread)
1052 {
1053 rc = RTSemEventMultiReset(pThread->EventUser);
1054 rtThreadRelease(pThread);
1055 }
1056 else
1057 rc = VERR_INVALID_HANDLE;
1058 return rc;
1059}
1060RT_EXPORT_SYMBOL(RTThreadUserReset);
1061
1062
1063/**
1064 * Wait for the thread to terminate.
1065 *
1066 * @returns iprt status code.
1067 * @param Thread The thread to wait for.
1068 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1069 * an indefinite wait.
1070 * @param prc Where to store the return code of the thread. Optional.
1071 * @param fAutoResume Whether or not to resume the wait on VERR_INTERRUPTED.
1072 */
1073static int rtThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc, bool fAutoResume)
1074{
1075 int rc = VERR_INVALID_HANDLE;
1076 if (Thread != NIL_RTTHREAD)
1077 {
1078 PRTTHREADINT pThread = rtThreadGet(Thread);
1079 if (pThread)
1080 {
1081 if (pThread->fFlags & RTTHREADFLAGS_WAITABLE)
1082 {
1083 if (fAutoResume)
1084 rc = RTSemEventMultiWait(pThread->EventTerminated, cMillies);
1085 else
1086 rc = RTSemEventMultiWaitNoResume(pThread->EventTerminated, cMillies);
1087 if (RT_SUCCESS(rc))
1088 {
1089 if (prc)
1090 *prc = pThread->rc;
1091
1092 /*
1093 * If the thread is marked as waitable, we'll do one additional
1094 * release in order to free up the thread structure (see how we
1095 * init cRef in rtThreadAlloc()).
1096 */
1097 if (ASMAtomicBitTestAndClear(&pThread->fFlags, RTTHREADFLAGS_WAITABLE_BIT))
1098 rtThreadRelease(pThread);
1099 }
1100 }
1101 else
1102 {
1103 rc = VERR_THREAD_NOT_WAITABLE;
1104 AssertRC(rc);
1105 }
1106 rtThreadRelease(pThread);
1107 }
1108 }
1109 return rc;
1110}
1111
1112
1113/**
1114 * Wait for the thread to terminate, resume on interruption.
1115 *
1116 * @returns iprt status code.
1117 * Will not return VERR_INTERRUPTED.
1118 * @param Thread The thread to wait for.
1119 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1120 * an indefinite wait.
1121 * @param prc Where to store the return code of the thread. Optional.
1122 */
1123RTDECL(int) RTThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc)
1124{
1125 int rc = rtThreadWait(Thread, cMillies, prc, true);
1126 Assert(rc != VERR_INTERRUPTED);
1127 return rc;
1128}
1129RT_EXPORT_SYMBOL(RTThreadWait);
1130
1131
1132/**
1133 * Wait for the thread to terminate, return on interruption.
1134 *
1135 * @returns iprt status code.
1136 * @param Thread The thread to wait for.
1137 * @param cMillies The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
1138 * an indefinite wait.
1139 * @param prc Where to store the return code of the thread. Optional.
1140 */
1141RTDECL(int) RTThreadWaitNoResume(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc)
1142{
1143 return rtThreadWait(Thread, cMillies, prc, false);
1144}
1145RT_EXPORT_SYMBOL(RTThreadWaitNoResume);
1146
1147
1148/**
1149 * Changes the type of the specified thread.
1150 *
1151 * @returns iprt status code.
1152 * @param Thread The thread which type should be changed.
1153 * @param enmType The new thread type.
1154 */
1155RTDECL(int) RTThreadSetType(RTTHREAD Thread, RTTHREADTYPE enmType)
1156{
1157 /*
1158 * Validate input.
1159 */
1160 int rc;
1161 if ( enmType > RTTHREADTYPE_INVALID
1162 && enmType < RTTHREADTYPE_END)
1163 {
1164 PRTTHREADINT pThread = rtThreadGet(Thread);
1165 if (pThread)
1166 {
1167 if (rtThreadIsAlive(pThread))
1168 {
1169 /*
1170 * Do the job.
1171 */
1172 RT_THREAD_LOCK_TMP(Tmp);
1173 RT_THREAD_LOCK_RW(Tmp);
1174 rc = rtThreadNativeSetPriority(pThread, enmType);
1175 if (RT_SUCCESS(rc))
1176 ASMAtomicXchgSize(&pThread->enmType, enmType);
1177 RT_THREAD_UNLOCK_RW(Tmp);
1178 if (RT_FAILURE(rc))
1179 Log(("RTThreadSetType: failed on thread %p (%s), rc=%Rrc!!!\n", Thread, pThread->szName, rc));
1180 }
1181 else
1182 rc = VERR_THREAD_IS_DEAD;
1183 rtThreadRelease(pThread);
1184 }
1185 else
1186 rc = VERR_INVALID_HANDLE;
1187 }
1188 else
1189 {
1190 AssertMsgFailed(("enmType=%d\n", enmType));
1191 rc = VERR_INVALID_PARAMETER;
1192 }
1193 return rc;
1194}
1195RT_EXPORT_SYMBOL(RTThreadSetType);
1196
1197
1198/**
1199 * Gets the type of the specified thread.
1200 *
1201 * @returns The thread type.
1202 * @returns RTTHREADTYPE_INVALID if the thread handle is invalid.
1203 * @param Thread The thread in question.
1204 */
1205RTDECL(RTTHREADTYPE) RTThreadGetType(RTTHREAD Thread)
1206{
1207 RTTHREADTYPE enmType = RTTHREADTYPE_INVALID;
1208 PRTTHREADINT pThread = rtThreadGet(Thread);
1209 if (pThread)
1210 {
1211 enmType = pThread->enmType;
1212 rtThreadRelease(pThread);
1213 }
1214 return enmType;
1215}
1216RT_EXPORT_SYMBOL(RTThreadGetType);
1217
1218#ifdef IN_RING3
1219
1220/**
1221 * Recalculates scheduling attributes for the default process
1222 * priority using the specified priority type for the calling thread.
1223 *
1224 * The scheduling attributes are targeted at threads and they are protected
1225 * by the thread read-write semaphore, that's why RTProc is forwarding the
1226 * operation to RTThread.
1227 *
1228 * @returns iprt status code.
1229 * @remarks Will only work for strict builds.
1230 */
1231int rtThreadDoCalcDefaultPriority(RTTHREADTYPE enmType)
1232{
1233 RT_THREAD_LOCK_TMP(Tmp);
1234 RT_THREAD_LOCK_RW(Tmp);
1235 int rc = rtSchedNativeCalcDefaultPriority(enmType);
1236 RT_THREAD_UNLOCK_RW(Tmp);
1237 return rc;
1238}
1239
1240
1241/**
1242 * Thread enumerator - sets the priority of one thread.
1243 *
1244 * @returns 0 to continue.
1245 * @returns !0 to stop. In our case a VERR_ code.
1246 * @param pNode The thread node.
1247 * @param pvUser The new priority.
1248 */
1249static DECLCALLBACK(int) rtThreadSetPriorityOne(PAVLPVNODECORE pNode, void *pvUser)
1250{
1251 PRTTHREADINT pThread = (PRTTHREADINT)pNode;
1252 if (!rtThreadIsAlive(pThread))
1253 return VINF_SUCCESS;
1254 int rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
1255 if (RT_SUCCESS(rc)) /* hide any warnings */
1256 return VINF_SUCCESS;
1257 return rc;
1258}
1259
1260
1261/**
1262 * Attempts to alter the priority of the current process.
1263 *
1264 * The scheduling attributes are targeted at threads and they are protected
1265 * by the thread read-write semaphore, that's why RTProc is forwarding the
1266 * operation to RTThread. This operation also involves updating all thread
1267 * which is much faster done from RTThread.
1268 *
1269 * @returns iprt status code.
1270 * @param enmPriority The new priority.
1271 */
1272int rtThreadDoSetProcPriority(RTPROCPRIORITY enmPriority)
1273{
1274 LogFlow(("rtThreadDoSetProcPriority: enmPriority=%d\n", enmPriority));
1275
1276 /*
1277 * First validate that we're allowed by the OS to use all the
1278 * scheduling attributes defined by the specified process priority.
1279 */
1280 RT_THREAD_LOCK_TMP(Tmp);
1281 RT_THREAD_LOCK_RW(Tmp);
1282 int rc = rtProcNativeSetPriority(enmPriority);
1283 if (RT_SUCCESS(rc))
1284 {
1285 /*
1286 * Update the priority of existing thread.
1287 */
1288 rc = RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
1289 if (RT_SUCCESS(rc))
1290 ASMAtomicXchgSize(&g_enmProcessPriority, enmPriority);
1291 else
1292 {
1293 /*
1294 * Failed, restore the priority.
1295 */
1296 rtProcNativeSetPriority(g_enmProcessPriority);
1297 RTAvlPVDoWithAll(&g_ThreadTree, true, rtThreadSetPriorityOne, NULL);
1298 }
1299 }
1300 RT_THREAD_UNLOCK_RW(Tmp);
1301 LogFlow(("rtThreadDoSetProcPriority: returns %Rrc\n", rc));
1302 return rc;
1303}
1304
1305
1306/**
1307 * Change the thread state to blocking.
1308 *
1309 * @param hThread The current thread.
1310 * @param enmState The sleep state.
1311 * @param fReallySleeping Really going to sleep now.
1312 */
1313RTDECL(void) RTThreadBlocking(RTTHREAD hThread, RTTHREADSTATE enmState, bool fReallySleeping)
1314{
1315 Assert(RTTHREAD_IS_SLEEPING(enmState));
1316 PRTTHREADINT pThread = hThread;
1317 if (pThread != NIL_RTTHREAD)
1318 {
1319 Assert(pThread == RTThreadSelf());
1320 if (rtThreadGetState(pThread) == RTTHREADSTATE_RUNNING)
1321 rtThreadSetState(pThread, enmState);
1322 ASMAtomicWriteBool(&pThread->fReallySleeping, fReallySleeping);
1323 }
1324}
1325RT_EXPORT_SYMBOL(RTThreadBlocking);
1326
1327
1328/**
1329 * Unblocks a thread.
1330 *
1331 * This function is paired with rtThreadBlocking.
1332 *
1333 * @param hThread The current thread.
1334 * @param enmCurState The current state, used to check for nested blocking.
1335 * The new state will be running.
1336 */
1337RTDECL(void) RTThreadUnblocked(RTTHREAD hThread, RTTHREADSTATE enmCurState)
1338{
1339 PRTTHREADINT pThread = hThread;
1340 if (pThread != NIL_RTTHREAD)
1341 {
1342 Assert(pThread == RTThreadSelf());
1343 ASMAtomicWriteBool(&pThread->fReallySleeping, false);
1344
1345 RTTHREADSTATE enmActualState = rtThreadGetState(pThread);
1346 if (enmActualState == enmCurState)
1347 {
1348 rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
1349 if ( pThread->LockValidator.pRec
1350 && pThread->LockValidator.enmRecState == enmCurState)
1351 ASMAtomicWriteNullPtr(&pThread->LockValidator.pRec);
1352 }
1353 /* This is a bit ugly... :-/ */
1354 else if ( ( enmActualState == RTTHREADSTATE_TERMINATED
1355 || enmActualState == RTTHREADSTATE_INITIALIZING)
1356 && pThread->LockValidator.pRec)
1357 ASMAtomicWriteNullPtr(&pThread->LockValidator.pRec);
1358 Assert( pThread->LockValidator.pRec == NULL
1359 || RTTHREAD_IS_SLEEPING(enmActualState));
1360 }
1361}
1362RT_EXPORT_SYMBOL(RTThreadUnblocked);
1363
1364
1365/**
1366 * Get the current thread state.
1367 *
1368 * @returns The thread state.
1369 * @param hThread The thread.
1370 */
1371RTDECL(RTTHREADSTATE) RTThreadGetState(RTTHREAD hThread)
1372{
1373 RTTHREADSTATE enmState = RTTHREADSTATE_INVALID;
1374 PRTTHREADINT pThread = rtThreadGet(hThread);
1375 if (pThread)
1376 {
1377 enmState = rtThreadGetState(pThread);
1378 rtThreadRelease(pThread);
1379 }
1380 return enmState;
1381}
1382RT_EXPORT_SYMBOL(RTThreadGetState);
1383
1384
1385RTDECL(RTTHREADSTATE) RTThreadGetReallySleeping(RTTHREAD hThread)
1386{
1387 RTTHREADSTATE enmState = RTTHREADSTATE_INVALID;
1388 PRTTHREADINT pThread = rtThreadGet(hThread);
1389 if (pThread)
1390 {
1391 enmState = rtThreadGetState(pThread);
1392 if (!ASMAtomicUoReadBool(&pThread->fReallySleeping))
1393 enmState = RTTHREADSTATE_RUNNING;
1394 rtThreadRelease(pThread);
1395 }
1396 return enmState;
1397}
1398RT_EXPORT_SYMBOL(RTThreadGetReallySleeping);
1399
1400
1401/**
1402 * Translate a thread state into a string.
1403 *
1404 * @returns Pointer to a read-only string containing the state name.
1405 * @param enmState The state.
1406 */
1407RTDECL(const char *) RTThreadStateName(RTTHREADSTATE enmState)
1408{
1409 switch (enmState)
1410 {
1411 case RTTHREADSTATE_INVALID: return "INVALID";
1412 case RTTHREADSTATE_INITIALIZING: return "INITIALIZING";
1413 case RTTHREADSTATE_TERMINATED: return "TERMINATED";
1414 case RTTHREADSTATE_RUNNING: return "RUNNING";
1415 case RTTHREADSTATE_CRITSECT: return "CRITSECT";
1416 case RTTHREADSTATE_EVENT: return "EVENT";
1417 case RTTHREADSTATE_EVENT_MULTI: return "EVENT_MULTI";
1418 case RTTHREADSTATE_FAST_MUTEX: return "FAST_MUTEX";
1419 case RTTHREADSTATE_MUTEX: return "MUTEX";
1420 case RTTHREADSTATE_RW_READ: return "RW_READ";
1421 case RTTHREADSTATE_RW_WRITE: return "RW_WRITE";
1422 case RTTHREADSTATE_SLEEP: return "SLEEP";
1423 case RTTHREADSTATE_SPIN_MUTEX: return "SPIN_MUTEX";
1424 default: return "UnknownThreadState";
1425 }
1426}
1427RT_EXPORT_SYMBOL(RTThreadStateName);
1428
1429#endif /* IN_RING3 */
1430#ifdef IPRT_WITH_GENERIC_TLS
1431
1432/**
1433 * Thread enumerator - clears a TLS entry.
1434 *
1435 * @returns 0.
1436 * @param pNode The thread node.
1437 * @param pvUser The TLS index.
1438 */
1439static DECLCALLBACK(int) rtThreadClearTlsEntryCallback(PAVLPVNODECORE pNode, void *pvUser)
1440{
1441 PRTTHREADINT pThread = (PRTTHREADINT)pNode;
1442 RTTLS iTls = (RTTLS)(uintptr_t)pvUser;
1443 ASMAtomicWriteNullPtr(&pThread->apvTlsEntries[iTls]);
1444 return 0;
1445}
1446
1447
1448/**
1449 * Helper for the generic TLS implementation that clears a given TLS
1450 * entry on all threads.
1451 *
1452 * @param iTls The TLS entry. (valid)
1453 */
1454void rtThreadClearTlsEntry(RTTLS iTls)
1455{
1456 RT_THREAD_LOCK_TMP(Tmp);
1457 RT_THREAD_LOCK_RD(Tmp);
1458 RTAvlPVDoWithAll(&g_ThreadTree, true /* fFromLeft*/, rtThreadClearTlsEntryCallback, (void *)(uintptr_t)iTls);
1459 RT_THREAD_UNLOCK_RD(Tmp);
1460}
1461
1462#endif /* IPRT_WITH_GENERIC_TLS */
1463
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