Index: /trunk/src/VBox/Runtime/testcase/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 19932)
+++ /trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 19933)
@@ -82,4 +82,5 @@
 	tstRand \
 	tstRTFsQueries \
+	tstR0ThreadPreemptionDriver \
 	tstSemPingPong \
 	tstStrFormat \
@@ -118,5 +119,6 @@
 SYSMODS += \
 	tstLdrObj \
-	tstLdrObjR0
+	tstLdrObjR0 \
+	tstR0ThreadPreemption
 if1of ($(VBOX_LDR_FMT)), lx pe)
 LIBRARIES += \
@@ -302,4 +304,16 @@
 tstRand_SOURCES = tstRand.cpp
 
+tstR0ThreadPreemption_TEMPLATE = VBOXR0
+tstR0ThreadPreemption_INST = $(INST_TESTCASE)
+tstR0ThreadPreemption_DEFS = IN_RT_R0
+tstR0ThreadPreemption_SYSSUFF = .r0
+tstR0ThreadPreemption_SOURCES = tstR0ThreadPreemption.cpp
+tstR0ThreadPreemption_LIBS = $(PATH_LIB)/RuntimeR0$(VBOX_SUFF_LIB)
+if1of ($(VBOX_LDR_FMT), pe lx)
+ tstR0ThreadPreemption_LIBS += $(PATH_LIB)/SUPR0$(VBOX_SUFF_LIB)
+endif
+
+tstR0ThreadPreemptionDriver_SOURCES = tstR0ThreadPreemptionDriver.cpp
+
 tstRTFsQueries_SOURCES = tstRTFsQueries.cpp
 
Index: /trunk/src/VBox/Runtime/testcase/tstR0ThreadPreemption.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstR0ThreadPreemption.cpp	(revision 19933)
+++ /trunk/src/VBox/Runtime/testcase/tstR0ThreadPreemption.cpp	(revision 19933)
@@ -0,0 +1,131 @@
+/* $Id$ */
+/** @file
+ * IPRT R0 Testcase - Thread Preemption.
+ */
+
+/*
+ * Copyright (C) 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                                                               *
+*******************************************************************************/
+#include <iprt/thread.h>
+
+#include <iprt/err.h>
+#include <iprt/time.h>
+#include <iprt/string.h>
+#include <VBox/sup.h>
+#include <VBox/x86.h>
+#include "tstR0ThreadPreemption.h"
+
+
+
+/**
+ * Service request callback function.
+ *
+ * @returns VBox status code.
+ * @param   pSession    The caller's session.
+ * @param   u64Arg      64-bit integer argument.
+ * @param   pReqHdr     The request header. Input / Output. Optional.
+ */
+DECLEXPORT(int) TSTR0ThreadPreemptionSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOperation,
+                                                   uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
+{
+    if (u64Arg)
+        return VERR_INVALID_PARAMETER;
+    if (!VALID_PTR(pReqHdr))
+        return VERR_INVALID_PARAMETER;
+    char   *pszErr = (char *)(pReqHdr + 1);
+    size_t  cchErr = pReqHdr->cbReq - sizeof(*pReqHdr);
+    if (cchErr < 32 || cchErr >= 0x10000)
+        return VERR_INVALID_PARAMETER;
+    *pszErr = '\0';
+
+    /*
+     * The big switch.
+     */
+    switch (uOperation)
+    {
+        case TSTR0THREADPREMEPTION_SANITY_OK:
+            break;
+
+        case TSTR0THREADPREMEPTION_SANITY_FAILURE:
+            RTStrPrintf(pszErr, cchErr, "!42failure42%1024s", "");
+            break;
+
+        case TSTR0THREADPREMEPTION_BASIC:
+        {
+            RTTHREADPREEMPTSTATE State = RTTHREADPREEMPTSTATE_INITIALIZER;
+            RTThreadPreemptDisable(&State);
+            if (RTThreadPreemptIsEnabled(NIL_RTTHREAD))
+                RTStrPrintf(pszErr, cchErr, "!RTThreadPreemptIsEnabled returns true after RTThreadPreemptDisable");
+            RTThreadPreemptRestore(&State);
+            break;
+        }
+
+        case TSTR0THREADPREMEPTION_IS_PENDING:
+        {
+            RTTHREADPREEMPTSTATE State = RTTHREADPREEMPTSTATE_INITIALIZER;
+            RTThreadPreemptDisable(&State);
+            if (!RTThreadPreemptIsEnabled(NIL_RTTHREAD))
+            {
+                if (ASMGetFlags() & X86_EFL_IF)
+                {
+                    uint64_t    u64StartTS    = RTTimeNanoTS();
+                    uint64_t    cLoops        = 0;
+                    uint64_t    cNanosElapsed;
+                    bool        fPending;
+                    do
+                    {
+                        fPending = RTThreadPreemptIsPending(NIL_RTTHREAD);
+                        cNanosElapsed = RTTimeNanoTS() - u64StartTS;
+                        cLoops++;
+                    } while (   !fPending
+                             && cNanosElapsed < UINT64_C(60)*1000U*1000U*1000U);
+                    if (fPending)
+                        RTStrPrintf(pszErr, cchErr, "RTThreadPreemptIsPending returned true after %llu loops / %llu ns\n",
+                                    cLoops, cNanosElapsed);
+                    else
+                        RTStrPrintf(pszErr, cchErr, "!Preempt not pending after %llu loops / %llu ns\n",
+                                    cLoops, cNanosElapsed);
+                }
+                else
+                    RTStrPrintf(pszErr, cchErr, "!Interrupts disabled");
+            }
+            else
+                RTStrPrintf(pszErr, cchErr, "!RTThreadPreemptIsEnabled returns true after RTThreadPreemptDisable");
+            RTThreadPreemptRestore(&State);
+            break;
+        }
+
+        default:
+            RTStrPrintf(pszErr, cchErr, "!Unknown test #%d\n", uOperation);
+            break;
+    }
+
+    /* The error indicator is the '!' in the message buffer. */
+    return VINF_SUCCESS;
+}
+
Index: /trunk/src/VBox/Runtime/testcase/tstR0ThreadPreemption.h
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstR0ThreadPreemption.h	(revision 19933)
+++ /trunk/src/VBox/Runtime/testcase/tstR0ThreadPreemption.h	(revision 19933)
@@ -0,0 +1,45 @@
+/* $Id$ */
+/** @file
+ * IPRT R0 Testcase - Thread Preemption, common header.
+ */
+
+/*
+ * Copyright (C) 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.
+ */
+
+#ifdef IN_RING0
+__BEGIN_DECLS
+DECLEXPORT(int) TSTR0ThreadPreemptionSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOperation,
+                                                   uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr);
+__END_DECLS
+#endif
+
+enum TSTR0THREADPREMEPTION
+{
+    TSTR0THREADPREMEPTION_SANITY_OK = 1,
+    TSTR0THREADPREMEPTION_SANITY_FAILURE,
+    TSTR0THREADPREMEPTION_BASIC,
+    TSTR0THREADPREMEPTION_IS_PENDING,
+} TSTR0THREADPREMEPTION;
+
Index: /trunk/src/VBox/Runtime/testcase/tstR0ThreadPreemptionDriver.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstR0ThreadPreemptionDriver.cpp	(revision 19933)
+++ /trunk/src/VBox/Runtime/testcase/tstR0ThreadPreemptionDriver.cpp	(revision 19933)
@@ -0,0 +1,169 @@
+/* $Id$ */
+/** @file
+ * IPRT R0 Testcase - Thread Preemption, driver program.
+ */
+
+/*
+ * Copyright (C) 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                                                               *
+*******************************************************************************/
+#include <iprt/initterm.h>
+
+#include <iprt/err.h>
+#include <iprt/path.h>
+#include <iprt/param.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+#ifdef VBOX
+# include <VBox/sup.h>
+# include "tstR0ThreadPreemption.h"
+#endif
+
+
+int main(int argc, char **argv)
+{
+#ifndef VBOX
+    RTPrintf("tstSup: SKIPPED\n");
+    return 0;
+#else
+    /*
+     * Init.
+     */
+    int rc = RTR3InitAndSUPLib();
+    if (RT_FAILURE(rc))
+    {
+        RTPrintf("tstR0ThreadPreemption: fatal error: RTR3InitAndSUPLib failed with rc=%Rrc\n", rc);
+        return 1;
+    }
+
+    RTTEST hTest;
+    rc = RTTestCreate("tstR0ThreadPreemption", &hTest);
+    if (RT_FAILURE(rc))
+    {
+        RTPrintf("tstR0ThreadPreemption: fatal error: RTTestCreate failed with rc=%Rrc\n", rc);
+        return 1;
+    }
+    RTTestBanner(hTest);
+
+    PSUPDRVSESSION pSession;
+    rc = SUPR3Init(&pSession);
+    if (RT_FAILURE(rc))
+    {
+        RTTestFailed(hTest, "SUPR3Init failed with rc=%Rrc\n", rc);
+        return RTTestSummaryAndDestroy(hTest);
+    }
+
+    char szPath[RTPATH_MAX];
+    rc = RTPathExecDir(szPath, sizeof(szPath));
+    if (RT_SUCCESS(rc))
+        rc = RTPathAppend(szPath, sizeof(szPath), "tstR0ThreadPreemption.r0");
+    if (RT_FAILURE(rc))
+    {
+        RTTestFailed(hTest, "Failed constructing .r0 filename (rc=%Rrc)", rc);
+        return RTTestSummaryAndDestroy(hTest);
+    }
+
+    void *pvImageBase;
+    rc = SUPR3LoadServiceModule(szPath, "tstR0ThreadPreemption",
+                                "TSTR0ThreadPreemptionSrvReqHandler",
+                                &pvImageBase);
+    if (RT_FAILURE(rc))
+    {
+        RTTestFailed(hTest, "SUPR3LoadServiceModule(%s,,,) failed with rc=%Rrc\n", szPath, rc);
+        return RTTestSummaryAndDestroy(hTest);
+    }
+
+    /* test request */
+    struct
+    {
+        SUPR0SERVICEREQHDR  Hdr;
+        char                szMsg[256];
+    } Req;
+
+    /*
+     * Sanity checks.
+     */
+    RTTestSub(hTest, "Sanity");
+    Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
+    Req.Hdr.cbReq = sizeof(Req);
+    Req.szMsg[0] = '\0';
+    RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstR0ThreadPreemption", sizeof("tstR0ThreadPreemption") - 1,
+                                             TSTR0THREADPREMEPTION_SANITY_OK, 0, &Req.Hdr), VINF_SUCCESS);
+    if (RT_FAILURE(rc))
+        return RTTestSummaryAndDestroy(hTest);
+    RTTESTI_CHECK_MSG(Req.szMsg[0] == '\0', ("%s", Req.szMsg));
+    if (Req.szMsg[0] != '\0')
+        return RTTestSummaryAndDestroy(hTest);
+
+    Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
+    Req.Hdr.cbReq = sizeof(Req);
+    Req.szMsg[0] = '\0';
+    RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstR0ThreadPreemption", sizeof("tstR0ThreadPreemption") - 1,
+                                             TSTR0THREADPREMEPTION_SANITY_FAILURE, 0, &Req.Hdr), VINF_SUCCESS);
+    if (RT_FAILURE(rc))
+        return RTTestSummaryAndDestroy(hTest);
+    RTTESTI_CHECK_MSG(!strncmp(Req.szMsg, "!42failure42", sizeof("!42failure42") - 1), ("%s", Req.szMsg));
+    if (strncmp(Req.szMsg, "!42failure42", sizeof("!42failure42") - 1))
+        return RTTestSummaryAndDestroy(hTest);
+
+    /*
+     * Basic tests, bail out on failure.
+     */
+    RTTestSub(hTest, "Basics");
+    Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
+    Req.Hdr.cbReq = sizeof(Req);
+    Req.szMsg[0] = '\0';
+    RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstR0ThreadPreemption", sizeof("tstR0ThreadPreemption") - 1,
+                                             TSTR0THREADPREMEPTION_BASIC, 0, &Req.Hdr), VINF_SUCCESS);
+    if (RT_FAILURE(rc))
+        return RTTestSummaryAndDestroy(hTest);
+    RTTESTI_CHECK_MSG(Req.szMsg[0] == '\0', ("%s", Req.szMsg));
+    if (Req.szMsg[0] == '!')
+        return RTTestSummaryAndDestroy(hTest);
+    if (Req.szMsg[0])
+        RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
+
+    /*
+     * Stay in ring-0 until preemption is pending.
+     */
+    RTTestSub(hTest, "Pending Preemption");
+    Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
+    Req.Hdr.cbReq = sizeof(Req);
+    Req.szMsg[0] = '\0';
+    RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstR0ThreadPreemption", sizeof("tstR0ThreadPreemption") - 1,
+                                             TSTR0THREADPREMEPTION_IS_PENDING, 0, &Req.Hdr), VINF_SUCCESS);
+    RTTESTI_CHECK_MSG(Req.szMsg[0] != '!', ("%s", Req.szMsg));
+    if (Req.szMsg[0])
+        RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
+
+    /*
+     * Done.
+     */
+    return RTTestSummaryAndDestroy(hTest);
+#endif
+}
