Index: /trunk/src/VBox/Runtime/testcase/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 19953)
+++ /trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 19954)
@@ -53,5 +53,5 @@
 	tstRTBitOperations \
 	tstRTCidr \
-	tstCritSect \
+	tstRTCritSect \
 	tstDeadlock \
 	tstDir \
@@ -103,5 +103,5 @@
 PROGRAMS.win += \
 	tstRTProcWait \
-	tstCritSectW32 \
+	tstRTCritSectW32 \
 	tstFileAppendWin-1 \
 	ntGetTimerResolution
@@ -153,8 +153,10 @@
 tstRTCidr_SOURCES = tstRTCidr.cpp
 
-tstCritSect_SOURCES = tstCritSect.cpp
-
-tstCritSectW32_SOURCES = tstCritSect.cpp
-tstCritSectW32_DEFS = TRY_WIN32_CRIT
+tstRTCritSect_TEMPLATE = VBOXR3TSTEXE
+tstRTCritSect_SOURCES = tstRTCritSect.cpp
+
+tstRTCritSectW32_TEMPLATE = VBOXR3TSTEXE
+tstRTCritSectW32_SOURCES = tstRTCritSect.cpp
+tstRTCritSectW32_DEFS = TRY_WIN32_CRIT
 
 tstDarwinSched_SOURCES = tstDarwinSched.cpp
Index: unk/src/VBox/Runtime/testcase/tstCritSect.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstCritSect.cpp	(revision 19953)
+++ 	(revision )
@@ -1,549 +1,0 @@
-/* $Id$ */
-/** @file
- * IPRT Testcase - Critical Sections.
- */
-
-/*
- * Copyright (C) 2006-2009 Sun Microsystems, Inc.
- *
- * 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.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
- * Clara, CA 95054 USA or visit http://www.sun.com if you need
- * additional information or have any questions.
- */
-
-/*******************************************************************************
-*   Header Files                                                               *
-*******************************************************************************/
-#ifdef TRY_WIN32_CRIT
-# include <Windows.h>
-#endif
-#include <iprt/critsect.h>
-
-#include <iprt/asm.h>
-#include <iprt/assert.h>
-#include <iprt/ctype.h>
-#include <iprt/err.h>
-#include <iprt/initterm.h>
-#include <iprt/getopt.h>
-#include <iprt/lock.h>
-#include <iprt/log.h>
-#include <iprt/mem.h>
-#include <iprt/semaphore.h>
-#include <iprt/string.h>
-#include <iprt/test.h>
-#include <iprt/time.h>
-#include <iprt/thread.h>
-
-
-#ifndef TRY_WIN32_CRIT
-# define LOCKERS(sect)   ((sect).cLockers)
-#else /* TRY_WIN32_CRIT */
-
-/* This is for comparing with the "real thing". */
-#define RTCRITSECT      CRITICAL_SECTION
-#define PRTCRITSECT     LPCRITICAL_SECTION
-#define LOCKERS(sect)   (*(LONG volatile *)&(sect).LockCount)
-
-DECLINLINE(int) RTCritSectInit(PCRITICAL_SECTION pCritSect)
-{
-    InitializeCriticalSection(pCritSect);
-    return VINF_SUCCESS;
-}
-
-#undef RTCritSectEnter
-DECLINLINE(int) RTCritSectEnter(PCRITICAL_SECTION pCritSect)
-{
-    EnterCriticalSection(pCritSect);
-    return VINF_SUCCESS;
-}
-
-DECLINLINE(int) RTCritSectLeave(PCRITICAL_SECTION pCritSect)
-{
-    LeaveCriticalSection(pCritSect);
-    return VINF_SUCCESS;
-}
-
-DECLINLINE(int) RTCritSectDelete(PCRITICAL_SECTION pCritSect)
-{
-    DeleteCriticalSection(pCritSect);
-    return VINF_SUCCESS;
-}
-
-#endif /* TRY_WIN32_CRIT */
-
-
-/*******************************************************************************
-*   Structures and Typedefs                                                    *
-*******************************************************************************/
-/**
- * Arguments to ThreadTest1().
- */
-typedef struct THREADTEST1ARGS
-{
-    /** The critical section. */
-    PRTCRITSECT         pCritSect;
-    /** The thread ordinal. */
-    uint32_t            iThread;
-    /** Pointer to the release counter. */
-    uint32_t volatile  *pu32Release;
-} THREADTEST1ARGS, *PTHREADTEST1ARGS;
-
-
-/**
- * Arguments to ThreadTest2().
- */
-typedef struct THREADTEST2ARGS
-{
-    /** The critical section. */
-    PRTCRITSECT         pCritSect;
-    /** The thread ordinal. */
-    uint32_t            iThread;
-    /** Pointer to the release counter. */
-    uint32_t volatile  *pu32Release;
-    /** Pointer to the alone indicator. */
-    uint32_t volatile  *pu32Alone;
-    /** Pointer to the previous thread variable. */
-    uint32_t volatile  *pu32Prev;
-    /** Pointer to the sequential enters counter. */
-    uint32_t volatile  *pcSeq;
-    /** Pointer to the reordered enters counter. */
-    uint32_t volatile  *pcReordered;
-    /** Pointer to the variable counting running threads. */
-    uint32_t volatile  *pcThreadRunning;
-    /** Number of times this thread was inside the section. */
-    uint32_t volatile   cTimes;
-    /** The number of threads. */
-    uint32_t            cThreads;
-    /** Number of iterations (sum of all threads). */
-    uint32_t            cIterations;
-    /** Yield while inside the section. */
-    unsigned            cCheckLoops;
-    /** Signal this when done. */
-    RTSEMEVENT          EventDone;
-} THREADTEST2ARGS, *PTHREADTEST2ARGS;
-
-
-/*******************************************************************************
-*   Global Variables                                                           *
-*******************************************************************************/
-/** The test handle. */
-static RTTEST g_hTest;
-
-
-
-/**
- * Thread which goes to sleep on the critsect and checks that it's released in the right order.
- */
-static DECLCALLBACK(int) ThreadTest1(RTTHREAD ThreadSelf, void *pvArgs)
-{
-    THREADTEST1ARGS Args = *(PTHREADTEST1ARGS)pvArgs;
-    Log2(("ThreadTest1: Start - iThread=%d ThreadSelf=%p\n", Args.iThread, ThreadSelf));
-    RTMemFree(pvArgs);
-
-    /*
-     * Enter it.
-     */
-    int rc = RTCritSectEnter(Args.pCritSect);
-    if (RT_FAILURE(rc))
-    {
-        RTTestFailed(g_hTest, "thread %d: RTCritSectEnter -> %Rrc", Args.iThread, rc);
-        return 1;
-    }
-
-    /*
-     * Check release order.
-     */
-    if (*Args.pu32Release != Args.iThread)
-        RTTestFailed(g_hTest, "thread %d: released as number %d", Args.iThread, *Args.pu32Release);
-    ASMAtomicIncU32(Args.pu32Release);
-
-    /*
-     * Leave it.
-     */
-    rc = RTCritSectLeave(Args.pCritSect);
-    if (RT_FAILURE(rc))
-    {
-        RTTestFailed(g_hTest, "thread %d: RTCritSectEnter -> %Rrc", Args.iThread, rc);
-        return 1;
-    }
-
-    Log2(("ThreadTest1: End - iThread=%d ThreadSelf=%p\n", Args.iThread, ThreadSelf));
-    return 0;
-}
-
-
-static int Test1(unsigned cThreads)
-{
-    RTTestSubF(g_hTest, "Test #1 with %u thread", cThreads);
-
-    /*
-     * Create a critical section.
-     */
-    RTCRITSECT CritSect;
-    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectInit(&CritSect), VINF_SUCCESS, 1);
-
-    /*
-     * Enter, leave and enter again.
-     */
-    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(&CritSect), VINF_SUCCESS, 1);
-    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectLeave(&CritSect), VINF_SUCCESS, 1);
-    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(&CritSect), VINF_SUCCESS, 1);
-
-    /*
-     * Now spawn threads which will go to sleep entering the critsect.
-     */
-    uint32_t    u32Release = 0;
-    for (uint32_t iThread = 0; iThread < cThreads; iThread++)
-    {
-        PTHREADTEST1ARGS pArgs = (PTHREADTEST1ARGS)RTMemAllocZ(sizeof(*pArgs));
-        pArgs->iThread = iThread;
-        pArgs->pCritSect = &CritSect;
-        pArgs->pu32Release = &u32Release;
-        int32_t     iLock = LOCKERS(CritSect);
-        RTTHREAD    Thread;
-        RTTEST_CHECK_RC_RET(g_hTest, RTThreadCreateF(&Thread, ThreadTest1, pArgs, 0, RTTHREADTYPE_DEFAULT, 0, "T%d", iThread), VINF_SUCCESS, 1);
-
-        /* wait for it to get into waiting. */
-        while (LOCKERS(CritSect) == iLock)
-            RTThreadSleep(10);
-        RTThreadSleep(20);
-    }
-
-    /*
-     * Now we'll release the threads and wait for all of them to quit.
-     */
-    u32Release = 0;
-    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectLeave(&CritSect), VINF_SUCCESS, 1);
-    while (u32Release < cThreads)
-        RTThreadSleep(10);
-
-    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectDelete(&CritSect), VINF_SUCCESS, 1);
-    return 0;
-}
-
-
-
-/**
- * Thread which goes to sleep on the critsect and checks
- * that it's released along and in the right order. This is done a number of times.
- *
- */
-static DECLCALLBACK(int) ThreadTest2(RTTHREAD ThreadSelf, void *pvArg)
-{
-    PTHREADTEST2ARGS pArgs = (PTHREADTEST2ARGS)pvArg;
-    Log2(("ThreadTest2: Start - iThread=%d ThreadSelf=%p\n", pArgs->iThread, ThreadSelf));
-    uint64_t    u64TSStart = 0;
-    ASMAtomicIncU32(pArgs->pcThreadRunning);
-
-    for (unsigned i = 0; *pArgs->pu32Release < pArgs->cIterations; i++)
-    {
-        /*
-         * Enter it.
-         */
-        int rc = RTCritSectEnter(pArgs->pCritSect);
-        if (RT_FAILURE(rc))
-        {
-            RTTestFailed(g_hTest, "thread %d, iteration %d: RTCritSectEnter -> %d", pArgs->iThread, i, rc);
-            return 1;
-        }
-        if (!u64TSStart)
-            u64TSStart = RTTimeNanoTS();
-
-#if 0 /* We just check for sequences. */
-        /*
-         * Check release order.
-         */
-        if ((*pArgs->pu32Release % pArgs->cThreads) != pArgs->iThread)
-            RTTestFailed(g_hTest, "thread %d, iteration %d: released as number %d (%d)",
-                         pArgs->iThread, i, *pArgs->pu32Release % pArgs->cThreads, *pArgs->pu32Release);
-        else
-            RTTestPrintf(g_hTest, RTTESTLVL_INFO, "iteration %d: released as number %d (%d)\n",
-                         pArgs->iThread, i, *pArgs->pu32Release % pArgs->cThreads, *pArgs->pu32Release);
-#endif
-        pArgs->cTimes++;
-        ASMAtomicIncU32(pArgs->pu32Release);
-
-        /*
-         * Check distribution every now and again.
-         */
-#if 0
-        if (!(*pArgs->pu32Release % 879))
-        {
-            uint32_t u32Perfect = *pArgs->pu32Release / pArgs->cThreads;
-            for (int iThread = 0 ; iThread < (int)pArgs->cThreads; iThread++)
-            {
-                int cDiff = pArgs[iThread - pArgs->iThread].cTimes - u32Perfect;
-                if ((unsigned)RT_ABS(cDiff) > RT_MAX(u32Perfect / 10000, 2))
-                {
-                    printf("tstCritSect: FAILURE - bad distribution thread %d u32Perfect=%d cTimes=%d cDiff=%d (runtime)\n",
-                           iThread, u32Perfect, pArgs[iThread - pArgs->iThread].cTimes, cDiff);
-                    ASMAtomicIncU32(&g_cErrors);
-                }
-            }
-        }
-#endif
-        /*
-         * Check alone and make sure we stay inside here a while
-         * so the other guys can get ready.
-         */
-        uint32_t u32;
-        for (u32 = 0; u32 < pArgs->cCheckLoops; u32++)
-        {
-            if (*pArgs->pu32Alone != ~0U)
-            {
-                RTTestFailed(g_hTest, "thread %d, iteration %d: not alone!!!", pArgs->iThread, i);
-                //AssertReleaseMsgFailed(("Not alone!\n"));
-                return 1;
-            }
-        }
-        ASMAtomicCmpXchgU32(pArgs->pu32Alone, pArgs->iThread, ~0);
-        for (u32 = 0; u32 < pArgs->cCheckLoops; u32++)
-        {
-            if (*pArgs->pu32Alone != pArgs->iThread)
-            {
-                RTTestFailed(g_hTest, "thread %d, iteration %d: not alone!!!", pArgs->iThread, i);
-                //AssertReleaseMsgFailed(("Not alone!\n"));
-                return 1;
-            }
-        }
-        ASMAtomicXchgU32(pArgs->pu32Alone, ~0);
-
-        /*
-         * Check for sequences.
-         */
-        if (*pArgs->pu32Prev == pArgs->iThread && pArgs->cThreads > 1)
-            ASMAtomicIncU32(pArgs->pcSeq);
-        else if ((*pArgs->pu32Prev + 1) % pArgs->cThreads != pArgs->iThread)
-            ASMAtomicIncU32(pArgs->pcReordered);
-        ASMAtomicXchgU32(pArgs->pu32Prev, pArgs->iThread);
-
-        /*
-         * Leave it.
-         */
-        rc = RTCritSectLeave(pArgs->pCritSect);
-        if (RT_FAILURE(rc))
-        {
-            RTTestFailed(g_hTest, "thread %d, iteration %d: RTCritSectEnter -> %d", pArgs->iThread, i, rc);
-            return 1;
-        }
-    }
-
-    uint64_t u64TSEnd = RTTimeNanoTS(); NOREF(u64TSEnd);
-    ASMAtomicDecU32(pArgs->pcThreadRunning);
-    RTSemEventSignal(pArgs->EventDone);
-    Log2(("ThreadTest2: End - iThread=%d ThreadSelf=%p time=%lld\n", pArgs->iThread, ThreadSelf, u64TSEnd - u64TSStart));
-    return 0;
-}
-
-static int Test2(unsigned cThreads, unsigned cIterations, unsigned cCheckLoops)
-{
-    RTTestSubF(g_hTest, "Test #2 - cThreads=%u cIterations=%u cCheckLoops=%u", cThreads, cIterations, cCheckLoops);
-
-    /*
-     * Create a critical section.
-     */
-    RTCRITSECT CritSect;
-    int rc;
-    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectInit(&CritSect), VINF_SUCCESS, 1);
-
-    /*
-     * Enter, leave and enter again.
-     */
-    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(&CritSect), VINF_SUCCESS, 1);
-    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectLeave(&CritSect), VINF_SUCCESS, 1);
-    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(&CritSect), VINF_SUCCESS, 1);
-
-    /*
-     * Now spawn threads which will go to sleep entering the critsect.
-     */
-    PTHREADTEST2ARGS paArgs = (PTHREADTEST2ARGS)RTMemAllocZ(sizeof(THREADTEST2ARGS) * cThreads);
-    RTSEMEVENT       EventDone;
-    RTTEST_CHECK_RC_RET(g_hTest, RTSemEventCreate(&EventDone), VINF_SUCCESS, 1);
-    uint32_t volatile   u32Release = 0;
-    uint32_t volatile   u32Alone = ~0;
-    uint32_t volatile   u32Prev = ~0;
-    uint32_t volatile   cSeq = 0;
-    uint32_t volatile   cReordered = 0;
-    uint32_t volatile   cThreadRunning = 0;
-    unsigned iThread;
-    for (iThread = 0; iThread < cThreads; iThread++)
-    {
-        paArgs[iThread].iThread     = iThread;
-        paArgs[iThread].pCritSect   = &CritSect;
-        paArgs[iThread].pu32Release = &u32Release;
-        paArgs[iThread].pu32Alone   = &u32Alone;
-        paArgs[iThread].pu32Prev    = &u32Prev;
-        paArgs[iThread].pcSeq       = &cSeq;
-        paArgs[iThread].pcReordered = &cReordered;
-        paArgs[iThread].pcThreadRunning = &cThreadRunning;
-        paArgs[iThread].cTimes      = 0;
-        paArgs[iThread].cThreads    = cThreads;
-        paArgs[iThread].cIterations = cIterations;
-        paArgs[iThread].cCheckLoops = cCheckLoops;
-        paArgs[iThread].EventDone   = EventDone;
-        int32_t     iLock = LOCKERS(CritSect);
-        char szThread[17];
-        RTStrPrintf(szThread, sizeof(szThread), "T%d", iThread);
-        RTTHREAD  Thread;
-        rc = RTThreadCreate(&Thread, ThreadTest2, &paArgs[iThread], 0, RTTHREADTYPE_DEFAULT, 0, szThread);
-        if (RT_FAILURE(rc))
-        {
-            RTTestFailed(g_hTest, "RTThreadCreate -> %d", rc);
-            return 1;
-        }
-        /* wait for it to get into waiting. */
-        while (LOCKERS(CritSect) == iLock)
-            RTThreadSleep(10);
-        RTThreadSleep(20);
-    }
-    RTTestPrintf(g_hTest, RTTESTLVL_INFO, "threads created...\n");
-
-    /*
-     * Now we'll release the threads and wait for all of them to quit.
-     */
-    u32Release = 0;
-    uint64_t u64TSStart = RTTimeNanoTS();
-    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectLeave(&CritSect), VINF_SUCCESS, 1);
-
-    while (cThreadRunning > 0)
-        RTSemEventWait(EventDone, RT_INDEFINITE_WAIT);
-    uint64_t u64TSEnd = RTTimeNanoTS();
-
-    /*
-     * Clean up and report results.
-     */
-    RTTEST_CHECK_RC(g_hTest, RTCritSectDelete(&CritSect), VINF_SUCCESS);
-
-    /* sequences */
-    if (cSeq > RT_MAX(u32Release / 10000, 1))
-        RTTestFailed(g_hTest, "too many same thread sequences! cSeq=%d\n", cSeq);
-
-    /* distribution caused by sequences / reordering. */
-    unsigned cDiffTotal = 0;
-    uint32_t u32Perfect = (u32Release + cThreads / 2) / cThreads;
-    for (iThread = 0; iThread < cThreads; iThread++)
-    {
-        int cDiff = paArgs[iThread].cTimes - u32Perfect;
-        if ((unsigned)RT_ABS(cDiff) > RT_MAX(u32Perfect / 10000, 2))
-            RTTestFailed(g_hTest, "bad distribution thread %d u32Perfect=%d cTimes=%d cDiff=%d\n",
-                         iThread, u32Perfect, paArgs[iThread].cTimes, cDiff);
-        cDiffTotal += RT_ABS(cDiff);
-    }
-
-    uint32_t cMillies = (uint32_t)((u64TSEnd - u64TSStart) / 1000000);
-    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
-                 "%d enter+leave in %dms cSeq=%d cReordered=%d cDiffTotal=%d\n",
-                 u32Release, cMillies, cSeq, cReordered, cDiffTotal);
-    return 0;
-}
-
-
-int main(int argc, char **argv)
-{
-    int rc = RTR3Init();
-    if (RT_FAILURE(rc))
-        return 1;
-    RTTEST hTest;
-#ifndef TRY_WIN32_CRT
-    rc = RTTestCreate("tstRTCritSect", &hTest);
-#else
-    rc = RTTestCreate("tstRTCritSectW32", &hTest);
-#endif
-    if (RT_FAILURE(rc))
-        return 1;
-    g_hTest = hTest;
-    RTTestBanner(hTest);
-
-    /* parse args. */
-    static const RTGETOPTDEF s_aOptions[] =
-    {
-        { "--distribution", 'd', RTGETOPT_REQ_NOTHING },
-        { "--help",         'h', RTGETOPT_REQ_NOTHING }
-    };
-
-    bool fTestDistribution = false;
-
-    int ch;
-    RTGETOPTUNION ValueUnion;
-    RTGETOPTSTATE GetState;
-    RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
-    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
-    {
-        switch (ch)
-        {
-            case 'd':
-                fTestDistribution = true;
-                break;
-
-            case 'h':
-                RTTestIPrintf(RTTESTLVL_ALWAYS, "%s [--help|-h] [--distribution|-d]\n", argv[0]);
-                return 1;
-
-            case VINF_GETOPT_NOT_OPTION:
-                RTTestIFailed("%Rrs\n", ch);
-                return RTTestSummaryAndDestroy(hTest);
-
-            default:
-                if (ch > 0)
-                {
-                    if (RT_C_IS_GRAPH(ch))
-                        RTTestIFailed("unhandled option: -%c\n", ch);
-                    else
-                        RTTestIFailed("unhandled option: %i\n", ch);
-                }
-                else if (ch == VERR_GETOPT_UNKNOWN_OPTION)
-                    RTTestIFailed("unknown option: %s\n", ValueUnion.psz);
-                else if (ValueUnion.pDef)
-                    RTTestIFailed("%s: %Rrs\n", ValueUnion.pDef->pszLong, ch);
-                else
-                    RTTestIFailed("%Rrs\n", ch);
-                return RTTestSummaryAndDestroy(hTest);
-        }
-    }
-
-
-    /*
-     * Perform the testing.
-     */
-    if (    !Test1(1)
-        &&  !Test1(3)
-        &&  !Test1(10)
-        &&  !Test1(63))
-    {
-
-        if (    fTestDistribution
-            &&  !Test2(1, 200000, 1000)
-            &&  !Test2(2, 200000, 1000)
-            &&  !Test2(3, 200000, 1000)
-            &&  !Test2(4, 200000, 1000)
-            &&  !Test2(5, 200000, 1000)
-            &&  !Test2(7, 200000, 1000)
-            &&  !Test2(67, 200000, 1000))
-        {
-            /*nothing*/;
-        }
-    }
-
-    /*
-     * Summary.
-     */
-    return RTTestSummaryAndDestroy(hTest);
-}
-
Index: /trunk/src/VBox/Runtime/testcase/tstRTCritSect.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTCritSect.cpp	(revision 19954)
+++ /trunk/src/VBox/Runtime/testcase/tstRTCritSect.cpp	(revision 19954)
@@ -0,0 +1,549 @@
+/* $Id$ */
+/** @file
+ * IPRT Testcase - Critical Sections.
+ */
+
+/*
+ * Copyright (C) 2006-2009 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#ifdef TRY_WIN32_CRIT
+# include <Windows.h>
+#endif
+#include <iprt/critsect.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/initterm.h>
+#include <iprt/getopt.h>
+#include <iprt/lock.h>
+#include <iprt/log.h>
+#include <iprt/mem.h>
+#include <iprt/semaphore.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+#include <iprt/time.h>
+#include <iprt/thread.h>
+
+
+#ifndef TRY_WIN32_CRIT
+# define LOCKERS(sect)   ((sect).cLockers)
+#else /* TRY_WIN32_CRIT */
+
+/* This is for comparing with the "real thing". */
+#define RTCRITSECT      CRITICAL_SECTION
+#define PRTCRITSECT     LPCRITICAL_SECTION
+#define LOCKERS(sect)   (*(LONG volatile *)&(sect).LockCount)
+
+DECLINLINE(int) RTCritSectInit(PCRITICAL_SECTION pCritSect)
+{
+    InitializeCriticalSection(pCritSect);
+    return VINF_SUCCESS;
+}
+
+#undef RTCritSectEnter
+DECLINLINE(int) RTCritSectEnter(PCRITICAL_SECTION pCritSect)
+{
+    EnterCriticalSection(pCritSect);
+    return VINF_SUCCESS;
+}
+
+DECLINLINE(int) RTCritSectLeave(PCRITICAL_SECTION pCritSect)
+{
+    LeaveCriticalSection(pCritSect);
+    return VINF_SUCCESS;
+}
+
+DECLINLINE(int) RTCritSectDelete(PCRITICAL_SECTION pCritSect)
+{
+    DeleteCriticalSection(pCritSect);
+    return VINF_SUCCESS;
+}
+
+#endif /* TRY_WIN32_CRIT */
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * Arguments to ThreadTest1().
+ */
+typedef struct THREADTEST1ARGS
+{
+    /** The critical section. */
+    PRTCRITSECT         pCritSect;
+    /** The thread ordinal. */
+    uint32_t            iThread;
+    /** Pointer to the release counter. */
+    uint32_t volatile  *pu32Release;
+} THREADTEST1ARGS, *PTHREADTEST1ARGS;
+
+
+/**
+ * Arguments to ThreadTest2().
+ */
+typedef struct THREADTEST2ARGS
+{
+    /** The critical section. */
+    PRTCRITSECT         pCritSect;
+    /** The thread ordinal. */
+    uint32_t            iThread;
+    /** Pointer to the release counter. */
+    uint32_t volatile  *pu32Release;
+    /** Pointer to the alone indicator. */
+    uint32_t volatile  *pu32Alone;
+    /** Pointer to the previous thread variable. */
+    uint32_t volatile  *pu32Prev;
+    /** Pointer to the sequential enters counter. */
+    uint32_t volatile  *pcSeq;
+    /** Pointer to the reordered enters counter. */
+    uint32_t volatile  *pcReordered;
+    /** Pointer to the variable counting running threads. */
+    uint32_t volatile  *pcThreadRunning;
+    /** Number of times this thread was inside the section. */
+    uint32_t volatile   cTimes;
+    /** The number of threads. */
+    uint32_t            cThreads;
+    /** Number of iterations (sum of all threads). */
+    uint32_t            cIterations;
+    /** Yield while inside the section. */
+    unsigned            cCheckLoops;
+    /** Signal this when done. */
+    RTSEMEVENT          EventDone;
+} THREADTEST2ARGS, *PTHREADTEST2ARGS;
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** The test handle. */
+static RTTEST g_hTest;
+
+
+
+/**
+ * Thread which goes to sleep on the critsect and checks that it's released in the right order.
+ */
+static DECLCALLBACK(int) ThreadTest1(RTTHREAD ThreadSelf, void *pvArgs)
+{
+    THREADTEST1ARGS Args = *(PTHREADTEST1ARGS)pvArgs;
+    Log2(("ThreadTest1: Start - iThread=%d ThreadSelf=%p\n", Args.iThread, ThreadSelf));
+    RTMemFree(pvArgs);
+
+    /*
+     * Enter it.
+     */
+    int rc = RTCritSectEnter(Args.pCritSect);
+    if (RT_FAILURE(rc))
+    {
+        RTTestFailed(g_hTest, "thread %d: RTCritSectEnter -> %Rrc", Args.iThread, rc);
+        return 1;
+    }
+
+    /*
+     * Check release order.
+     */
+    if (*Args.pu32Release != Args.iThread)
+        RTTestFailed(g_hTest, "thread %d: released as number %d", Args.iThread, *Args.pu32Release);
+    ASMAtomicIncU32(Args.pu32Release);
+
+    /*
+     * Leave it.
+     */
+    rc = RTCritSectLeave(Args.pCritSect);
+    if (RT_FAILURE(rc))
+    {
+        RTTestFailed(g_hTest, "thread %d: RTCritSectEnter -> %Rrc", Args.iThread, rc);
+        return 1;
+    }
+
+    Log2(("ThreadTest1: End - iThread=%d ThreadSelf=%p\n", Args.iThread, ThreadSelf));
+    return 0;
+}
+
+
+static int Test1(unsigned cThreads)
+{
+    RTTestSubF(g_hTest, "Test #1 with %u thread", cThreads);
+
+    /*
+     * Create a critical section.
+     */
+    RTCRITSECT CritSect;
+    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectInit(&CritSect), VINF_SUCCESS, 1);
+
+    /*
+     * Enter, leave and enter again.
+     */
+    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(&CritSect), VINF_SUCCESS, 1);
+    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectLeave(&CritSect), VINF_SUCCESS, 1);
+    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(&CritSect), VINF_SUCCESS, 1);
+
+    /*
+     * Now spawn threads which will go to sleep entering the critsect.
+     */
+    uint32_t    u32Release = 0;
+    for (uint32_t iThread = 0; iThread < cThreads; iThread++)
+    {
+        PTHREADTEST1ARGS pArgs = (PTHREADTEST1ARGS)RTMemAllocZ(sizeof(*pArgs));
+        pArgs->iThread = iThread;
+        pArgs->pCritSect = &CritSect;
+        pArgs->pu32Release = &u32Release;
+        int32_t     iLock = LOCKERS(CritSect);
+        RTTHREAD    Thread;
+        RTTEST_CHECK_RC_RET(g_hTest, RTThreadCreateF(&Thread, ThreadTest1, pArgs, 0, RTTHREADTYPE_DEFAULT, 0, "T%d", iThread), VINF_SUCCESS, 1);
+
+        /* wait for it to get into waiting. */
+        while (LOCKERS(CritSect) == iLock)
+            RTThreadSleep(10);
+        RTThreadSleep(20);
+    }
+
+    /*
+     * Now we'll release the threads and wait for all of them to quit.
+     */
+    u32Release = 0;
+    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectLeave(&CritSect), VINF_SUCCESS, 1);
+    while (u32Release < cThreads)
+        RTThreadSleep(10);
+
+    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectDelete(&CritSect), VINF_SUCCESS, 1);
+    return 0;
+}
+
+
+
+/**
+ * Thread which goes to sleep on the critsect and checks
+ * that it's released along and in the right order. This is done a number of times.
+ *
+ */
+static DECLCALLBACK(int) ThreadTest2(RTTHREAD ThreadSelf, void *pvArg)
+{
+    PTHREADTEST2ARGS pArgs = (PTHREADTEST2ARGS)pvArg;
+    Log2(("ThreadTest2: Start - iThread=%d ThreadSelf=%p\n", pArgs->iThread, ThreadSelf));
+    uint64_t    u64TSStart = 0;
+    ASMAtomicIncU32(pArgs->pcThreadRunning);
+
+    for (unsigned i = 0; *pArgs->pu32Release < pArgs->cIterations; i++)
+    {
+        /*
+         * Enter it.
+         */
+        int rc = RTCritSectEnter(pArgs->pCritSect);
+        if (RT_FAILURE(rc))
+        {
+            RTTestFailed(g_hTest, "thread %d, iteration %d: RTCritSectEnter -> %d", pArgs->iThread, i, rc);
+            return 1;
+        }
+        if (!u64TSStart)
+            u64TSStart = RTTimeNanoTS();
+
+#if 0 /* We just check for sequences. */
+        /*
+         * Check release order.
+         */
+        if ((*pArgs->pu32Release % pArgs->cThreads) != pArgs->iThread)
+            RTTestFailed(g_hTest, "thread %d, iteration %d: released as number %d (%d)",
+                         pArgs->iThread, i, *pArgs->pu32Release % pArgs->cThreads, *pArgs->pu32Release);
+        else
+            RTTestPrintf(g_hTest, RTTESTLVL_INFO, "iteration %d: released as number %d (%d)\n",
+                         pArgs->iThread, i, *pArgs->pu32Release % pArgs->cThreads, *pArgs->pu32Release);
+#endif
+        pArgs->cTimes++;
+        ASMAtomicIncU32(pArgs->pu32Release);
+
+        /*
+         * Check distribution every now and again.
+         */
+#if 0
+        if (!(*pArgs->pu32Release % 879))
+        {
+            uint32_t u32Perfect = *pArgs->pu32Release / pArgs->cThreads;
+            for (int iThread = 0 ; iThread < (int)pArgs->cThreads; iThread++)
+            {
+                int cDiff = pArgs[iThread - pArgs->iThread].cTimes - u32Perfect;
+                if ((unsigned)RT_ABS(cDiff) > RT_MAX(u32Perfect / 10000, 2))
+                {
+                    printf("tstCritSect: FAILURE - bad distribution thread %d u32Perfect=%d cTimes=%d cDiff=%d (runtime)\n",
+                           iThread, u32Perfect, pArgs[iThread - pArgs->iThread].cTimes, cDiff);
+                    ASMAtomicIncU32(&g_cErrors);
+                }
+            }
+        }
+#endif
+        /*
+         * Check alone and make sure we stay inside here a while
+         * so the other guys can get ready.
+         */
+        uint32_t u32;
+        for (u32 = 0; u32 < pArgs->cCheckLoops; u32++)
+        {
+            if (*pArgs->pu32Alone != ~0U)
+            {
+                RTTestFailed(g_hTest, "thread %d, iteration %d: not alone!!!", pArgs->iThread, i);
+                //AssertReleaseMsgFailed(("Not alone!\n"));
+                return 1;
+            }
+        }
+        ASMAtomicCmpXchgU32(pArgs->pu32Alone, pArgs->iThread, ~0);
+        for (u32 = 0; u32 < pArgs->cCheckLoops; u32++)
+        {
+            if (*pArgs->pu32Alone != pArgs->iThread)
+            {
+                RTTestFailed(g_hTest, "thread %d, iteration %d: not alone!!!", pArgs->iThread, i);
+                //AssertReleaseMsgFailed(("Not alone!\n"));
+                return 1;
+            }
+        }
+        ASMAtomicXchgU32(pArgs->pu32Alone, ~0);
+
+        /*
+         * Check for sequences.
+         */
+        if (*pArgs->pu32Prev == pArgs->iThread && pArgs->cThreads > 1)
+            ASMAtomicIncU32(pArgs->pcSeq);
+        else if ((*pArgs->pu32Prev + 1) % pArgs->cThreads != pArgs->iThread)
+            ASMAtomicIncU32(pArgs->pcReordered);
+        ASMAtomicXchgU32(pArgs->pu32Prev, pArgs->iThread);
+
+        /*
+         * Leave it.
+         */
+        rc = RTCritSectLeave(pArgs->pCritSect);
+        if (RT_FAILURE(rc))
+        {
+            RTTestFailed(g_hTest, "thread %d, iteration %d: RTCritSectEnter -> %d", pArgs->iThread, i, rc);
+            return 1;
+        }
+    }
+
+    uint64_t u64TSEnd = RTTimeNanoTS(); NOREF(u64TSEnd);
+    ASMAtomicDecU32(pArgs->pcThreadRunning);
+    RTSemEventSignal(pArgs->EventDone);
+    Log2(("ThreadTest2: End - iThread=%d ThreadSelf=%p time=%lld\n", pArgs->iThread, ThreadSelf, u64TSEnd - u64TSStart));
+    return 0;
+}
+
+static int Test2(unsigned cThreads, unsigned cIterations, unsigned cCheckLoops)
+{
+    RTTestSubF(g_hTest, "Test #2 - cThreads=%u cIterations=%u cCheckLoops=%u", cThreads, cIterations, cCheckLoops);
+
+    /*
+     * Create a critical section.
+     */
+    RTCRITSECT CritSect;
+    int rc;
+    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectInit(&CritSect), VINF_SUCCESS, 1);
+
+    /*
+     * Enter, leave and enter again.
+     */
+    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(&CritSect), VINF_SUCCESS, 1);
+    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectLeave(&CritSect), VINF_SUCCESS, 1);
+    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectEnter(&CritSect), VINF_SUCCESS, 1);
+
+    /*
+     * Now spawn threads which will go to sleep entering the critsect.
+     */
+    PTHREADTEST2ARGS paArgs = (PTHREADTEST2ARGS)RTMemAllocZ(sizeof(THREADTEST2ARGS) * cThreads);
+    RTSEMEVENT       EventDone;
+    RTTEST_CHECK_RC_RET(g_hTest, RTSemEventCreate(&EventDone), VINF_SUCCESS, 1);
+    uint32_t volatile   u32Release = 0;
+    uint32_t volatile   u32Alone = ~0;
+    uint32_t volatile   u32Prev = ~0;
+    uint32_t volatile   cSeq = 0;
+    uint32_t volatile   cReordered = 0;
+    uint32_t volatile   cThreadRunning = 0;
+    unsigned iThread;
+    for (iThread = 0; iThread < cThreads; iThread++)
+    {
+        paArgs[iThread].iThread     = iThread;
+        paArgs[iThread].pCritSect   = &CritSect;
+        paArgs[iThread].pu32Release = &u32Release;
+        paArgs[iThread].pu32Alone   = &u32Alone;
+        paArgs[iThread].pu32Prev    = &u32Prev;
+        paArgs[iThread].pcSeq       = &cSeq;
+        paArgs[iThread].pcReordered = &cReordered;
+        paArgs[iThread].pcThreadRunning = &cThreadRunning;
+        paArgs[iThread].cTimes      = 0;
+        paArgs[iThread].cThreads    = cThreads;
+        paArgs[iThread].cIterations = cIterations;
+        paArgs[iThread].cCheckLoops = cCheckLoops;
+        paArgs[iThread].EventDone   = EventDone;
+        int32_t     iLock = LOCKERS(CritSect);
+        char szThread[17];
+        RTStrPrintf(szThread, sizeof(szThread), "T%d", iThread);
+        RTTHREAD  Thread;
+        rc = RTThreadCreate(&Thread, ThreadTest2, &paArgs[iThread], 0, RTTHREADTYPE_DEFAULT, 0, szThread);
+        if (RT_FAILURE(rc))
+        {
+            RTTestFailed(g_hTest, "RTThreadCreate -> %d", rc);
+            return 1;
+        }
+        /* wait for it to get into waiting. */
+        while (LOCKERS(CritSect) == iLock)
+            RTThreadSleep(10);
+        RTThreadSleep(20);
+    }
+    RTTestPrintf(g_hTest, RTTESTLVL_INFO, "threads created...\n");
+
+    /*
+     * Now we'll release the threads and wait for all of them to quit.
+     */
+    u32Release = 0;
+    uint64_t u64TSStart = RTTimeNanoTS();
+    RTTEST_CHECK_RC_RET(g_hTest, RTCritSectLeave(&CritSect), VINF_SUCCESS, 1);
+
+    while (cThreadRunning > 0)
+        RTSemEventWait(EventDone, RT_INDEFINITE_WAIT);
+    uint64_t u64TSEnd = RTTimeNanoTS();
+
+    /*
+     * Clean up and report results.
+     */
+    RTTEST_CHECK_RC(g_hTest, RTCritSectDelete(&CritSect), VINF_SUCCESS);
+
+    /* sequences */
+    if (cSeq > RT_MAX(u32Release / 10000, 1))
+        RTTestFailed(g_hTest, "too many same thread sequences! cSeq=%d\n", cSeq);
+
+    /* distribution caused by sequences / reordering. */
+    unsigned cDiffTotal = 0;
+    uint32_t u32Perfect = (u32Release + cThreads / 2) / cThreads;
+    for (iThread = 0; iThread < cThreads; iThread++)
+    {
+        int cDiff = paArgs[iThread].cTimes - u32Perfect;
+        if ((unsigned)RT_ABS(cDiff) > RT_MAX(u32Perfect / 10000, 2))
+            RTTestFailed(g_hTest, "bad distribution thread %d u32Perfect=%d cTimes=%d cDiff=%d\n",
+                         iThread, u32Perfect, paArgs[iThread].cTimes, cDiff);
+        cDiffTotal += RT_ABS(cDiff);
+    }
+
+    uint32_t cMillies = (uint32_t)((u64TSEnd - u64TSStart) / 1000000);
+    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
+                 "%d enter+leave in %dms cSeq=%d cReordered=%d cDiffTotal=%d\n",
+                 u32Release, cMillies, cSeq, cReordered, cDiffTotal);
+    return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+    int rc = RTR3Init();
+    if (RT_FAILURE(rc))
+        return 1;
+    RTTEST hTest;
+#ifndef TRY_WIN32_CRT
+    rc = RTTestCreate("tstRTCritSect", &hTest);
+#else
+    rc = RTTestCreate("tstRTCritSectW32", &hTest);
+#endif
+    if (RT_FAILURE(rc))
+        return 1;
+    g_hTest = hTest;
+    RTTestBanner(hTest);
+
+    /* parse args. */
+    static const RTGETOPTDEF s_aOptions[] =
+    {
+        { "--distribution", 'd', RTGETOPT_REQ_NOTHING },
+        { "--help",         'h', RTGETOPT_REQ_NOTHING }
+    };
+
+    bool fTestDistribution = false;
+
+    int ch;
+    RTGETOPTUNION ValueUnion;
+    RTGETOPTSTATE GetState;
+    RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
+    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
+    {
+        switch (ch)
+        {
+            case 'd':
+                fTestDistribution = true;
+                break;
+
+            case 'h':
+                RTTestIPrintf(RTTESTLVL_ALWAYS, "%s [--help|-h] [--distribution|-d]\n", argv[0]);
+                return 1;
+
+            case VINF_GETOPT_NOT_OPTION:
+                RTTestIFailed("%Rrs\n", ch);
+                return RTTestSummaryAndDestroy(hTest);
+
+            default:
+                if (ch > 0)
+                {
+                    if (RT_C_IS_GRAPH(ch))
+                        RTTestIFailed("unhandled option: -%c\n", ch);
+                    else
+                        RTTestIFailed("unhandled option: %i\n", ch);
+                }
+                else if (ch == VERR_GETOPT_UNKNOWN_OPTION)
+                    RTTestIFailed("unknown option: %s\n", ValueUnion.psz);
+                else if (ValueUnion.pDef)
+                    RTTestIFailed("%s: %Rrs\n", ValueUnion.pDef->pszLong, ch);
+                else
+                    RTTestIFailed("%Rrs\n", ch);
+                return RTTestSummaryAndDestroy(hTest);
+        }
+    }
+
+
+    /*
+     * Perform the testing.
+     */
+    if (    !Test1(1)
+        &&  !Test1(3)
+        &&  !Test1(10)
+        &&  !Test1(63))
+    {
+
+        if (    fTestDistribution
+            &&  !Test2(1, 200000, 1000)
+            &&  !Test2(2, 200000, 1000)
+            &&  !Test2(3, 200000, 1000)
+            &&  !Test2(4, 200000, 1000)
+            &&  !Test2(5, 200000, 1000)
+            &&  !Test2(7, 200000, 1000)
+            &&  !Test2(67, 200000, 1000))
+        {
+            /*nothing*/;
+        }
+    }
+
+    /*
+     * Summary.
+     */
+    return RTTestSummaryAndDestroy(hTest);
+}
+
