/* $Id: thread.cpp 109153 2016-07-27 11:46:03Z bird $ */
/** @file
 * IPRT - Threads, common routines.
 */

/*
 * Copyright (C) 2006-2016 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 *
 * The contents of this file may alternatively be used under the terms
 * of the Common Development and Distribution License Version 1.0
 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
 * VirtualBox OSE distribution, in which case the provisions of the
 * CDDL are applicable instead of those of the GPL.
 *
 * You may elect to license modified versions of this file under the
 * terms and conditions of either the GPL or the CDDL or both.
 */

/*********************************************************************************************************************************
*   Header Files                                                                                                                 *
*********************************************************************************************************************************/
#define LOG_GROUP RTLOGGROUP_THREAD
#include <iprt/thread.h>
#include "internal/iprt.h"

#include <iprt/log.h>
#include <iprt/avl.h>
#include <iprt/alloc.h>
#include <iprt/assert.h>
#include <iprt/lockvalidator.h>
#include <iprt/semaphore.h>
#ifdef IN_RING0
# include <iprt/spinlock.h>
#endif
#include <iprt/asm.h>
#include <iprt/err.h>
#include <iprt/string.h>
#include "internal/magics.h"
#include "internal/thread.h"
#include "internal/sched.h"
#include "internal/process.h"
#ifdef RT_WITH_ICONV_CACHE
# include "internal/string.h"
#endif

/*********************************************************************************************************************************
*   Defined Constants And Macros                                                                                                 *
*********************************************************************************************************************************/
#ifdef IN_RING0
# define RT_THREAD_LOCK_RW()        RTSpinlockAcquire(g_ThreadSpinlock)
# define RT_THREAD_UNLOCK_RW()      RTSpinlockRelease(g_ThreadSpinlock)
# define RT_THREAD_LOCK_RD()        RTSpinlockAcquire(g_ThreadSpinlock)
# define RT_THREAD_UNLOCK_RD()      RTSpinlockRelease(g_ThreadSpinlock)
#else
# define RT_THREAD_LOCK_RW()        rtThreadLockRW()
# define RT_THREAD_UNLOCK_RW()      rtThreadUnLockRW()
# define RT_THREAD_LOCK_RD()        rtThreadLockRD()
# define RT_THREAD_UNLOCK_RD()      rtThreadUnLockRD()
#endif

/*********************************************************************************************************************************
*   Global Variables                                                                                                             *
*********************************************************************************************************************************/
/** The AVL thread containing the threads. */
static PAVLPVNODECORE g_ThreadTree;
/** The number of threads in the tree (for ring-0 termination kludge). */
static uint32_t volatile g_cThreadInTree;
#ifdef IN_RING3
/** The RW lock protecting the tree. */
static RTSEMRW g_ThreadRWSem = NIL_RTSEMRW;
#else
/** The spinlocks protecting the tree. */
static RTSPINLOCK g_ThreadSpinlock = NIL_RTSPINLOCK;
#endif
/** Indicates whether we've been initialized or not. */
static bool g_frtThreadInitialized;

/*********************************************************************************************************************************
*   Internal Functions                                                                                                           *
*********************************************************************************************************************************/
static void rtThreadDestroy(PRTTHREADINT pThread);
#ifdef IN_RING3
static int rtThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags,
			 uint32_t fIntFlags, const char *pszName);
#endif
static void rtThreadRemoveLocked(PRTTHREADINT pThread);
static PRTTHREADINT rtThreadAlloc(RTTHREADTYPE enmType, unsigned fFlags,
				  uint32_t fIntFlags, const char *pszName);

/** @page pg_rt_thread  IPRT Thread Internals
 *
 * IPRT provides interface to whatever native threading that the host provides,
 * preferably using a CRT level interface to better integrate with other libraries.
 *
 * Internally IPRT keeps track of threads by means of the RTTHREADINT structure.
 * All the RTTHREADINT structures are kept in a AVL tree which is protected by a
 * read/write lock for efficient access. A thread is inserted into the tree in
 * three places in the code. The main thread is 'adopted' by IPRT on rtR3Init()
 * by rtThreadAdopt(). When creating a new thread there the child and the parent
 * race inserting the thread, this is rtThreadMain() and RTThreadCreate.
 *
 * RTTHREADINT objects are using reference counting as a mean of sticking around
 * till no-one needs them any longer. Waitable threads is created with one extra
 * reference so they won't go away until they are waited on. This introduces a
 * major problem if we use the host thread identifier as key in the AVL tree - the
 * host may reuse the thread identifier before the thread was waited on. So, on
 * most platforms we are using the RTTHREADINT pointer as key and not the
 * thread id. RTThreadSelf() then have to be implemented using a pointer stored
 * in thread local storage (TLS).
 *
 * In Ring-0 we only try keep track of kernel threads created by RTThreadCreate
 * at the moment. There we really only need the 'join' feature, but doing things
 * the same way allow us to name threads and similar stuff.
 */

/**
 * Initializes the thread database.
 *
 * @returns iprt status code.
 */
DECLHIDDEN(int) rtThreadInit(void)
{
#ifdef IN_RING3
	int rc = VINF_ALREADY_INITIALIZED;
	if (g_ThreadRWSem == NIL_RTSEMRW) {
		/*
		 * We assume the caller is the 1st thread, which we'll call 'main'.
		 * But first, we'll create the semaphore.
		 */
		rc = RTSemRWCreateEx(&g_ThreadRWSem, RTSEMRW_FLAGS_NO_LOCK_VAL,
				     NIL_RTLOCKVALCLASS,
				     RTLOCKVAL_SUB_CLASS_NONE, NULL);
		if (RT_SUCCESS(rc)) {
			rc = rtThreadNativeInit();
			if (RT_SUCCESS(rc))
				rc = rtThreadAdopt(RTTHREADTYPE_DEFAULT, 0,
						   RTTHREADINT_FLAGS_MAIN,
						   "main");
			if (RT_SUCCESS(rc))
				rc = rtSchedNativeCalcDefaultPriority
				    (RTTHREADTYPE_DEFAULT);
			if (RT_SUCCESS(rc)) {
				g_frtThreadInitialized = true;
				return VINF_SUCCESS;
			}

			/* failed, clear out */
			RTSemRWDestroy(g_ThreadRWSem);
			g_ThreadRWSem = NIL_RTSEMRW;
		}
	}
#elif defined(IN_RING0)
	int rc;
	/*
	 * Create the spinlock and to native init.
	 */
	Assert(g_ThreadSpinlock == NIL_RTSPINLOCK);
	rc = RTSpinlockCreate(&g_ThreadSpinlock,
			      RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "RTThread");
	if (RT_SUCCESS(rc)) {
		rc = rtThreadNativeInit();
		if (RT_SUCCESS(rc)) {
			g_frtThreadInitialized = true;
			return VINF_SUCCESS;
		}

		/* failed, clear out */
		RTSpinlockDestroy(g_ThreadSpinlock);
		g_ThreadSpinlock = NIL_RTSPINLOCK;
	}
#else
# error "!IN_RING0 && !IN_RING3"
#endif
	return rc;
}

#ifdef IN_RING3
/**
 * Called when IPRT was first initialized in unobtrusive mode and later changed
 * to obtrustive.
 *
 * This is only applicable in ring-3.
 */
DECLHIDDEN(void)rtThreadReInitObtrusive(void)
{
	rtThreadNativeReInitObtrusive();
}
#endif

/**
 * Terminates the thread database.
 */
DECLHIDDEN(void) rtThreadTerm(void)
{
#ifdef IN_RING3
	/* we don't cleanup here yet */

#elif defined(IN_RING0)
	/* just destroy the spinlock and assume the thread is fine... */
	RTSpinlockDestroy(g_ThreadSpinlock);
	g_ThreadSpinlock = NIL_RTSPINLOCK;
	if (g_ThreadTree != NULL)
		RTAssertMsg2Weak("WARNING: g_ThreadTree=%p\n", g_ThreadTree);
#endif
}

#ifdef IN_RING3

DECLINLINE(void) rtThreadLockRW(void)
{
	if (g_ThreadRWSem == NIL_RTSEMRW)
		rtThreadInit();
	int rc = RTSemRWRequestWrite(g_ThreadRWSem, RT_INDEFINITE_WAIT);
	AssertReleaseRC(rc);
}

DECLINLINE(void) rtThreadLockRD(void)
{
	if (g_ThreadRWSem == NIL_RTSEMRW)
		rtThreadInit();
	int rc = RTSemRWRequestRead(g_ThreadRWSem, RT_INDEFINITE_WAIT);
	AssertReleaseRC(rc);
}

DECLINLINE(void) rtThreadUnLockRW(void)
{
	int rc = RTSemRWReleaseWrite(g_ThreadRWSem);
	AssertReleaseRC(rc);
}

DECLINLINE(void) rtThreadUnLockRD(void)
{
	int rc = RTSemRWReleaseRead(g_ThreadRWSem);
	AssertReleaseRC(rc);
}

/**
 * Adopts the calling thread.
 * No locks are taken or released by this function.
 */
static int rtThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags,
			 uint32_t fIntFlags, const char *pszName)
{
	int rc;
	PRTTHREADINT pThread;
	Assert(!(fFlags & RTTHREADFLAGS_WAITABLE));
	fFlags &= ~RTTHREADFLAGS_WAITABLE;

	/*
	 * Allocate and insert the thread.
	 * (It is vital that rtThreadNativeAdopt updates the TLS before
	 * we try inserting the thread because of locking.)
	 */
	rc = VERR_NO_MEMORY;
	pThread =
	    rtThreadAlloc(enmType, fFlags, RTTHREADINT_FLAGS_ALIEN | fIntFlags,
			  pszName);
	if (pThread) {
		RTNATIVETHREAD NativeThread = RTThreadNativeSelf();
		rc = rtThreadNativeAdopt(pThread);
		if (RT_SUCCESS(rc)) {
			rtThreadInsert(pThread, NativeThread);
			rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
			rtThreadRelease(pThread);
		}
	}
	return rc;
}

/**
 * Adopts a non-IPRT thread.
 *
 * @returns IPRT status code.
 * @param   enmType         The thread type.
 * @param   fFlags          The thread flags. RTTHREADFLAGS_WAITABLE is not currently allowed.
 * @param   pszName         The thread name. Optional.
 * @param   pThread         Where to store the thread handle. Optional.
 */
RTDECL(int)RTThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags,
			 const char *pszName, PRTTHREAD pThread)
{
	int rc;
	RTTHREAD Thread;

	AssertReturn(!(fFlags & RTTHREADFLAGS_WAITABLE),
		     VERR_INVALID_PARAMETER);
	AssertReturn(!pszName || VALID_PTR(pszName), VERR_INVALID_POINTER);
	AssertReturn(!pThread || VALID_PTR(pThread), VERR_INVALID_POINTER);

	rc = VINF_SUCCESS;
	Thread = RTThreadSelf();
	if (Thread == NIL_RTTHREAD) {
		/* generate a name if none was given. */
		char szName[RTTHREAD_NAME_LEN];
		if (!pszName || !*pszName) {
			static uint32_t s_i32AlienId = 0;
			uint32_t i32Id = ASMAtomicIncU32(&s_i32AlienId);
			RTStrPrintf(szName, sizeof(szName), "ALIEN-%RX32",
				    i32Id);
			pszName = szName;
		}

		/* try adopt it */
		rc = rtThreadAdopt(enmType, fFlags, 0, pszName);
		Thread = RTThreadSelf();
		Log(("RTThreadAdopt: %RTthrd %RTnthrd '%s' enmType=%d fFlags=%#x rc=%Rrc\n", Thread, RTThreadNativeSelf(), pszName, enmType, fFlags, rc));
	} else
		Log(("RTThreadAdopt: %RTthrd %RTnthrd '%s' enmType=%d fFlags=%#x - already adopted!\n", Thread, RTThreadNativeSelf(), pszName, enmType, fFlags));

	if (pThread)
		*pThread = Thread;
	return rc;
}

RT_EXPORT_SYMBOL(RTThreadAdopt);

/**
 * Get the thread handle of the current thread, automatically adopting alien
 * threads.
 *
 * @returns Thread handle.
 */
RTDECL(RTTHREAD) RTThreadSelfAutoAdopt(void)
{
	RTTHREAD hSelf = RTThreadSelf();
	if (RT_UNLIKELY(hSelf == NIL_RTTHREAD))
		RTThreadAdopt(RTTHREADTYPE_DEFAULT, 0, NULL, &hSelf);
	return hSelf;
}

RT_EXPORT_SYMBOL(RTThreadSelfAutoAdopt);

#endif /* IN_RING3 */

/**
 * Allocates a per thread data structure and initializes the basic fields.
 *
 * @returns Pointer to per thread data structure.
 *          This is reference once.
 * @returns NULL on failure.
 * @param   enmType     The thread type.
 * @param   fFlags      The thread flags.
 * @param   fIntFlags   The internal thread flags.
 * @param   pszName     Pointer to the thread name.
 */
PRTTHREADINT rtThreadAlloc(RTTHREADTYPE enmType, unsigned fFlags,
			   uint32_t fIntFlags, const char *pszName)
{
	PRTTHREADINT pThread = (PRTTHREADINT) RTMemAllocZ(sizeof(RTTHREADINT));
	if (pThread) {
		size_t cchName;
		int rc;

		pThread->Core.Key = (void *)NIL_RTTHREAD;
		pThread->u32Magic = RTTHREADINT_MAGIC;
		cchName = strlen(pszName);
		if (cchName >= RTTHREAD_NAME_LEN)
			cchName = RTTHREAD_NAME_LEN - 1;
		memcpy(pThread->szName, pszName, cchName);
		pThread->szName[cchName] = '\0';
		pThread->cRefs = 2 + !!(fFlags & RTTHREADFLAGS_WAITABLE);	/* And extra reference if waitable. */
		pThread->rc = VERR_PROCESS_RUNNING;	 /** @todo get a better error code! */
		pThread->enmType = enmType;
		pThread->fFlags = fFlags;
		pThread->fIntFlags = fIntFlags;
		pThread->enmState = RTTHREADSTATE_INITIALIZING;
		pThread->fReallySleeping = false;
#ifdef IN_RING3
		rtLockValidatorInitPerThread(&pThread->LockValidator);
#endif
#ifdef RT_WITH_ICONV_CACHE
		rtStrIconvCacheInit(pThread);
#endif
		rc = RTSemEventMultiCreate(&pThread->EventUser);
		if (RT_SUCCESS(rc)) {
			rc = RTSemEventMultiCreate(&pThread->EventTerminated);
			if (RT_SUCCESS(rc))
				return pThread;
			RTSemEventMultiDestroy(pThread->EventUser);
		}
		RTMemFree(pThread);
	}
	return NULL;
}

/**
 * Insert the per thread data structure into the tree.
 *
 * This can be called from both the thread it self and the parent,
 * thus it must handle insertion failures in a nice manner.
 *
 * @param   pThread         Pointer to thread structure allocated by rtThreadAlloc().
 * @param   NativeThread    The native thread id.
 */
DECLHIDDEN(void)rtThreadInsert(PRTTHREADINT pThread,
			       RTNATIVETHREAD NativeThread)
{
	Assert(pThread);
	Assert(pThread->u32Magic == RTTHREADINT_MAGIC);

	{
		RT_THREAD_LOCK_RW();

		/*
		 * Do not insert a terminated thread.
		 *
		 * This may happen if the thread finishes before the RTThreadCreate call
		 * gets this far. Since the OS may quickly reuse the native thread ID
		 * it should not be reinserted at this point.
		 */
		if (rtThreadGetState(pThread) != RTTHREADSTATE_TERMINATED) {
			/*
			 * Before inserting we must check if there is a thread with this id
			 * in the tree already. We're racing parent and child on insert here
			 * so that the handle is valid in both ends when they return / start.
			 *
			 * If it's not ourself we find, it's a dead alien thread and we will
			 * unlink it from the tree. Alien threads will be released at this point.
			 */
			PRTTHREADINT pThreadOther =
			    (PRTTHREADINT) RTAvlPVGet(&g_ThreadTree,
						      (void *)NativeThread);
			if (pThreadOther != pThread) {
				bool fRc;
				/* remove dead alien if any */
				if (pThreadOther) {
					AssertMsg(pThreadOther->
						  fIntFlags &
						  RTTHREADINT_FLAGS_ALIEN,
						  ("%p:%s; %p:%s\n", pThread,
						   pThread->szName,
						   pThreadOther,
						   pThreadOther->szName));
					ASMAtomicBitClear(&pThread->fIntFlags,
							  RTTHREADINT_FLAG_IN_TREE_BIT);
					rtThreadRemoveLocked(pThreadOther);
					if (pThreadOther->
					    fIntFlags & RTTHREADINT_FLAGS_ALIEN)
						rtThreadRelease(pThreadOther);
				}

				/* insert the thread */
				ASMAtomicWritePtr(&pThread->Core.Key,
						  (void *)NativeThread);
				fRc =
				    RTAvlPVInsert(&g_ThreadTree,
						  &pThread->Core);
				ASMAtomicOrU32(&pThread->fIntFlags,
					       RTTHREADINT_FLAG_IN_TREE);
				if (fRc)
					ASMAtomicIncU32(&g_cThreadInTree);

				AssertReleaseMsg(fRc,
						 ("Lock problem? %p (%RTnthrd) %s\n",
						  pThread, NativeThread,
						  pThread->szName));
				NOREF(fRc);
			}
		}

		RT_THREAD_UNLOCK_RW();
	}
}

/**
 * Removes the thread from the AVL tree, call owns the tree lock
 * and has cleared the RTTHREADINT_FLAG_IN_TREE bit.
 *
 * @param   pThread     The thread to remove.
 */
static void rtThreadRemoveLocked(PRTTHREADINT pThread)
{
	PRTTHREADINT pThread2 =
	    (PRTTHREADINT) RTAvlPVRemove(&g_ThreadTree, pThread->Core.Key);
#if !defined(RT_OS_OS2)	/** @todo this asserts for threads created by NSPR */
	AssertMsg(pThread2 == pThread,
		  ("%p(%s) != %p (%p/%s)\n", pThread2,
		   pThread2 ? pThread2->szName : "<null>", pThread,
		   pThread->Core.Key, pThread->szName));
#endif
	if (pThread2)
		ASMAtomicDecU32(&g_cThreadInTree);
}

/**
 * Removes the thread from the AVL tree.
 *
 * @param   pThread     The thread to remove.
 */
static void rtThreadRemove(PRTTHREADINT pThread)
{
	RT_THREAD_LOCK_RW();
	if (ASMAtomicBitTestAndClear
	    (&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT))
		rtThreadRemoveLocked(pThread);
	RT_THREAD_UNLOCK_RW();
}

/**
 * Checks if a thread is alive or not.
 *
 * @returns true if the thread is alive (or we don't really know).
 * @returns false if the thread has surely terminate.
 */
DECLINLINE(bool) rtThreadIsAlive(PRTTHREADINT pThread)
{
	return !(pThread->fIntFlags & RTTHREADINT_FLAGS_TERMINATED);
}

/**
 * Gets a thread by it's native ID.
 *
 * @returns pointer to the thread structure.
 * @returns NULL if not a thread IPRT knows.
 * @param   NativeThread    The native thread id.
 */
DECLHIDDEN(PRTTHREADINT) rtThreadGetByNative(RTNATIVETHREAD NativeThread)
{
	PRTTHREADINT pThread;
	/*
	 * Simple tree lookup.
	 */
	RT_THREAD_LOCK_RD();
	pThread =
	    (PRTTHREADINT) RTAvlPVGet(&g_ThreadTree, (void *)NativeThread);
	RT_THREAD_UNLOCK_RD();
	return pThread;
}

/**
 * Gets the per thread data structure for a thread handle.
 *
 * @returns Pointer to the per thread data structure for Thread.
 *          The caller must release the thread using rtThreadRelease().
 * @returns NULL if Thread was not found.
 * @param   Thread      Thread id which structure is to be returned.
 */
DECLHIDDEN(PRTTHREADINT) rtThreadGet(RTTHREAD Thread)
{
	if (Thread != NIL_RTTHREAD && VALID_PTR(Thread)) {
		PRTTHREADINT pThread = (PRTTHREADINT) Thread;
		if (pThread->u32Magic == RTTHREADINT_MAGIC
		    && pThread->cRefs > 0) {
			ASMAtomicIncU32(&pThread->cRefs);
			return pThread;
		}
	}

	AssertMsgFailed(("Thread=%RTthrd\n", Thread));
	return NULL;
}

/**
 * Release a per thread data structure.
 *
 * @returns New reference count.
 * @param   pThread     The thread structure to release.
 */
DECLHIDDEN(uint32_t) rtThreadRelease(PRTTHREADINT pThread)
{
	uint32_t cRefs;

	Assert(pThread);
	if (pThread->cRefs >= 1) {
		cRefs = ASMAtomicDecU32(&pThread->cRefs);
		if (!cRefs)
			rtThreadDestroy(pThread);
	} else {
		cRefs = 0;
		AssertFailed();
	}
	return cRefs;
}

/**
 * Destroys the per thread data.
 *
 * @param   pThread     The thread to destroy.
 */
static void rtThreadDestroy(PRTTHREADINT pThread)
{
	RTSEMEVENTMULTI hEvt1, hEvt2;
	/*
	 * Remove it from the tree and mark it as dead.
	 *
	 * Threads that has seen rtThreadTerminate and should already have been
	 * removed from the tree. There is probably no thread that  should
	 * require removing here. However, be careful making sure that cRefs
	 * isn't 0 if we do or we'll blow up because the strict locking code
	 * will be calling us back.
	 */
	if (ASMBitTest(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT)) {
		ASMAtomicIncU32(&pThread->cRefs);
		rtThreadRemove(pThread);
		ASMAtomicDecU32(&pThread->cRefs);
	}

	/*
	 * Invalidate the thread structure.
	 */
#ifdef IN_RING3
	rtLockValidatorSerializeDestructEnter();

	rtLockValidatorDeletePerThread(&pThread->LockValidator);
#endif
#ifdef RT_WITH_ICONV_CACHE
	rtStrIconvCacheDestroy(pThread);
#endif
	ASMAtomicXchgU32(&pThread->u32Magic, RTTHREADINT_MAGIC_DEAD);
	ASMAtomicWritePtr(&pThread->Core.Key, (void *)NIL_RTTHREAD);
	pThread->enmType = RTTHREADTYPE_INVALID;
	hEvt1 = pThread->EventUser;
	pThread->EventUser = NIL_RTSEMEVENTMULTI;
	hEvt2 = pThread->EventTerminated;
	pThread->EventTerminated = NIL_RTSEMEVENTMULTI;

#ifdef IN_RING3
	rtLockValidatorSerializeDestructLeave();
#endif

	/*
	 * Destroy semaphore resources and free the bugger.
	 */
	RTSemEventMultiDestroy(hEvt1);
	if (hEvt2 != NIL_RTSEMEVENTMULTI)
		RTSemEventMultiDestroy(hEvt2);

	rtThreadNativeDestroy(pThread);
	RTMemFree(pThread);
}

/**
 * Terminates the thread.
 * Called by the thread wrapper function when the thread terminates.
 *
 * @param   pThread     The thread structure.
 * @param   rc          The thread result code.
 */
DECLHIDDEN(void) rtThreadTerminate(PRTTHREADINT pThread, int rc)
{
	Assert(pThread->cRefs >= 1);

#ifdef IPRT_WITH_GENERIC_TLS
	/*
	 * Destroy TLS entries.
	 */
	rtThreadTlsDestruction(pThread);
#endif /* IPRT_WITH_GENERIC_TLS */

	/*
	 * Set the rc, mark it terminated and signal anyone waiting.
	 */
	pThread->rc = rc;
	rtThreadSetState(pThread, RTTHREADSTATE_TERMINATED);
	ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAGS_TERMINATED);
	if (pThread->EventTerminated != NIL_RTSEMEVENTMULTI)
		RTSemEventMultiSignal(pThread->EventTerminated);

	/*
	 * Remove the thread from the tree so that there will be no
	 * key clashes in the AVL tree and release our reference to ourself.
	 */
	rtThreadRemove(pThread);
	rtThreadRelease(pThread);
}

/**
 * The common thread main function.
 * This is called by rtThreadNativeMain().
 *
 * @returns The status code of the thread.
 *          pThread is dereference by the thread before returning!
 * @param   pThread         The thread structure.
 * @param   NativeThread    The native thread id.
 * @param   pszThreadName   The name of the thread (purely a dummy for backtrace).
 */
DECLCALLBACK(DECLHIDDEN(int)) rtThreadMain(PRTTHREADINT pThread,
					   RTNATIVETHREAD NativeThread,
					   const char *pszThreadName)
{
	int rc;
	NOREF(pszThreadName);
	rtThreadInsert(pThread, NativeThread);
	Log(("rtThreadMain: Starting: pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n", pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));

	/*
	 * Change the priority.
	 */
	rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
#ifdef IN_RING3
	AssertMsgRC(rc,
		    ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d enmPriority=%d rc=%Rrc\n",
		     pThread, NativeThread, pThread->szName, pThread->enmType,
		     g_enmProcessPriority, rc));
#else
	AssertMsgRC(rc,
		    ("Failed to set priority of thread %p (%RTnthrd / %s) to enmType=%d rc=%Rrc\n",
		     pThread, NativeThread, pThread->szName, pThread->enmType,
		     rc));
#endif

	/*
	 * Call thread function and terminate when it returns.
	 */
	rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
	rc = pThread->pfnThread(pThread, pThread->pvUser);

	/*
	 * Paranoia checks for leftover resources.
	 */
#ifdef RTSEMRW_STRICT
	int32_t cWrite = ASMAtomicReadS32(&pThread->cWriteLocks);
	Assert(!cWrite);
	int32_t cRead = ASMAtomicReadS32(&pThread->cReadLocks);
	Assert(!cRead);
#endif

	Log(("rtThreadMain: Terminating: rc=%d pThread=%p NativeThread=%RTnthrd Name=%s pfnThread=%p pvUser=%p\n", rc, pThread, NativeThread, pThread->szName, pThread->pfnThread, pThread->pvUser));
	rtThreadTerminate(pThread, rc);
	return rc;
}

/**
 * Create a new thread.
 *
 * @returns iprt status code.
 * @param   pThread     Where to store the thread handle to the new thread. (optional)
 * @param   pfnThread   The thread function.
 * @param   pvUser      User argument.
 * @param   cbStack     The size of the stack for the new thread.
 *                      Use 0 for the default stack size.
 * @param   enmType     The thread type. Used for deciding scheduling attributes
 *                      of the thread.
 * @param   fFlags      Flags of the RTTHREADFLAGS type (ORed together).
 * @param   pszName     Thread name.
 */
RTDECL(int)RTThreadCreate(PRTTHREAD pThread, PFNRTTHREAD pfnThread,
			  void *pvUser, size_t cbStack, RTTHREADTYPE enmType,
			  unsigned fFlags, const char *pszName)
{
	int rc;
	PRTTHREADINT pThreadInt;

	LogFlow(("RTThreadCreate: pThread=%p pfnThread=%p pvUser=%p cbStack=%#x enmType=%d fFlags=%#x pszName=%p:{%s}\n", pThread, pfnThread, pvUser, cbStack, enmType, fFlags, pszName, pszName));

	/*
	 * Validate input.
	 */
	if (!VALID_PTR(pThread) && pThread) {
		Assert(VALID_PTR(pThread));
		return VERR_INVALID_PARAMETER;
	}
	if (!VALID_PTR(pfnThread)) {
		Assert(VALID_PTR(pfnThread));
		return VERR_INVALID_PARAMETER;
	}
	if (!pszName || !*pszName || strlen(pszName) >= RTTHREAD_NAME_LEN) {
		AssertMsgFailed(("pszName=%s (max len is %d because of logging)\n", pszName, RTTHREAD_NAME_LEN - 1));
		return VERR_INVALID_PARAMETER;
	}
	if (fFlags & ~RTTHREADFLAGS_MASK) {
		AssertMsgFailed(("fFlags=%#x\n", fFlags));
		return VERR_INVALID_PARAMETER;
	}

	/*
	 * Allocate thread argument.
	 */
	pThreadInt = rtThreadAlloc(enmType, fFlags, 0, pszName);
	if (pThreadInt) {
		RTNATIVETHREAD NativeThread;

		pThreadInt->pfnThread = pfnThread;
		pThreadInt->pvUser = pvUser;
		pThreadInt->cbStack = cbStack;

		rc = rtThreadNativeCreate(pThreadInt, &NativeThread);
		if (RT_SUCCESS(rc)) {
			rtThreadInsert(pThreadInt, NativeThread);
			rtThreadRelease(pThreadInt);
			Log(("RTThreadCreate: Created thread %p (%p) %s\n",
			     pThreadInt, NativeThread, pszName));
			if (pThread)
				*pThread = pThreadInt;
			return VINF_SUCCESS;
		}

		pThreadInt->cRefs = 1;
		rtThreadRelease(pThreadInt);
	} else
		rc = VERR_NO_TMP_MEMORY;
	LogFlow(("RTThreadCreate: Failed to create thread, rc=%Rrc\n", rc));
	AssertReleaseRC(rc);
	return rc;
}

RT_EXPORT_SYMBOL(RTThreadCreate);

/**
 * Create a new thread.
 *
 * Same as RTThreadCreate except the name is given in the RTStrPrintfV form.
 *
 * @returns iprt status code.
 * @param   pThread     See RTThreadCreate.
 * @param   pfnThread   See RTThreadCreate.
 * @param   pvUser      See RTThreadCreate.
 * @param   cbStack     See RTThreadCreate.
 * @param   enmType     See RTThreadCreate.
 * @param   fFlags      See RTThreadCreate.
 * @param   pszNameFmt  Thread name format.
 * @param   va          Format arguments.
 */
RTDECL(int)RTThreadCreateV(PRTTHREAD pThread, PFNRTTHREAD pfnThread,
			   void *pvUser, size_t cbStack, RTTHREADTYPE enmType,
			   uint32_t fFlags, const char *pszNameFmt, va_list va)
{
	char szName[RTTHREAD_NAME_LEN * 2];
	RTStrPrintfV(szName, sizeof(szName), pszNameFmt, va);
	return RTThreadCreate(pThread, pfnThread, pvUser, cbStack, enmType,
			      fFlags, szName);
}

RT_EXPORT_SYMBOL(RTThreadCreateV);

/**
 * Create a new thread.
 *
 * Same as RTThreadCreate except the name is given in the RTStrPrintf form.
 *
 * @returns iprt status code.
 * @param   pThread     See RTThreadCreate.
 * @param   pfnThread   See RTThreadCreate.
 * @param   pvUser      See RTThreadCreate.
 * @param   cbStack     See RTThreadCreate.
 * @param   enmType     See RTThreadCreate.
 * @param   fFlags      See RTThreadCreate.
 * @param   pszNameFmt  Thread name format.
 * @param   ...         Format arguments.
 */
RTDECL(int)RTThreadCreateF(PRTTHREAD pThread, PFNRTTHREAD pfnThread,
			   void *pvUser, size_t cbStack, RTTHREADTYPE enmType,
			   uint32_t fFlags, const char *pszNameFmt, ...)
{
	va_list va;
	int rc;
	va_start(va, pszNameFmt);
	rc = RTThreadCreateV(pThread, pfnThread, pvUser, cbStack, enmType,
			     fFlags, pszNameFmt, va);
	va_end(va);
	return rc;
}

RT_EXPORT_SYMBOL(RTThreadCreateF);

/**
 * Gets the native thread id of a IPRT thread.
 *
 * @returns The native thread id.
 * @param   Thread      The IPRT thread.
 */
RTDECL(RTNATIVETHREAD) RTThreadGetNative(RTTHREAD Thread)
{
	PRTTHREADINT pThread = rtThreadGet(Thread);
	if (pThread) {
		RTNATIVETHREAD NativeThread =
		    (RTNATIVETHREAD) pThread->Core.Key;
		rtThreadRelease(pThread);
		return NativeThread;
	}
	return NIL_RTNATIVETHREAD;
}

RT_EXPORT_SYMBOL(RTThreadGetNative);

/**
 * Gets the IPRT thread of a native thread.
 *
 * @returns The IPRT thread handle
 * @returns NIL_RTTHREAD if not a thread known to IPRT.
 * @param   NativeThread        The native thread handle/id.
 */
RTDECL(RTTHREAD) RTThreadFromNative(RTNATIVETHREAD NativeThread)
{
	PRTTHREADINT pThread = rtThreadGetByNative(NativeThread);
	if (pThread)
		return pThread;
	return NIL_RTTHREAD;
}

RT_EXPORT_SYMBOL(RTThreadFromNative);

/**
 * Gets the name of the current thread thread.
 *
 * @returns Pointer to readonly name string.
 * @returns NULL on failure.
 */
RTDECL(const char *)RTThreadSelfName(void)
{
	RTTHREAD Thread = RTThreadSelf();
	if (Thread != NIL_RTTHREAD) {
		PRTTHREADINT pThread = rtThreadGet(Thread);
		if (pThread) {
			const char *szName = pThread->szName;
			rtThreadRelease(pThread);
			return szName;
		}
	}
	return NULL;
}

RT_EXPORT_SYMBOL(RTThreadSelfName);

/**
 * Gets the name of a thread.
 *
 * @returns Pointer to readonly name string.
 * @returns NULL on failure.
 * @param   Thread      Thread handle of the thread to query the name of.
 */
RTDECL(const char *)RTThreadGetName(RTTHREAD Thread)
{
	PRTTHREADINT pThread;
	if (Thread == NIL_RTTHREAD)
		return NULL;
	pThread = rtThreadGet(Thread);
	if (pThread) {
		const char *szName = pThread->szName;
		rtThreadRelease(pThread);
		return szName;
	}
	return NULL;
}

RT_EXPORT_SYMBOL(RTThreadGetName);

/**
 * Sets the name of a thread.
 *
 * @returns iprt status code.
 * @param   Thread      Thread handle of the thread to query the name of.
 * @param   pszName     The thread name.
 */
RTDECL(int)RTThreadSetName(RTTHREAD Thread, const char *pszName)
{
	/*
	 * Validate input.
	 */
	PRTTHREADINT pThread;
	size_t cchName = strlen(pszName);
	if (cchName >= RTTHREAD_NAME_LEN) {
		AssertMsgFailed(("pszName=%s is too long, max is %d\n", pszName,
				 RTTHREAD_NAME_LEN - 1));
		return VERR_INVALID_PARAMETER;
	}
	pThread = rtThreadGet(Thread);
	if (!pThread)
		return VERR_INVALID_HANDLE;

	/*
	 * Update the name.
	 */
	pThread->szName[cchName] = '\0';	/* paranoia */
	memcpy(pThread->szName, pszName, cchName);
	rtThreadRelease(pThread);
	return VINF_SUCCESS;
}

RT_EXPORT_SYMBOL(RTThreadSetName);

/**
 * Checks if the specified thread is the main thread.
 *
 * @returns true if it is, false if it isn't.
 *
 * @param   hThread     The thread handle.
 *
 * @remarks This function may not return the correct value when rtR3Init was
 *          called on a thread of the than the main one.  This could for
 *          instance happen when the DLL/DYLIB/SO containing IPRT is dynamically
 *          loaded at run time by a different thread.
 */
RTDECL(bool) RTThreadIsMain(RTTHREAD hThread)
{
	PRTTHREADINT pThread = rtThreadGet(hThread);
	if (pThread) {
		bool fRc = !!(pThread->fIntFlags & RTTHREADINT_FLAGS_MAIN);
		rtThreadRelease(pThread);
		return fRc;
	}
	return false;
}

RT_EXPORT_SYMBOL(RTThreadIsMain);

RTDECL(bool) RTThreadIsSelfAlive(void)
{
	if (g_frtThreadInitialized) {
		RTTHREAD hSelf = RTThreadSelf();
		if (hSelf != NIL_RTTHREAD) {
			/*
			 * Inspect the thread state.  ASSUMES thread state order.
			 */
			RTTHREADSTATE enmState = rtThreadGetState(hSelf);
			if (enmState >= RTTHREADSTATE_RUNNING
			    && enmState <= RTTHREADSTATE_END)
				return true;
		}
	}
	return false;
}

RT_EXPORT_SYMBOL(RTThreadIsSelfAlive);

RTDECL(bool) RTThreadIsSelfKnown(void)
{
	if (g_frtThreadInitialized) {
		RTTHREAD hSelf = RTThreadSelf();
		if (hSelf != NIL_RTTHREAD)
			return true;
	}
	return false;
}

RT_EXPORT_SYMBOL(RTThreadIsSelfKnown);

RTDECL(bool) RTThreadIsInitialized(void)
{
	return g_frtThreadInitialized;
}

RT_EXPORT_SYMBOL(RTThreadIsInitialized);

/**
 * Signal the user event.
 *
 * @returns     iprt status code.
 */
RTDECL(int)RTThreadUserSignal(RTTHREAD Thread)
{
	int rc;
	PRTTHREADINT pThread = rtThreadGet(Thread);
	if (pThread) {
		rc = RTSemEventMultiSignal(pThread->EventUser);
		rtThreadRelease(pThread);
	} else
		rc = VERR_INVALID_HANDLE;
	return rc;
}

RT_EXPORT_SYMBOL(RTThreadUserSignal);

/**
 * Wait for the user event, resume on interruption.
 *
 * @returns     iprt status code.
 * @param       Thread          The thread to wait for.
 * @param       cMillies        The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
 *                              an indefinite wait.
 */
RTDECL(int)RTThreadUserWait(RTTHREAD Thread, RTMSINTERVAL cMillies)
{
	int rc;
	PRTTHREADINT pThread = rtThreadGet(Thread);
	if (pThread) {
		rc = RTSemEventMultiWait(pThread->EventUser, cMillies);
		rtThreadRelease(pThread);
	} else
		rc = VERR_INVALID_HANDLE;
	return rc;
}

RT_EXPORT_SYMBOL(RTThreadUserWait);

/**
 * Wait for the user event, return on interruption.
 *
 * @returns     iprt status code.
 * @param       Thread          The thread to wait for.
 * @param       cMillies        The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
 *                              an indefinite wait.
 */
RTDECL(int)RTThreadUserWaitNoResume(RTTHREAD Thread, RTMSINTERVAL cMillies)
{
	int rc;
	PRTTHREADINT pThread = rtThreadGet(Thread);
	if (pThread) {
		rc = RTSemEventMultiWaitNoResume(pThread->EventUser, cMillies);
		rtThreadRelease(pThread);
	} else
		rc = VERR_INVALID_HANDLE;
	return rc;
}

RT_EXPORT_SYMBOL(RTThreadUserWaitNoResume);

/**
 * Reset the user event.
 *
 * @returns     iprt status code.
 * @param       Thread          The thread to reset.
 */
RTDECL(int)RTThreadUserReset(RTTHREAD Thread)
{
	int rc;
	PRTTHREADINT pThread = rtThreadGet(Thread);
	if (pThread) {
		rc = RTSemEventMultiReset(pThread->EventUser);
		rtThreadRelease(pThread);
	} else
		rc = VERR_INVALID_HANDLE;
	return rc;
}

RT_EXPORT_SYMBOL(RTThreadUserReset);

/**
 * Wait for the thread to terminate.
 *
 * @returns     iprt status code.
 * @param       Thread          The thread to wait for.
 * @param       cMillies        The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
 *                              an indefinite wait.
 * @param       prc             Where to store the return code of the thread. Optional.
 * @param       fAutoResume     Whether or not to resume the wait on VERR_INTERRUPTED.
 */
static int rtThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc,
			bool fAutoResume)
{
	int rc = VERR_INVALID_HANDLE;
	if (Thread != NIL_RTTHREAD) {
		PRTTHREADINT pThread = rtThreadGet(Thread);
		if (pThread) {
			if (pThread->fFlags & RTTHREADFLAGS_WAITABLE) {
				if (fAutoResume)
					rc = RTSemEventMultiWait(pThread->
								 EventTerminated,
								 cMillies);
				else
					rc = RTSemEventMultiWaitNoResume
					    (pThread->EventTerminated,
					     cMillies);
				if (RT_SUCCESS(rc)) {
					if (prc)
						*prc = pThread->rc;

					/*
					 * If the thread is marked as waitable, we'll do one additional
					 * release in order to free up the thread structure (see how we
					 * init cRef in rtThreadAlloc()).
					 */
					if (ASMAtomicBitTestAndClear
					    (&pThread->fFlags,
					     RTTHREADFLAGS_WAITABLE_BIT)) {
						rtThreadRelease(pThread);
#ifdef IN_RING0
						/*
						 * IPRT termination kludge. Call native code to make sure
						 * the last thread is really out of IPRT to prevent it from
						 * crashing after we destroyed the spinlock in rtThreadTerm.
						 */
						if (ASMAtomicReadU32
						    (&g_cThreadInTree) == 1
						    &&
						    ASMAtomicReadU32(&pThread->
								     cRefs) > 1)
							rtThreadNativeWaitKludge
							    (pThread);
#endif
					}
				}
			} else {
				rc = VERR_THREAD_NOT_WAITABLE;
				AssertRC(rc);
			}
			rtThreadRelease(pThread);
		}
	}
	return rc;
}

/**
 * Wait for the thread to terminate, resume on interruption.
 *
 * @returns     iprt status code.
 *              Will not return VERR_INTERRUPTED.
 * @param       Thread          The thread to wait for.
 * @param       cMillies        The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
 *                              an indefinite wait.
 * @param       prc             Where to store the return code of the thread. Optional.
 */
RTDECL(int)RTThreadWait(RTTHREAD Thread, RTMSINTERVAL cMillies, int *prc)
{
	int rc = rtThreadWait(Thread, cMillies, prc, true);
	Assert(rc != VERR_INTERRUPTED);
	return rc;
}

RT_EXPORT_SYMBOL(RTThreadWait);

/**
 * Wait for the thread to terminate, return on interruption.
 *
 * @returns     iprt status code.
 * @param       Thread          The thread to wait for.
 * @param       cMillies        The number of milliseconds to wait. Use RT_INDEFINITE_WAIT for
 *                              an indefinite wait.
 * @param       prc             Where to store the return code of the thread. Optional.
 */
RTDECL(int)RTThreadWaitNoResume(RTTHREAD Thread, RTMSINTERVAL cMillies,
				int *prc)
{
	return rtThreadWait(Thread, cMillies, prc, false);
}

RT_EXPORT_SYMBOL(RTThreadWaitNoResume);

/**
 * Changes the type of the specified thread.
 *
 * @returns iprt status code.
 * @param   Thread      The thread which type should be changed.
 * @param   enmType     The new thread type.
 */
RTDECL(int)RTThreadSetType(RTTHREAD Thread, RTTHREADTYPE enmType)
{
	/*
	 * Validate input.
	 */
	int rc;
	if (enmType > RTTHREADTYPE_INVALID && enmType < RTTHREADTYPE_END) {
		PRTTHREADINT pThread = rtThreadGet(Thread);
		if (pThread) {
			if (rtThreadIsAlive(pThread)) {
				/*
				 * Do the job.
				 */
				RT_THREAD_LOCK_RW();
				rc = rtThreadNativeSetPriority(pThread,
							       enmType);
				if (RT_SUCCESS(rc))
					ASMAtomicXchgSize(&pThread->enmType,
							  enmType);
				RT_THREAD_UNLOCK_RW();
				if (RT_FAILURE(rc))
					Log(("RTThreadSetType: failed on thread %p (%s), rc=%Rrc!!!\n", Thread, pThread->szName, rc));
			} else
				rc = VERR_THREAD_IS_DEAD;
			rtThreadRelease(pThread);
		} else
			rc = VERR_INVALID_HANDLE;
	} else {
		AssertMsgFailed(("enmType=%d\n", enmType));
		rc = VERR_INVALID_PARAMETER;
	}
	return rc;
}

RT_EXPORT_SYMBOL(RTThreadSetType);

/**
 * Gets the type of the specified thread.
 *
 * @returns The thread type.
 * @returns RTTHREADTYPE_INVALID if the thread handle is invalid.
 * @param   Thread      The thread in question.
 */
RTDECL(RTTHREADTYPE) RTThreadGetType(RTTHREAD Thread)
{
	RTTHREADTYPE enmType = RTTHREADTYPE_INVALID;
	PRTTHREADINT pThread = rtThreadGet(Thread);
	if (pThread) {
		enmType = pThread->enmType;
		rtThreadRelease(pThread);
	}
	return enmType;
}

RT_EXPORT_SYMBOL(RTThreadGetType);

#ifdef IN_RING3

/**
 * Recalculates scheduling attributes for the default process
 * priority using the specified priority type for the calling thread.
 *
 * The scheduling attributes are targeted at threads and they are protected
 * by the thread read-write semaphore, that's why RTProc is forwarding the
 * operation to RTThread.
 *
 * @returns iprt status code.
 * @remarks Will only work for strict builds.
 */
int rtThreadDoCalcDefaultPriority(RTTHREADTYPE enmType)
{
	RT_THREAD_LOCK_RW();
	int rc = rtSchedNativeCalcDefaultPriority(enmType);
	RT_THREAD_UNLOCK_RW();
	return rc;
}

/**
 * Thread enumerator - sets the priority of one thread.
 *
 * @returns 0 to continue.
 * @returns !0 to stop. In our case a VERR_ code.
 * @param   pNode   The thread node.
 * @param   pvUser  The new priority.
 */
static DECLCALLBACK(int) rtThreadSetPriorityOne(PAVLPVNODECORE pNode,
						void *pvUser)
{
	PRTTHREADINT pThread = (PRTTHREADINT) pNode;
	if (!rtThreadIsAlive(pThread))
		return VINF_SUCCESS;
	int rc = rtThreadNativeSetPriority(pThread, pThread->enmType);
	if (RT_SUCCESS(rc))	/* hide any warnings */
		return VINF_SUCCESS;
	NOREF(pvUser);
	return rc;
}

/**
 * Attempts to alter the priority of the current process.
 *
 * The scheduling attributes are targeted at threads and they are protected
 * by the thread read-write semaphore, that's why RTProc is forwarding the
 * operation to RTThread. This operation also involves updating all thread
 * which is much faster done from RTThread.
 *
 * @returns iprt status code.
 * @param   enmPriority     The new priority.
 */
DECLHIDDEN(int)rtThreadDoSetProcPriority(RTPROCPRIORITY enmPriority)
{
	LogFlow(("rtThreadDoSetProcPriority: enmPriority=%d\n", enmPriority));

	/*
	 * First validate that we're allowed by the OS to use all the
	 * scheduling attributes defined by the specified process priority.
	 */
	RT_THREAD_LOCK_RW();
	int rc = rtProcNativeSetPriority(enmPriority);
	if (RT_SUCCESS(rc)) {
		/*
		 * Update the priority of existing thread.
		 */
		rc = RTAvlPVDoWithAll(&g_ThreadTree, true,
				      rtThreadSetPriorityOne, NULL);
		if (RT_SUCCESS(rc))
			ASMAtomicXchgSize(&g_enmProcessPriority, enmPriority);
		else {
			/*
			 * Failed, restore the priority.
			 */
			rtProcNativeSetPriority(g_enmProcessPriority);
			RTAvlPVDoWithAll(&g_ThreadTree, true,
					 rtThreadSetPriorityOne, NULL);
		}
	}
	RT_THREAD_UNLOCK_RW();
	LogFlow(("rtThreadDoSetProcPriority: returns %Rrc\n", rc));
	return rc;
}

/**
 * Change the thread state to blocking.
 *
 * @param   hThread         The current thread.
 * @param   enmState        The sleep state.
 * @param   fReallySleeping Really going to sleep now.
 */
RTDECL(void)RTThreadBlocking(RTTHREAD hThread, RTTHREADSTATE enmState,
			     bool fReallySleeping)
{
	Assert(RTTHREAD_IS_SLEEPING(enmState));
	PRTTHREADINT pThread = hThread;
	if (pThread != NIL_RTTHREAD) {
		Assert(pThread == RTThreadSelf());
		if (rtThreadGetState(pThread) == RTTHREADSTATE_RUNNING)
			rtThreadSetState(pThread, enmState);
		ASMAtomicWriteBool(&pThread->fReallySleeping, fReallySleeping);
	}
}

RT_EXPORT_SYMBOL(RTThreadBlocking);

/**
 * Unblocks a thread.
 *
 * This function is paired with rtThreadBlocking.
 *
 * @param   hThread     The current thread.
 * @param   enmCurState The current state, used to check for nested blocking.
 *                      The new state will be running.
 */
RTDECL(void) RTThreadUnblocked(RTTHREAD hThread, RTTHREADSTATE enmCurState)
{
	PRTTHREADINT pThread = hThread;
	if (pThread != NIL_RTTHREAD) {
		Assert(pThread == RTThreadSelf());
		ASMAtomicWriteBool(&pThread->fReallySleeping, false);

		RTTHREADSTATE enmActualState = rtThreadGetState(pThread);
		if (enmActualState == enmCurState) {
			rtThreadSetState(pThread, RTTHREADSTATE_RUNNING);
			if (pThread->LockValidator.pRec
			    && pThread->LockValidator.enmRecState ==
			    enmCurState)
				ASMAtomicWriteNullPtr(&pThread->LockValidator.
						      pRec);
		}
		/* This is a bit ugly... :-/ */
		else if ((enmActualState == RTTHREADSTATE_TERMINATED
			  || enmActualState == RTTHREADSTATE_INITIALIZING)
			 && pThread->LockValidator.pRec)
			ASMAtomicWriteNullPtr(&pThread->LockValidator.pRec);
		Assert(pThread->LockValidator.pRec == NULL
		       || RTTHREAD_IS_SLEEPING(enmActualState));
	}
}

RT_EXPORT_SYMBOL(RTThreadUnblocked);

/**
 * Get the current thread state.
 *
 * @returns The thread state.
 * @param   hThread         The thread.
 */
RTDECL(RTTHREADSTATE) RTThreadGetState(RTTHREAD hThread)
{
	RTTHREADSTATE enmState = RTTHREADSTATE_INVALID;
	PRTTHREADINT pThread = rtThreadGet(hThread);
	if (pThread) {
		enmState = rtThreadGetState(pThread);
		rtThreadRelease(pThread);
	}
	return enmState;
}

RT_EXPORT_SYMBOL(RTThreadGetState);

RTDECL(RTTHREADSTATE) RTThreadGetReallySleeping(RTTHREAD hThread)
{
	RTTHREADSTATE enmState = RTTHREADSTATE_INVALID;
	PRTTHREADINT pThread = rtThreadGet(hThread);
	if (pThread) {
		enmState = rtThreadGetState(pThread);
		if (!ASMAtomicUoReadBool(&pThread->fReallySleeping))
			enmState = RTTHREADSTATE_RUNNING;
		rtThreadRelease(pThread);
	}
	return enmState;
}

RT_EXPORT_SYMBOL(RTThreadGetReallySleeping);

/**
 * Translate a thread state into a string.
 *
 * @returns Pointer to a read-only string containing the state name.
 * @param   enmState            The state.
 */
RTDECL(const char *)RTThreadStateName(RTTHREADSTATE enmState)
{
	switch (enmState) {
	case RTTHREADSTATE_INVALID:
		return "INVALID";
	case RTTHREADSTATE_INITIALIZING:
		return "INITIALIZING";
	case RTTHREADSTATE_TERMINATED:
		return "TERMINATED";
	case RTTHREADSTATE_RUNNING:
		return "RUNNING";
	case RTTHREADSTATE_CRITSECT:
		return "CRITSECT";
	case RTTHREADSTATE_EVENT:
		return "EVENT";
	case RTTHREADSTATE_EVENT_MULTI:
		return "EVENT_MULTI";
	case RTTHREADSTATE_FAST_MUTEX:
		return "FAST_MUTEX";
	case RTTHREADSTATE_MUTEX:
		return "MUTEX";
	case RTTHREADSTATE_RW_READ:
		return "RW_READ";
	case RTTHREADSTATE_RW_WRITE:
		return "RW_WRITE";
	case RTTHREADSTATE_SLEEP:
		return "SLEEP";
	case RTTHREADSTATE_SPIN_MUTEX:
		return "SPIN_MUTEX";
	default:
		return "UnknownThreadState";
	}
}

RT_EXPORT_SYMBOL(RTThreadStateName);

#endif /* IN_RING3 */
#ifdef IPRT_WITH_GENERIC_TLS

/**
 * Thread enumerator - clears a TLS entry.
 *
 * @returns 0.
 * @param   pNode   The thread node.
 * @param   pvUser  The TLS index.
 */
static DECLCALLBACK(int) rtThreadClearTlsEntryCallback(PAVLPVNODECORE pNode,
						       void *pvUser)
{
	PRTTHREADINT pThread = (PRTTHREADINT) pNode;
	RTTLS iTls = (RTTLS) (uintptr_t) pvUser;
	ASMAtomicWriteNullPtr(&pThread->apvTlsEntries[iTls]);
	return 0;
}

/**
 * Helper for the generic TLS implementation that clears a given TLS
 * entry on all threads.
 *
 * @param   iTls        The TLS entry. (valid)
 */
DECLHIDDEN(void)rtThreadClearTlsEntry(RTTLS iTls)
{
	RT_THREAD_LOCK_RD();
	RTAvlPVDoWithAll(&g_ThreadTree, true /* fFromLeft */ ,
			 rtThreadClearTlsEntryCallback,
			 (void *)(uintptr_t) iTls);
	RT_THREAD_UNLOCK_RD();
}

#endif /* IPRT_WITH_GENERIC_TLS */

#if defined(RT_OS_WINDOWS) && defined(IN_RING3)

/**
 * Thread enumeration callback for RTThreadNameThreads
 */
static DECLCALLBACK(int) rtThreadNameThreadCallback(PAVLPVNODECORE pNode,
						    void *pvUser)
{
	PRTTHREADINT pThread = (PRTTHREADINT) pNode;
	rtThreadNativeInformDebugger(pThread);
	RT_NOREF_PV(pvUser);
	return 0;
}

/**
 * A function that can be called from the windows debugger to get the names of
 * all threads when attaching to a process.
 *
 * Usage: .call VBoxRT!RTThreadNameThreads()
 *
 * @returns 0
 * @remarks Do not call from source code as it skips locks.
 */
extern "C" RTDECL(int) RTThreadNameThreads(void);
RTDECL(int) RTThreadNameThreads(void)
{
	return RTAvlPVDoWithAll(&g_ThreadTree, true /* fFromLeft */ ,
				rtThreadNameThreadCallback, NULL);
}

#endif
