Index: trunk/src/VBox/Runtime/common/misc/assert.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/misc/assert.cpp	(revision 5417)
+++ trunk/src/VBox/Runtime/common/misc/assert.cpp	(revision 5417)
@@ -0,0 +1,200 @@
+/* $Id$ */
+/** @file
+ * innotek Portable Runtime - Assertion Workers.
+ */
+
+/*
+ * Copyright (C) 2006-2007 innotek GmbH
+ *
+ * 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 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.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <iprt/assert.h>
+#include <iprt/log.h>
+#include <iprt/string.h>
+#include <iprt/stdarg.h>
+#ifdef IN_RING3
+# include <stdio.h>
+#endif
+
+
+#ifdef IN_GUEST_R0
+#include <VBox/log.h>
+
+
+/**
+ * The 1st part of an assert message.
+ *
+ * @param   pszExpr     Expression. Can be NULL.
+ * @param   uLine       Location line number.
+ * @param   pszFile     Location file name.
+ * @param   pszFunction Location function name.
+ * @remark  This API exists in HC Ring-3 and GC.
+ */
+RTDECL(void)    AssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
+{
+    RTLogBackdoorPrintf("\n!!Assertion Failed!!\n"
+                        "Expression: %s\n"
+                        "Location  : %s(%d) %s\n",
+                        pszExpr, pszFile, uLine, pszFunction);
+}
+
+
+/**
+ * The 2nd (optional) part of an assert message.
+ *
+ * @param   pszFormat   Printf like format string.
+ * @param   ...         Arguments to that string.
+ * @remark  This API exists in HC Ring-3 and GC.
+ */
+RTDECL(void) AssertMsg2(const char *pszFormat, ...)
+{   /* forwarder. */
+    va_list args;
+    va_start(args, pszFormat);
+    RTLogBackdoorPrintfV(pszFormat, args);
+    va_end(args);
+}
+
+#if defined(RT_OS_LINUX) && defined(IN_MODULE)
+/*
+ * When we build this in the Linux kernel module, we wish to make the
+ * symbols available to other modules as well.
+ */
+# include "the-linux-kernel.h"
+EXPORT_SYMBOL(AssertMsg1);
+EXPORT_SYMBOL(AssertMsg2);
+#endif
+
+#elif defined(IN_RING0)
+
+/* OS specific.  */
+
+#else /* !IN_RING0 */
+
+
+/** The last assert message, 1st part. */
+RTDATADECL(char) g_szRTAssertMsg1[1024];
+/** The last assert message, 2nd part. */
+RTDATADECL(char) g_szRTAssertMsg2[2048];
+
+/**
+ * The 1st part of an assert message.
+ *
+ * @param   pszExpr     Expression. Can be NULL.
+ * @param   uLine       Location line number.
+ * @param   pszFile     Location file name.
+ * @param   pszFunction Location function name.
+ * @remark  This API exists in HC Ring-3 and GC.
+ */
+RTDECL(void)    AssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
+{
+#if !defined(IN_RING3) && !defined(LOG_NO_COM)
+    RTLogComPrintf("\n!!Assertion Failed!!\n"
+                   "Expression: %s\n"
+                   "Location  : %s(%d) %s\n",
+                   pszExpr, pszFile, uLine, pszFunction);
+#endif
+
+    PRTLOGGER pLog = RTLogRelDefaultInstance();
+    if (pLog)
+    {
+        RTLogRelPrintf("\n!!Assertion Failed!!\n"
+                       "Expression: %s\n"
+                       "Location  : %s(%d) %s\n",
+                       pszExpr, pszFile, uLine, pszFunction);
+        RTLogFlush(pLog);
+    }
+
+    pLog = RTLogDefaultInstance();
+    if (pLog)
+    {
+        RTLogPrintf("\n!!Assertion Failed!!\n"
+                    "Expression: %s\n"
+                    "Location  : %s(%d) %s\n",
+                    pszExpr, pszFile, uLine, pszFunction);
+        RTLogFlush(pLog);
+    }
+
+#ifdef IN_RING3
+    /* print to stderr, helps user and gdb debugging. */
+    fprintf(stderr,
+            "\n!!Assertion Failed!!\n"
+            "Expression: %s\n"
+            "Location  : %s(%d) %s\n",
+            VALID_PTR(pszExpr) ? pszExpr : "<none>",
+            VALID_PTR(pszFile) ? pszFile : "<none>",
+            uLine,
+            VALID_PTR(pszFunction) ? pszFunction : "");
+    fflush(stderr);
+#endif
+
+    RTStrPrintf(g_szRTAssertMsg1, sizeof(g_szRTAssertMsg1),
+                "\n!!Assertion Failed!!\n"
+                "Expression: %s\n"
+                "Location  : %s(%d) %s\n",
+                pszExpr, pszFile, uLine, pszFunction);
+}
+
+
+/**
+ * The 2nd (optional) part of an assert message.
+ *
+ * @param   pszFormat   Printf like format string.
+ * @param   ...         Arguments to that string.
+ * @remark  This API exists in HC Ring-3 and GC.
+ */
+RTDECL(void)    AssertMsg2(const char *pszFormat, ...)
+{
+    va_list args;
+
+#if !defined(IN_RING3) && !defined(LOG_NO_COM)
+    va_start(args, pszFormat);
+    RTLogComPrintfV(pszFormat, args);
+    va_end(args);
+#endif
+
+    PRTLOGGER pLog = RTLogRelDefaultInstance();
+    if (pLog)
+    {
+        va_start(args, pszFormat);
+        RTLogRelPrintfV(pszFormat, args);
+        va_end(args);
+        RTLogFlush(pLog);
+    }
+
+    pLog = RTLogDefaultInstance();
+    if (pLog)
+    {
+        va_start(args, pszFormat);
+        RTLogPrintfV(pszFormat, args);
+        va_end(args);
+        RTLogFlush(pLog);
+    }
+
+#ifdef IN_RING3
+    /* print to stderr, helps user and gdb debugging. */
+    char szMsg[1024];
+    va_start(args, pszFormat);
+    RTStrPrintfV(szMsg, sizeof(szMsg), pszFormat, args);
+    va_end(args);
+    fprintf(stderr, "%s", szMsg);
+    fflush(stderr);
+#endif
+
+    va_start(args, pszFormat);
+    RTStrPrintfV(g_szRTAssertMsg2, sizeof(g_szRTAssertMsg2), pszFormat, args);
+    va_end(args);
+}
+
+#endif /* !IN_RING0 */
+
Index: trunk/src/VBox/Runtime/common/misc/req.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/misc/req.cpp	(revision 5417)
+++ trunk/src/VBox/Runtime/common/misc/req.cpp	(revision 5417)
@@ -0,0 +1,879 @@
+/* $Id: VMReq.cpp 17451 2007-01-15 14:08:28Z bird $ */
+/** @file
+ * innotek Portable Runtime - Request packets
+ */
+
+/*
+ * Copyright (C) 2006-2007 innotek GmbH
+ *
+ * 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 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.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/string.h>
+#include <iprt/time.h>
+#include <iprt/semaphore.h>
+#include <iprt/thread.h>
+#include <iprt/req.h>
+#include <iprt/log.h>
+#include <iprt/mem.h>
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static int  rtReqProcessOne(PRTREQ pReq);
+
+
+
+/**
+ * Create a request packet queueu
+ *
+ * @returns iprt status code.
+ * @param   pReqQueue       The request queue.
+ */
+RTDECL(int) RTReqCreateQueue(PRTREQQUEUE *ppQueue)
+{
+    *ppQueue = (PRTREQQUEUE)RTMemAllocZ(sizeof(RTREQQUEUE));
+    if (!ppQueue)
+        return VERR_NO_MEMORY;
+
+    int rc = RTSemEventCreate(&(*ppQueue)->EventSem);
+    if (rc != VINF_SUCCESS)
+        RTMemFree(*ppQueue);
+
+    return rc;
+}
+
+
+/**
+ * Destroy a request packet queueu
+ *
+ * @returns iprt status code.
+ * @param   pReqQueue       The request queue.
+ */
+RTDECL(int) RTReqDestroyQueue(PRTREQQUEUE pQueue)
+{
+    /*
+     * Check input.
+     */
+    if (!pQueue)
+    {
+        AssertFailed();
+        return VERR_INVALID_PARAMETER;
+    }
+    RTSemEventDestroy(pQueue->EventSem);
+    RTMemFree(pQueue);
+    return VINF_SUCCESS;
+}
+
+/**
+ * Process one or more request packets
+ *
+ * @returns iprt status code.
+ * @returns VERR_TIMEOUT if cMillies was reached without the packet being added.
+ *
+ * @param   pReqQueue       The request queue.
+ * @param   cMillies        Number of milliseconds to wait for a pending request.
+ *                          Use RT_INDEFINITE_WAIT to only wait till one is added.
+ */
+RTDECL(int) RTReqProcess(PRTREQQUEUE pQueue, unsigned cMillies)
+{
+    LogFlow(("RTReqProcess %x\n", pQueue));
+    /*
+     * Check input.
+     */
+    if (!pQueue)
+    {
+        AssertFailed();
+        return VERR_INVALID_PARAMETER;
+    }
+
+    /*
+     * Process loop.
+     *
+     * We do not repeat the outer loop if we've got an informationtional status code
+     * since that code needs processing by our caller.
+     */
+    int rc = VINF_SUCCESS;
+    while (rc <= VINF_SUCCESS)
+    {
+        /*
+         * Get pending requests.
+         */
+        PRTREQ pReqs = (PRTREQ)ASMAtomicXchgPtr((void * volatile *)&pQueue->pReqs, NULL);
+        if (!pReqs)
+        {
+            /** @note We currently don't care if the entire time wasted here is larger than cMillies */
+            rc = RTSemEventWait(pQueue->EventSem, cMillies);
+            if (rc != VINF_SUCCESS)
+                break;
+            continue;
+        }
+
+        /*
+         * Reverse the list to process it in FIFO order.
+         */
+        PRTREQ pReq = pReqs;
+        if (pReq->pNext)
+            Log2(("RTReqProcess: 2+ requests: %p %p %p\n", pReq, pReq->pNext, pReq->pNext->pNext));
+        pReqs = NULL;
+        while (pReq)
+        {
+            Assert(pReq->enmState == RTREQSTATE_QUEUED);
+            Assert(pReq->pQueue == pQueue);
+            PRTREQ pCur = pReq;
+            pReq = pReq->pNext;
+            pCur->pNext = pReqs;
+            pReqs = pCur;
+        }
+
+
+        /*
+         * Process the requests.
+         */
+        while (pReqs)
+        {
+            /* Unchain the first request and advance the list. */
+            pReq = pReqs;
+            pReqs = pReqs->pNext;
+            pReq->pNext = NULL;
+
+            /* Process the request */
+            rc = rtReqProcessOne(pReq);
+            AssertRC(rc);
+            if (rc != VINF_SUCCESS)
+                break;
+        }
+    }
+
+    LogFlow(("RTReqProcess: returns %Vrc\n", rc));
+    return rc;
+}
+
+/**
+ * Allocate and queue a call request.
+ *
+ * If it's desired to poll on the completion of the request set cMillies
+ * to 0 and use RTReqWait() to check for completation. In the other case
+ * use RT_INDEFINITE_WAIT.
+ * The returned request packet must be freed using RTReqFree().
+ *
+ * @returns iprt statuscode.
+ *          Will not return VERR_INTERRUPTED.
+ * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
+ *
+ * @param   pReqQueue       The request queue.
+ * @param   ppReq           Where to store the pointer to the request.
+ *                          This will be NULL or a valid request pointer not matter what happens.
+ * @param   cMillies        Number of milliseconds to wait for the request to
+ *                          be completed. Use RT_INDEFINITE_WAIT to only
+ *                          wait till it's completed.
+ * @param   pfnFunction     Pointer to the function to call.
+ * @param   cArgs           Number of arguments following in the ellipsis.
+ *                          Not possible to pass 64-bit arguments!
+ * @param   ...             Function arguments.
+ */
+RTDECL(int) RTReqCall(PRTREQQUEUE pQueue, PRTREQ *ppReq, unsigned cMillies, PFNRT pfnFunction, unsigned cArgs, ...)
+{
+    va_list va;
+    va_start(va, cArgs);
+    int rc = RTReqCallV(pQueue, ppReq, cMillies, RTREQFLAGS_IPRT_STATUS, pfnFunction, cArgs, va);
+    va_end(va);
+    return rc;
+}
+
+
+/**
+ * Allocate and queue a call request to a void function.
+ *
+ * If it's desired to poll on the completion of the request set cMillies
+ * to 0 and use RTReqWait() to check for completation. In the other case
+ * use RT_INDEFINITE_WAIT.
+ * The returned request packet must be freed using RTReqFree().
+ *
+ * @returns iprt status code.
+ *          Will not return VERR_INTERRUPTED.
+ * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
+ *
+ * @param   pReqQueue       The request queue.
+ * @param   ppReq           Where to store the pointer to the request.
+ *                          This will be NULL or a valid request pointer not matter what happends.
+ * @param   cMillies        Number of milliseconds to wait for the request to
+ *                          be completed. Use RT_INDEFINITE_WAIT to only
+ *                          wait till it's completed.
+ * @param   pfnFunction     Pointer to the function to call.
+ * @param   cArgs           Number of arguments following in the ellipsis.
+ *                          Not possible to pass 64-bit arguments!
+ * @param   ...             Function arguments.
+ */
+RTDECL(int) RTReqCallVoid(PRTREQQUEUE pQueue, PRTREQ *ppReq, unsigned cMillies, PFNRT pfnFunction, unsigned cArgs, ...)
+{
+    va_list va;
+    va_start(va, cArgs);
+    int rc = RTReqCallV(pQueue, ppReq, cMillies, RTREQFLAGS_VOID, pfnFunction, cArgs, va);
+    va_end(va);
+    return rc;
+}
+
+
+/**
+ * Allocate and queue a call request to a void function.
+ *
+ * If it's desired to poll on the completion of the request set cMillies
+ * to 0 and use RTReqWait() to check for completation. In the other case
+ * use RT_INDEFINITE_WAIT.
+ * The returned request packet must be freed using RTReqFree().
+ *
+ * @returns iprt status code.
+ *          Will not return VERR_INTERRUPTED.
+ * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
+ *
+ * @param   pReqQueue       The request queue.
+ * @param   ppReq           Where to store the pointer to the request.
+ *                          This will be NULL or a valid request pointer not matter what happends, unless fFlags
+ *                          contains RTREQFLAGS_NO_WAIT when it will be optional and always NULL.
+ * @param   cMillies        Number of milliseconds to wait for the request to
+ *                          be completed. Use RT_INDEFINITE_WAIT to only
+ *                          wait till it's completed.
+ * @param   fFlags          A combination of the RTREQFLAGS values.
+ * @param   pfnFunction     Pointer to the function to call.
+ * @param   cArgs           Number of arguments following in the ellipsis.
+ *                          Not possible to pass 64-bit arguments!
+ * @param   ...             Function arguments.
+ */
+RTDECL(int) RTReqCallEx(PRTREQQUEUE pQueue, PRTREQ *ppReq, unsigned cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, ...)
+{
+    va_list va;
+    va_start(va, cArgs);
+    int rc = RTReqCallV(pQueue, ppReq, cMillies, fFlags, pfnFunction, cArgs, va);
+    va_end(va);
+    return rc;
+}
+
+
+/**
+ * Allocate and queue a call request.
+ *
+ * If it's desired to poll on the completion of the request set cMillies
+ * to 0 and use RTReqWait() to check for completation. In the other case
+ * use RT_INDEFINITE_WAIT.
+ * The returned request packet must be freed using RTReqFree().
+ *
+ * @returns iprt status code.
+ *          Will not return VERR_INTERRUPTED.
+ * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
+ *
+ * @param   pReqQueue       The request queue.
+ * @param   ppReq           Where to store the pointer to the request.
+ *                          This will be NULL or a valid request pointer not matter what happends, unless fFlags
+ *                          contains RTREQFLAGS_NO_WAIT when it will be optional and always NULL.
+ * @param   cMillies        Number of milliseconds to wait for the request to
+ *                          be completed. Use RT_INDEFINITE_WAIT to only
+ *                          wait till it's completed.
+ * @param   fFlags          A combination of the RTREQFLAGS values.
+ * @param   pfnFunction     Pointer to the function to call.
+ * @param   cArgs           Number of arguments following in the ellipsis.
+ *                          Not possible to pass 64-bit arguments!
+ * @param   pvArgs          Pointer to function arguments.
+ */
+RTDECL(int) RTReqCallV(PRTREQQUEUE pQueue, PRTREQ *ppReq, unsigned cMillies, unsigned fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args)
+{
+    LogFlow(("RTReqCallV: cMillies=%d fFlags=%#x pfnFunction=%p cArgs=%d\n", cMillies, fFlags, pfnFunction, cArgs));
+
+    /*
+     * Check input.
+     */
+    if (!pfnFunction || !pQueue || (fFlags & ~(RTREQFLAGS_RETURN_MASK | RTREQFLAGS_NO_WAIT)))
+    {
+        AssertFailed();
+        return VERR_INVALID_PARAMETER;
+    }
+    if (!(fFlags & RTREQFLAGS_NO_WAIT) || ppReq)
+    {
+        Assert(ppReq);
+        *ppReq = NULL;
+    }
+    PRTREQ pReq = NULL;
+    if (cArgs * sizeof(uintptr_t) > sizeof(pReq->u.Internal.aArgs))
+    {
+        AssertMsgFailed(("cArg=%d\n", cArgs));
+        return VERR_TOO_MUCH_DATA;
+    }
+
+    /*
+     * Allocate request
+     */
+    int rc = RTReqAlloc(pQueue, &pReq, RTREQTYPE_INTERNAL);
+    if (rc != VINF_SUCCESS)
+        return rc;
+
+    /*
+     * Initialize the request data.
+     */
+    pReq->fFlags         = fFlags;
+    pReq->u.Internal.pfn = pfnFunction;
+    pReq->u.Internal.cArgs = cArgs;
+    for (unsigned iArg = 0; iArg < cArgs; iArg++)
+        pReq->u.Internal.aArgs[iArg] = va_arg(Args, uintptr_t);
+
+    /*
+     * Queue the request and return.
+     */
+    rc = RTReqQueue(pReq, cMillies);
+    if (   rc != VINF_SUCCESS
+        && rc != VERR_TIMEOUT)
+    {
+        RTReqFree(pReq);
+        pReq = NULL;
+    }
+    if (!(fFlags & RTREQFLAGS_NO_WAIT))
+    {
+        *ppReq = pReq;
+        LogFlow(("RTReqCallV: returns %Vrc *ppReq=%p\n", rc, pReq));
+    }
+    else
+        LogFlow(("RTReqCallV: returns %Vrc\n", rc));
+    Assert(rc != VERR_INTERRUPTED);
+    return rc;
+}
+
+
+/**
+ * Joins the list pList with whatever is linked up at *pHead.
+ */
+static void vmr3ReqJoinFreeSub(volatile PRTREQ *ppHead, PRTREQ pList)
+{
+    for (unsigned cIterations = 0;; cIterations++)
+    {
+        PRTREQ pHead = (PRTREQ)ASMAtomicXchgPtr((void * volatile *)ppHead, pList);
+        if (!pHead)
+            return;
+        PRTREQ pTail = pHead;
+        while (pTail->pNext)
+            pTail = pTail->pNext;
+        pTail->pNext = pList;
+        if (ASMAtomicCmpXchgPtr((void * volatile *)ppHead, (void *)pHead, pList))
+            return;
+        pTail->pNext = NULL;
+        if (ASMAtomicCmpXchgPtr((void * volatile *)ppHead, (void *)pHead, NULL))
+            return;
+        pList = pHead;
+        Assert(cIterations != 32);
+        Assert(cIterations != 64);
+    }
+}
+
+
+/**
+ * Joins the list pList with whatever is linked up at *pHead.
+ */
+static void vmr3ReqJoinFree(PRTREQQUEUE pQueue, PRTREQ pList)
+{
+    /*
+     * Split the list if it's too long.
+     */
+    unsigned cReqs = 1;
+    PRTREQ pTail = pList;
+    while (pTail->pNext)
+    {
+        if (cReqs++ > 25)
+        {
+            const uint32_t i = pQueue->iReqFree;
+            vmr3ReqJoinFreeSub(&pQueue->apReqFree[(i + 2) % ELEMENTS(pQueue->apReqFree)], pTail->pNext);
+
+            pTail->pNext = NULL;
+            vmr3ReqJoinFreeSub(&pQueue->apReqFree[(i + 2 + (i == pQueue->iReqFree)) % ELEMENTS(pQueue->apReqFree)], pTail->pNext);
+            return;
+        }
+        pTail = pTail->pNext;
+    }
+    vmr3ReqJoinFreeSub(&pQueue->apReqFree[(pQueue->iReqFree + 2) % ELEMENTS(pQueue->apReqFree)], pList);
+}
+
+
+/**
+ * Allocates a request packet.
+ *
+ * The caller allocates a request packet, fills in the request data
+ * union and queues the request.
+ *
+ * @returns iprt status code.
+ *
+ * @param   pReqQueue       The request queue.
+ * @param   ppReq           Where to store the pointer to the allocated packet.
+ * @param   enmType         Package type.
+ */
+RTDECL(int) RTReqAlloc(PRTREQQUEUE pQueue, PRTREQ *ppReq, RTREQTYPE enmType)
+{
+    /*
+     * Validate input.
+     */
+    if (    enmType < RTREQTYPE_INVALID
+        ||  enmType > RTREQTYPE_MAX)
+    {
+        AssertMsgFailed(("Invalid package type %d valid range %d-%d inclusivly.\n",
+                         enmType, RTREQTYPE_INVALID + 1, RTREQTYPE_MAX - 1));
+        return VERR_RT_REQUEST_INVALID_TYPE;
+    }
+
+    /*
+     * Try get a recycled packet.
+     * While this could all be solved with a single list with a lock, it's a sport
+     * of mine to avoid locks.
+     */
+    int cTries = ELEMENTS(pQueue->apReqFree) * 2;
+    while (--cTries >= 0)
+    {
+        PRTREQ volatile *ppHead = &pQueue->apReqFree[ASMAtomicIncU32(&pQueue->iReqFree) % ELEMENTS(pQueue->apReqFree)];
+#if 0 /* sad, but this won't work safely because the reading of pReq->pNext. */
+        PRTREQ pNext = NULL;
+        PRTREQ pReq = *ppHead;
+        if (    pReq
+            &&  !ASMAtomicCmpXchgPtr((void * volatile *)ppHead, (pNext = pReq->pNext), pReq)
+            &&  (pReq = *ppHead)
+            &&  !ASMAtomicCmpXchgPtr((void * volatile *)ppHead, (pNext = pReq->pNext), pReq))
+            pReq = NULL;
+        if (pReq)
+        {
+            Assert(pReq->pNext == pNext); NOREF(pReq);
+#else
+        PRTREQ pReq = (PRTREQ)ASMAtomicXchgPtr((void * volatile *)ppHead, NULL);
+        if (pReq)
+        {
+            PRTREQ pNext = pReq->pNext;
+            if (    pNext
+                &&  !ASMAtomicCmpXchgPtr((void * volatile *)ppHead, pNext, NULL))
+            {
+                vmr3ReqJoinFree(pQueue, pReq->pNext);
+            }
+#endif
+            ASMAtomicDecU32(&pQueue->cReqFree);
+
+            /*
+             * Make sure the event sem is not signaled.
+             */
+            if (!pReq->fEventSemClear)
+            {
+                int rc = RTSemEventWait(pReq->EventSem, 0);
+                if (rc != VINF_SUCCESS && rc != VERR_TIMEOUT)
+                {
+                    /*
+                     * This shall not happen, but if it does we'll just destroy
+                     * the semaphore and create a new one.
+                     */
+                    AssertMsgFailed(("rc=%Vrc from RTSemEventWait(%#x).\n", rc, pReq->EventSem));
+                    RTSemEventDestroy(pReq->EventSem);
+                    rc = RTSemEventCreate(&pReq->EventSem);
+                    AssertRC(rc);
+                    if (rc != VINF_SUCCESS)
+                        return rc;
+                }
+                pReq->fEventSemClear = true;
+            }
+            else
+                Assert(RTSemEventWait(pReq->EventSem, 0) == VERR_TIMEOUT);
+
+            /*
+             * Initialize the packet and return it.
+             */
+            Assert(pReq->enmType == RTREQTYPE_INVALID);
+            Assert(pReq->enmState == RTREQSTATE_FREE);
+            Assert(pReq->pQueue == pQueue);
+            ASMAtomicXchgSize(&pReq->pNext, NULL);
+            pReq->enmState = RTREQSTATE_ALLOCATED;
+            pReq->iStatus  = VERR_RT_REQUEST_STATUS_STILL_PENDING;
+            pReq->fFlags   = RTREQFLAGS_IPRT_STATUS;
+            pReq->enmType  = enmType;
+
+            *ppReq = pReq;
+            LogFlow(("RTReqAlloc: returns VINF_SUCCESS *ppReq=%p recycled\n", pReq));
+            return VINF_SUCCESS;
+        }
+    }
+
+    /*
+     * Ok allocate one.
+     */
+    PRTREQ pReq = (PRTREQ)RTMemAllocZ(sizeof(*pReq));
+    if (!pReq)
+        return VERR_NO_MEMORY;
+
+    /*
+     * Create the semaphore.
+     */
+    int rc = RTSemEventCreate(&pReq->EventSem);
+    AssertRC(rc);
+    if (rc != VINF_SUCCESS)
+    {
+        RTMemFree(pReq);
+        return rc;
+    }
+
+    /*
+     * Initialize the packet and return it.
+     */
+    pReq->pNext    = NULL;
+    pReq->pQueue   = pQueue;
+    pReq->enmState = RTREQSTATE_ALLOCATED;
+    pReq->iStatus  = VERR_RT_REQUEST_STATUS_STILL_PENDING;
+    pReq->fEventSemClear = true;
+    pReq->fFlags   = RTREQFLAGS_IPRT_STATUS;
+    pReq->enmType  = enmType;
+
+    *ppReq = pReq;
+    LogFlow(("RTReqAlloc: returns VINF_SUCCESS *ppReq=%p new\n", pReq));
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Free a request packet.
+ *
+ * @returns iprt status code.
+ *
+ * @param   pReq            Package to free.
+ * @remark  The request packet must be in allocated or completed state!
+ */
+RTDECL(int) RTReqFree(PRTREQ pReq)
+{
+    /*
+     * Ignore NULL (all free functions should do this imho).
+     */
+    if (!pReq)
+        return VINF_SUCCESS;
+
+
+    /*
+     * Check packet state.
+     */
+    switch (pReq->enmState)
+    {
+        case RTREQSTATE_ALLOCATED:
+        case RTREQSTATE_COMPLETED:
+            break;
+        default:
+            AssertMsgFailed(("Invalid state %d!\n", pReq->enmState));
+            return VERR_RT_REQUEST_STATE;
+    }
+
+    /*
+     * Make it a free packet and put it into one of the free packet lists.
+     */
+    pReq->enmState = RTREQSTATE_FREE;
+    pReq->iStatus  = VERR_RT_REQUEST_STATUS_FREED;
+    pReq->enmType  = RTREQTYPE_INVALID;
+
+    PRTREQQUEUE pQueue = pReq->pQueue;
+    if (pQueue->cReqFree < 128)
+    {
+        ASMAtomicIncU32(&pQueue->cReqFree);
+        PRTREQ volatile *ppHead = &pQueue->apReqFree[ASMAtomicIncU32(&pQueue->iReqFree) % ELEMENTS(pQueue->apReqFree)];
+        PRTREQ pNext;
+        do
+        {
+            pNext = *ppHead;
+            ASMAtomicXchgPtr((void * volatile *)&pReq->pNext, pNext);
+        } while (!ASMAtomicCmpXchgPtr((void * volatile *)ppHead, (void *)pReq, (void *)pNext));
+    }
+    else
+    {
+        RTSemEventDestroy(pReq->EventSem);
+        RTMemFree(pReq);
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Queue a request.
+ *
+ * The quest must be allocated using RTReqAlloc() and contain
+ * all the required data.
+ * If it's disired to poll on the completion of the request set cMillies
+ * to 0 and use RTReqWait() to check for completation. In the other case
+ * use RT_INDEFINITE_WAIT.
+ *
+ * @returns iprt status code.
+ *          Will not return VERR_INTERRUPTED.
+ * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
+ *
+ * @param   pReq            The request to queue.
+ * @param   cMillies        Number of milliseconds to wait for the request to
+ *                          be completed. Use RT_INDEFINITE_WAIT to only
+ *                          wait till it's completed.
+ */
+RTDECL(int) RTReqQueue(PRTREQ pReq, unsigned cMillies)
+{
+    LogFlow(("RTReqQueue: pReq=%p cMillies=%d\n", pReq, cMillies));
+    /*
+     * Verify the supplied package.
+     */
+    if (pReq->enmState != RTREQSTATE_ALLOCATED)
+    {
+        AssertMsgFailed(("Invalid state %d\n", pReq->enmState));
+        return VERR_RT_REQUEST_STATE;
+    }
+    if (   !pReq->pQueue
+        ||  pReq->pNext
+        ||  !pReq->EventSem)
+    {
+        AssertMsgFailed(("Invalid request package! Anyone cooking their own packages???\n"));
+        return VERR_RT_REQUEST_INVALID_PACKAGE;
+    }
+    if (    pReq->enmType < RTREQTYPE_INVALID
+        || pReq->enmType > RTREQTYPE_MAX)
+    {
+        AssertMsgFailed(("Invalid package type %d valid range %d-%d inclusivly. This was verified on alloc too...\n",
+                         pReq->enmType, RTREQTYPE_INVALID + 1, RTREQTYPE_MAX - 1));
+        return VERR_RT_REQUEST_INVALID_TYPE;
+    }
+
+    int rc = VINF_SUCCESS;
+    /*
+     * Insert it.
+     */
+    pReq->enmState = RTREQSTATE_QUEUED;
+    PRTREQ pNext;
+    do
+    {
+        pNext = pReq->pQueue->pReqs;
+        pReq->pNext = pNext;
+    } while (!ASMAtomicCmpXchgPtr((void * volatile *)&pReq->pQueue->pReqs, (void *)pReq, (void *)pNext));
+
+    /*
+     * Notify queue thread.
+     */
+    RTSemEventSignal(pReq->pQueue->EventSem);
+
+    /*
+     * Wait and return.
+     */
+    if (!(pReq->fFlags & RTREQFLAGS_NO_WAIT))
+        rc = RTReqWait(pReq, cMillies);
+    LogFlow(("RTReqQueue: returns %Vrc\n", rc));
+    return rc;
+}
+
+
+/**
+ * Wait for a request to be completed.
+ *
+ * @returns iprt status code.
+ *          Will not return VERR_INTERRUPTED.
+ * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed.
+ *
+ * @param   pReq            The request to wait for.
+ * @param   cMillies        Number of milliseconds to wait.
+ *                          Use RT_INDEFINITE_WAIT to only wait till it's completed.
+ */
+RTDECL(int) RTReqWait(PRTREQ pReq, unsigned cMillies)
+{
+    LogFlow(("RTReqWait: pReq=%p cMillies=%d\n", pReq, cMillies));
+
+    /*
+     * Verify the supplied package.
+     */
+    if (    pReq->enmState != RTREQSTATE_QUEUED
+        &&  pReq->enmState != RTREQSTATE_PROCESSING
+        &&  pReq->enmState != RTREQSTATE_COMPLETED)
+    {
+        AssertMsgFailed(("Invalid state %d\n", pReq->enmState));
+        return VERR_RT_REQUEST_STATE;
+    }
+    if (    !pReq->pQueue
+        ||  !pReq->EventSem)
+    {
+        AssertMsgFailed(("Invalid request package! Anyone cooking their own packages???\n"));
+        return VERR_RT_REQUEST_INVALID_PACKAGE;
+    }
+    if (    pReq->enmType < RTREQTYPE_INVALID
+        ||  pReq->enmType > RTREQTYPE_MAX)
+    {
+        AssertMsgFailed(("Invalid package type %d valid range %d-%d inclusivly. This was verified on alloc and queue too...\n",
+                         pReq->enmType, RTREQTYPE_INVALID + 1, RTREQTYPE_MAX - 1));
+        return VERR_RT_REQUEST_INVALID_TYPE;
+    }
+
+    /*
+     * Wait on the package.
+     */
+    int rc;
+    if (cMillies != RT_INDEFINITE_WAIT)
+        rc = RTSemEventWait(pReq->EventSem, cMillies);
+    else
+    {
+        do
+        {
+            rc = RTSemEventWait(pReq->EventSem, RT_INDEFINITE_WAIT);
+            Assert(rc != VERR_TIMEOUT);
+        } while (pReq->enmState != RTREQSTATE_COMPLETED);
+    }
+    if (rc == VINF_SUCCESS)
+        ASMAtomicXchgSize(&pReq->fEventSemClear, true);
+    if (pReq->enmState == RTREQSTATE_COMPLETED)
+        rc = VINF_SUCCESS;
+    LogFlow(("RTReqWait: returns %Vrc\n", rc));
+    Assert(rc != VERR_INTERRUPTED);
+    return rc;
+}
+
+
+/**
+ * Process one request.
+ *
+ * @returns IPRT status code.
+ *
+ * @param   pReq        Request packet to process.
+ */
+static int  rtReqProcessOne(PRTREQ pReq)
+{
+    LogFlow(("rtReqProcessOne: pReq=%p type=%d fFlags=%#x\n", pReq, pReq->enmType, pReq->fFlags));
+
+    /*
+     * Process the request.
+     */
+    Assert(pReq->enmState == RTREQSTATE_QUEUED);
+    pReq->enmState = RTREQSTATE_PROCESSING;
+    int     rcRet = VINF_SUCCESS;           /* the return code of this function. */
+    int     rcReq = VERR_NOT_IMPLEMENTED;   /* the request status. */
+    switch (pReq->enmType)
+    {
+        /*
+         * A packed down call frame.
+         */
+        case RTREQTYPE_INTERNAL:
+        {
+            uintptr_t *pauArgs = &pReq->u.Internal.aArgs[0];
+            union
+            {
+                PFNRT pfn;
+                DECLCALLBACKMEMBER(int, pfn00)(void);
+                DECLCALLBACKMEMBER(int, pfn01)(uintptr_t);
+                DECLCALLBACKMEMBER(int, pfn02)(uintptr_t, uintptr_t);
+                DECLCALLBACKMEMBER(int, pfn03)(uintptr_t, uintptr_t, uintptr_t);
+                DECLCALLBACKMEMBER(int, pfn04)(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+                DECLCALLBACKMEMBER(int, pfn05)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+                DECLCALLBACKMEMBER(int, pfn06)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+                DECLCALLBACKMEMBER(int, pfn07)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+                DECLCALLBACKMEMBER(int, pfn08)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+                DECLCALLBACKMEMBER(int, pfn09)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+                DECLCALLBACKMEMBER(int, pfn10)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+                DECLCALLBACKMEMBER(int, pfn11)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+                DECLCALLBACKMEMBER(int, pfn12)(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+            } u;
+            u.pfn = pReq->u.Internal.pfn;
+#ifdef RT_ARCH_AMD64
+            switch (pReq->u.Internal.cArgs)
+            {
+                case 0:  rcRet = u.pfn00(); break;
+                case 1:  rcRet = u.pfn01(pauArgs[0]); break;
+                case 2:  rcRet = u.pfn02(pauArgs[0], pauArgs[1]); break;
+                case 3:  rcRet = u.pfn03(pauArgs[0], pauArgs[1], pauArgs[2]); break;
+                case 4:  rcRet = u.pfn04(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3]); break;
+                case 5:  rcRet = u.pfn05(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4]); break;
+                case 6:  rcRet = u.pfn06(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5]); break;
+                case 7:  rcRet = u.pfn07(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6]); break;
+                case 8:  rcRet = u.pfn08(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7]); break;
+                case 9:  rcRet = u.pfn09(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8]); break;
+                case 10: rcRet = u.pfn10(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8], pauArgs[9]); break;
+                case 11: rcRet = u.pfn11(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8], pauArgs[9], pauArgs[10]); break;
+                case 12: rcRet = u.pfn12(pauArgs[0], pauArgs[1], pauArgs[2], pauArgs[3], pauArgs[4], pauArgs[5], pauArgs[6], pauArgs[7], pauArgs[8], pauArgs[9], pauArgs[10], pauArgs[11]); break;
+                default:
+                    AssertReleaseMsgFailed(("cArgs=%d\n", pReq->u.Internal.cArgs));
+                    rcRet = rcReq = VERR_INTERNAL_ERROR;
+                    break;
+            }
+#else /* x86: */
+            size_t cbArgs = pReq->u.Internal.cArgs * sizeof(uintptr_t);
+# ifdef __GNUC__
+            __asm__ __volatile__("movl  %%esp, %%edx\n\t"
+                                 "subl  %2, %%esp\n\t"
+                                 "andl  $0xfffffff0, %%esp\n\t"
+                                 "shrl  $2, %2\n\t"
+                                 "movl  %%esp, %%edi\n\t"
+                                 "rep movsl\n\t"
+                                 "movl  %%edx, %%edi\n\t"
+                                 "call  *%%eax\n\t"
+                                 "mov   %%edi, %%esp\n\t"
+                                 : "=a" (rcRet),
+                                   "=S" (pauArgs),
+                                   "=c" (cbArgs)
+                                 : "0" (u.pfn),
+                                   "1" (pauArgs),
+                                   "2" (cbArgs)
+                                 : "edi", "edx");
+# else
+            __asm
+            {
+                xor     edx, edx        /* just mess it up. */
+                mov     eax, u.pfn
+                mov     ecx, cbArgs
+                shr     ecx, 2
+                mov     esi, pauArgs
+                mov     ebx, esp
+                sub     esp, cbArgs
+                and     esp, 0xfffffff0
+                mov     edi, esp
+                rep movsd
+                call    eax
+                mov     esp, ebx
+                mov     rcRet, eax
+            }
+# endif
+#endif /* x86 */
+            if ((pReq->fFlags & (RTREQFLAGS_RETURN_MASK)) == RTREQFLAGS_VOID)
+                rcRet = VINF_SUCCESS;
+            rcReq = rcRet;
+            break;
+        }
+
+        default:
+            AssertMsgFailed(("pReq->enmType=%d\n", pReq->enmType));
+            rcReq = VERR_NOT_IMPLEMENTED;
+            break;
+    }
+
+    /*
+     * Complete the request.
+     */
+    pReq->iStatus  = rcReq;
+    pReq->enmState = RTREQSTATE_COMPLETED;
+    if (pReq->fFlags & RTREQFLAGS_NO_WAIT)
+    {
+        /* Free the packet, nobody is waiting. */
+        LogFlow(("rtReqProcessOne: Completed request %p: rcReq=%Vrc rcRet=%Vrc - freeing it\n",
+                 pReq, rcReq, rcRet));
+        RTReqFree(pReq);
+    }
+    else
+    {
+        /* Notify the waiter and him free up the packet. */
+        LogFlow(("rtReqProcessOne: Completed request %p: rcReq=%Vrc rcRet=%Vrc - notifying waiting thread\n",
+                 pReq, rcReq, rcRet));
+        ASMAtomicXchgSize(&pReq->fEventSemClear, false);
+        int rc2 = RTSemEventSignal(pReq->EventSem);
+        if (rc2 != VINF_SUCCESS)
+        {
+            AssertRC(rc2);
+            rcRet = rc2;
+        }
+    }
+    return rcRet;
+}
+
+
+
+
Index: trunk/src/VBox/Runtime/common/misc/semspingpong.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/misc/semspingpong.cpp	(revision 5417)
+++ trunk/src/VBox/Runtime/common/misc/semspingpong.cpp	(revision 5417)
@@ -0,0 +1,260 @@
+/* $Id$ */
+/** @file
+ * innotek Portable Runtime - Thread Ping-Pong Construct.
+ */
+
+/*
+ * Copyright (C) 2006-2007 innotek GmbH
+ *
+ * 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 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.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <iprt/semaphore.h>
+#include <iprt/thread.h>
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+
+
+
+/**
+ * Validates a pPP handle passed to one of the PP functions.
+ *
+ * @returns true if valid, false if invalid.
+ * @param   pPP     Pointe to the ping-pong structure.
+ */
+inline bool rtsemPPValid(PRTPINGPONG  pPP)
+{
+    if (!VALID_PTR(pPP))
+        return false;
+
+    RTPINGPONGSPEAKER enmSpeaker = pPP->enmSpeaker;
+    if (    enmSpeaker != RTPINGPONGSPEAKER_PING
+        &&  enmSpeaker != RTPINGPONGSPEAKER_PONG
+        &&  enmSpeaker != RTPINGPONGSPEAKER_PONG_SIGNALED
+        &&  enmSpeaker != RTPINGPONGSPEAKER_PING_SIGNALED)
+        return false;
+
+    return true;
+}
+
+/**
+ * Init a Ping-Pong construct.
+ *
+ * @returns iprt status code.
+ * @param   pPP         Pointer to the ping-pong structure which needs initialization.
+ */
+RTR3DECL(int) RTSemPingPongInit(PRTPINGPONG pPP)
+{
+    /*
+     * Init the structure.
+     */
+    pPP->enmSpeaker = RTPINGPONGSPEAKER_PING;
+
+    int rc = RTSemEventCreate(&pPP->Ping);
+    if (RT_SUCCESS(rc))
+    {
+        rc = RTSemEventCreate(&pPP->Pong);
+        if (RT_SUCCESS(rc))
+            return VINF_SUCCESS;
+        RTSemEventDestroy(pPP->Ping);
+    }
+
+    return rc;
+}
+
+
+/**
+ * Destroys a Ping-Pong construct.
+ *
+ * @returns iprt status code.
+ * @param   pPP         Pointer to the ping-pong structure which is to be destroyed.
+ *                      (I.e. put into uninitialized state.)
+ */
+RTR3DECL(int) RTSemPingPongDestroy(PRTPINGPONG pPP)
+{
+    /*
+     * Validate input
+     */
+    if (!rtsemPPValid(pPP))
+    {
+        AssertMsgFailed(("Invalid input %p\n", pPP));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    /*
+     * Invalidate the ping pong handle and destroy the event semaphores.
+     */
+    ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_UNINITIALIZE);
+    int rc = RTSemEventDestroy(pPP->Ping);
+    int rc2 = RTSemEventDestroy(pPP->Pong);
+    AssertRC(rc);
+    AssertRC(rc2);
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Signals the pong thread in a ping-pong construct. (I.e. sends ping.)
+ * This is called by the ping thread.
+ *
+ * @returns iprt status code.
+ * @param   pPP         Pointer to the ping-pong structure to ping.
+ */
+RTR3DECL(int) RTSemPing(PRTPINGPONG pPP)
+{
+    /*
+     * Validate input
+     */
+    if (!rtsemPPValid(pPP))
+    {
+        AssertMsgFailed(("Invalid input %p\n", pPP));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    if (pPP->enmSpeaker != RTPINGPONGSPEAKER_PING)
+    {
+        AssertMsgFailed(("Speaking out of turn!\n"));
+        return VERR_SEM_OUT_OF_TURN;
+    }
+
+    /*
+     * Signal the other thread.
+     */
+    ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PONG_SIGNALED);
+    int rc = RTSemEventSignal(pPP->Pong);
+    if (RT_SUCCESS(rc))
+        return rc;
+
+    /* restore the state. */
+    AssertMsgFailed(("Failed to signal pong sem %x. rc=%d\n",  pPP->Pong,  rc));
+    ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PING);
+    return rc;
+}
+
+
+/**
+ * Signals the ping thread in a ping-pong construct. (I.e. sends pong.)
+ * This is called by the pong thread.
+ *
+ * @returns iprt status code.
+ * @param   pPP         Pointer to the ping-pong structure to pong.
+ */
+RTR3DECL(int) RTSemPong(PRTPINGPONG pPP)
+{
+    /*
+     * Validate input
+     */
+    if (!rtsemPPValid(pPP))
+    {
+        AssertMsgFailed(("Invalid input %p\n", pPP));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    if (pPP->enmSpeaker != RTPINGPONGSPEAKER_PONG)
+    {
+        AssertMsgFailed(("Speaking out of turn!\n"));
+        return VERR_SEM_OUT_OF_TURN;
+    }
+
+    /*
+     * Signal the other thread.
+     */
+    ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PING_SIGNALED);
+    int rc = RTSemEventSignal(pPP->Ping);
+    if (RT_SUCCESS(rc))
+        return rc;
+
+    /* restore the state. */
+    AssertMsgFailed(("Failed to signal ping sem %x. rc=%d\n",  pPP->Ping,  rc));
+    ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PONG);
+    return rc;
+}
+
+
+/**
+ * Wait function for the ping thread.
+ *
+ * @returns iprt status code.
+ *          Will not return VERR_INTERRUPTED.
+ * @param   pPP         Pointer to the ping-pong structure to wait on.
+ * @param   cMillies    Number of milliseconds to wait.
+ */
+RTR3DECL(int) RTSemPingWait(PRTPINGPONG pPP, unsigned cMillies)
+{
+    /*
+     * Validate input
+     */
+    if (!rtsemPPValid(pPP))
+    {
+        AssertMsgFailed(("Invalid input %p\n", pPP));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    if (    pPP->enmSpeaker != RTPINGPONGSPEAKER_PONG
+        &&  pPP->enmSpeaker != RTPINGPONGSPEAKER_PONG_SIGNALED
+        &&  pPP->enmSpeaker != RTPINGPONGSPEAKER_PING_SIGNALED)
+    {
+        AssertMsgFailed(("Listening out of turn! enmSpeaker=%d\n", pPP->enmSpeaker));
+        return VERR_SEM_OUT_OF_TURN;
+    }
+
+    /*
+     * Wait.
+     */
+    int rc = RTSemEventWait(pPP->Ping, cMillies);
+    if (RT_SUCCESS(rc))
+        ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PING);
+    Assert(rc != VERR_INTERRUPTED);
+    return rc;
+}
+
+
+/**
+ * Wait function for the pong thread.
+ *
+ * @returns iprt status code.
+ *          Will not return VERR_INTERRUPTED.
+ * @param   pPP         Pointer to the ping-pong structure to wait on.
+ * @param   cMillies    Number of milliseconds to wait.
+ */
+RTR3DECL(int) RTSemPongWait(PRTPINGPONG pPP, unsigned cMillies)
+{
+    /*
+     * Validate input
+     */
+    if (!rtsemPPValid(pPP))
+    {
+        AssertMsgFailed(("Invalid input %p\n", pPP));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    if (    pPP->enmSpeaker != RTPINGPONGSPEAKER_PING
+        &&  pPP->enmSpeaker != RTPINGPONGSPEAKER_PING_SIGNALED
+        &&  pPP->enmSpeaker != RTPINGPONGSPEAKER_PONG_SIGNALED)
+    {
+        AssertMsgFailed(("Listening out of turn! enmSpeaker=%d\n", pPP->enmSpeaker));
+        return VERR_SEM_OUT_OF_TURN;
+    }
+
+    /*
+     * Wait.
+     */
+    int rc = RTSemEventWait(pPP->Pong, cMillies);
+    if (RT_SUCCESS(rc))
+        ASMAtomicXchgSize(&pPP->enmSpeaker, RTPINGPONGSPEAKER_PONG);
+    Assert(rc != VERR_INTERRUPTED);
+    return rc;
+}
+
Index: trunk/src/VBox/Runtime/common/misc/thread.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/misc/thread.cpp	(revision 5417)
+++ trunk/src/VBox/Runtime/common/misc/thread.cpp	(revision 5417)
@@ -0,0 +1,1298 @@
+/* $Id$ */
+/** @file
+ * innotek Portable Runtime - Threads, common routines.
+ */
+
+/*
+ * Copyright (C) 2006-2007 innotek GmbH
+ *
+ * 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 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.
+ */
+
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#define LOG_GROUP RTLOGGROUP_THREAD
+#include <iprt/thread.h>
+#include <iprt/log.h>
+#include <iprt/avl.h>
+#include <iprt/alloc.h>
+#include <iprt/assert.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/thread.h"
+#include "internal/sched.h"
+#include "internal/process.h"
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+#ifdef IN_RING0
+# define RT_THREAD_LOCK_TMP(Tmp)    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER
+# define RT_THREAD_LOCK_RW(Tmp)     RTSpinlockAcquireNoInts(g_ThreadSpinlock, &(Tmp))
+# define RT_THREAD_UNLOCK_RW(Tmp)   RTSpinlockReleaseNoInts(g_ThreadSpinlock, &(Tmp))
+# define RT_THREAD_LOCK_RD(Tmp)     RTSpinlockAcquireNoInts(g_ThreadSpinlock, &(Tmp))
+# define RT_THREAD_UNLOCK_RD(Tmp)   RTSpinlockReleaseNoInts(g_ThreadSpinlock, &(Tmp))
+#else
+# define RT_THREAD_LOCK_TMP(Tmp)
+# define RT_THREAD_LOCK_RW(Tmp)     rtThreadLockRW()
+# define RT_THREAD_UNLOCK_RW(Tmp)   rtThreadUnLockRW()
+# define RT_THREAD_LOCK_RD(Tmp)     rtThreadLockRD()
+# define RT_THREAD_UNLOCK_RD(Tmp)   rtThreadUnLockRD()
+#endif
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** The AVL thread containing the threads. */
+static PAVLPVNODECORE   g_ThreadTree;
+#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
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static void rtThreadDestroy(PRTTHREADINT pThread);
+static int rtThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, const char *pszName);
+static void rtThreadRemoveLocked(PRTTHREADINT pThread);
+static PRTTHREADINT rtThreadAlloc(RTTHREADTYPE enmType, unsigned fFlags, unsigned 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 RTCreateThread
+ * 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.
+ */
+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.
+         */
+        int rc = RTSemRWCreate(&g_ThreadRWSem);
+        if (RT_SUCCESS(rc))
+        {
+            rc = rtThreadNativeInit();
+#ifdef IN_RING3
+            if (RT_SUCCESS(rc))
+                rc = rtThreadAdopt(RTTHREADTYPE_DEFAULT, 0, "main");
+            if (RT_SUCCESS(rc))
+                rc = rtSchedNativeCalcDefaultPriority(RTTHREADTYPE_DEFAULT);
+#endif
+            if (RT_SUCCESS(rc))
+                return VINF_SUCCESS;
+
+            /* failed, clear out */
+            RTSemRWDestroy(g_ThreadRWSem);
+            g_ThreadRWSem = NIL_RTSEMRW;
+        }
+    }
+
+#elif defined(IN_RING0)
+
+    /*
+     * Create the spinlock and to native init.
+     */
+    Assert(g_ThreadSpinlock == NIL_RTSPINLOCK);
+    int rc = RTSpinlockCreate(&g_ThreadSpinlock);
+    if (RT_SUCCESS(rc))
+    {
+        rc = rtThreadNativeInit();
+        if (RT_SUCCESS(rc))
+            return VINF_SUCCESS;
+
+        /* failed, clear out */
+        RTSpinlockDestroy(g_ThreadSpinlock);
+        g_ThreadSpinlock = NIL_RTSPINLOCK;
+    }
+#else
+# error "!IN_RING0 && !IN_RING3"
+#endif
+    return rc;
+}
+
+
+/**
+ * Terminates the thread database.
+ */
+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)
+        AssertMsg2("WARNING: g_ThreadTree=%p\n", g_ThreadTree);
+#endif
+}
+
+
+
+#ifdef IN_RING3
+
+inline void rtThreadLockRW(void)
+{
+    if (g_ThreadRWSem == NIL_RTSEMRW)
+        rtThreadInit();
+    int rc = RTSemRWRequestWrite(g_ThreadRWSem, RT_INDEFINITE_WAIT);
+    AssertReleaseRC(rc);
+}
+
+
+inline void rtThreadLockRD(void)
+{
+    if (g_ThreadRWSem == NIL_RTSEMRW)
+        rtThreadInit();
+    int rc = RTSemRWRequestRead(g_ThreadRWSem, RT_INDEFINITE_WAIT);
+    AssertReleaseRC(rc);
+}
+
+
+inline void rtThreadUnLockRW(void)
+{
+    int rc = RTSemRWReleaseWrite(g_ThreadRWSem);
+    AssertReleaseRC(rc);
+}
+
+
+inline void rtThreadUnLockRD(void)
+{
+    int rc = RTSemRWReleaseRead(g_ThreadRWSem);
+    AssertReleaseRC(rc);
+}
+
+#endif /* IN_RING3 */
+
+
+/**
+ * Adopts the calling thread.
+ * No locks are taken or released by this function.
+ */
+static int rtThreadAdopt(RTTHREADTYPE enmType, unsigned fFlags, const char *pszName)
+{
+    Assert(!(fFlags & RTTHREADFLAGS_WAITABLE));
+    fFlags &= ~RTTHREADFLAGS_WAITABLE;
+
+    /*
+     * Allocate and insert the thread.
+     */
+    int rc = VERR_NO_MEMORY;
+    PRTTHREADINT pThread = rtThreadAlloc(enmType, fFlags, RTTHREADINT_FLAGS_ALIEN, pszName);
+    if (pThread)
+    {
+        RTNATIVETHREAD NativeThread = RTThreadNativeSelf();
+        rc = rtThreadNativeAdopt(pThread);
+        if (RT_SUCCESS(rc))
+        {
+            rtThreadInsert(pThread, NativeThread);
+            pThread->enmState = RTTHREADSTATE_RUNNING;
+        }
+    }
+    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)
+{
+    AssertReturn(!(fFlags & RTTHREADFLAGS_WAITABLE), VERR_INVALID_PARAMETER);
+    AssertReturn(!pszName || VALID_PTR(pszName), VERR_INVALID_POINTER);
+    AssertReturn(!pThread || VALID_PTR(pThread), VERR_INVALID_POINTER);
+
+    int      rc = VINF_SUCCESS;
+    RTTHREAD 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, 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;
+}
+
+
+/**
+ * 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, unsigned fIntFlags, const char *pszName)
+{
+    PRTTHREADINT pThread = (PRTTHREADINT)RTMemAllocZ(sizeof(RTTHREADINT));
+    if (pThread)
+    {
+        pThread->Core.Key   = (void*)NIL_RTTHREAD;
+        pThread->u32Magic   = RTTHREADINT_MAGIC;
+        size_t 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;
+        int 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.
+ */
+void rtThreadInsert(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread)
+{
+    Assert(pThread);
+    Assert(pThread->u32Magic == RTTHREADINT_MAGIC);
+
+    RT_THREAD_LOCK_TMP(Tmp);
+    RT_THREAD_LOCK_RW(Tmp);
+
+    /*
+     * 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)
+    {
+        /* remove dead alien if any */
+        if (pThreadOther)
+        {
+            Assert(pThreadOther->fIntFlags & RTTHREADINT_FLAGS_ALIEN);
+            ASMAtomicBitClear(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT);
+            rtThreadRemoveLocked(pThreadOther);
+            if (pThreadOther->fIntFlags & RTTHREADINT_FLAGS_ALIEN)
+                rtThreadRelease(pThreadOther);
+        }
+
+        /* insert the thread */
+        pThread->Core.Key = (void *)NativeThread;
+        bool fRc = RTAvlPVInsert(&g_ThreadTree, &pThread->Core);
+        ASMAtomicOrU32(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE);
+
+        AssertReleaseMsg(fRc, ("Lock problem? %p (%RTnthrd) %s\n", pThread, NativeThread, pThread->szName));
+        NOREF(fRc);
+    }
+
+    RT_THREAD_UNLOCK_RW(Tmp);
+}
+
+
+/**
+ * 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);
+    AssertMsg(pThread2 == pThread, ("%p(%s) != %p (%p/%s)\n", pThread2, pThread2  ? pThread2->szName : "<null>",
+                                    pThread, pThread->Core.Key, pThread->szName));
+    NOREF(pThread2);
+}
+
+
+/**
+ * Removes the thread from the AVL tree.
+ *
+ * @param   pThread     The thread to remove.
+ */
+static void rtThreadRemove(PRTTHREADINT pThread)
+{
+    RT_THREAD_LOCK_TMP(Tmp);
+    RT_THREAD_LOCK_RW(Tmp);
+    if (ASMAtomicBitTestAndClear(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT))
+        rtThreadRemoveLocked(pThread);
+    RT_THREAD_UNLOCK_RW(Tmp);
+}
+
+
+/**
+ * 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.
+ */
+PRTTHREADINT rtThreadGetByNative(RTNATIVETHREAD NativeThread)
+{
+    /*
+     * Simple tree lookup.
+     */
+    RT_THREAD_LOCK_TMP(Tmp);
+    RT_THREAD_LOCK_RD(Tmp);
+    PRTTHREADINT pThread = (PRTTHREADINT)RTAvlPVGet(&g_ThreadTree, (void *)NativeThread);
+    RT_THREAD_UNLOCK_RD(Tmp);
+    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.
+ */
+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.
+ */
+uint32_t rtThreadRelease(PRTTHREADINT pThread)
+{
+    Assert(pThread);
+    uint32_t cRefs;
+    if (pThread->cRefs >= 1)
+    {
+        cRefs = ASMAtomicDecU32(&pThread->cRefs);
+        if (!cRefs)
+            rtThreadDestroy(pThread);
+    }
+    else
+        cRefs = 0;
+    return cRefs;
+}
+
+
+/**
+ * Destroys the per thread data.
+ *
+ * @param   pThread     The thread to destroy.
+ */
+static void rtThreadDestroy(PRTTHREADINT pThread)
+{
+    /*
+     * Mark it dead and remove it from the tree.
+     */
+    ASMAtomicXchgU32(&pThread->u32Magic, RTTHREADINT_MAGIC_DEAD);
+    rtThreadRemove(pThread);
+
+    /*
+     * Free resources.
+     */
+    pThread->Core.Key   = (void *)NIL_RTTHREAD;
+    pThread->enmType    = RTTHREADTYPE_INVALID;
+    RTSemEventMultiDestroy(pThread->EventUser);
+    pThread->EventUser  = NIL_RTSEMEVENTMULTI;
+    if (pThread->EventTerminated != NIL_RTSEMEVENTMULTI)
+    {
+        RTSemEventMultiDestroy(pThread->EventTerminated);
+        pThread->EventTerminated = NIL_RTSEMEVENTMULTI;
+    }
+    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.
+ */
+void rtThreadTerminate(PRTTHREADINT pThread, int rc)
+{
+    Assert(pThread->cRefs >= 1);
+
+    /*
+     * Set the rc, mark it terminated and signal anyone waiting.
+     */
+    pThread->rc = rc;
+    ASMAtomicXchgSize(&pThread->enmState, 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).
+ */
+int rtThreadMain(PRTTHREADINT pThread, RTNATIVETHREAD NativeThread, const char *pszThreadName)
+{
+    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.
+     */
+    int 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=%Vrc\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=%Vrc\n",
+                     pThread, NativeThread, pThread->szName, pThread->enmType, rc));
+#endif
+
+    /*
+     * Call thread function and terminate when it returns.
+     */
+    pThread->enmState = RTTHREADSTATE_RUNNING;
+    rc = pThread->pfnThread(pThread, pThread->pvUser);
+
+    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)
+{
+    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.
+     */
+    int             rc;
+    PRTTHREADINT    pThreadInt = rtThreadAlloc(enmType, fFlags, 0, pszName);
+    if (pThreadInt)
+    {
+        pThreadInt->pfnThread = pfnThread;
+        pThreadInt->pvUser    = pvUser;
+        pThreadInt->cbStack   = cbStack;
+
+        RTNATIVETHREAD NativeThread;
+        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=%Vrc\n", rc));
+    AssertReleaseRC(rc);
+    return rc;
+}
+
+
+/**
+ * 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)
+        return (RTNATIVETHREAD)pThread->Core.Key;
+    return NIL_RTNATIVETHREAD;
+}
+
+
+/**
+ * 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)
+    {
+        rtThreadRelease(pThread);
+        return pThread;
+    }
+    return NIL_RTTHREAD;
+}
+
+
+/**
+ * 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)
+            return pThread->szName;
+    }
+    return NULL;
+}
+
+
+/**
+ * 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)
+{
+    if (Thread == NIL_RTTHREAD)
+        return NULL;
+    PRTTHREADINT pThread = rtThreadGet(Thread);
+    return pThread ?  pThread->szName : NULL;
+}
+
+
+/**
+ * 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.
+     */
+    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;
+    }
+    PRTTHREADINT pThread = rtThreadGet(Thread);
+    if (!pThread)
+        return VERR_INVALID_HANDLE;
+
+    /*
+     * Update the name.
+     */
+    pThread->szName[cchName] = '\0';    /* paranoia */
+    memcpy(pThread->szName, pszName, cchName);
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * 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;
+}
+
+
+/**
+ * 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, unsigned cMillies)
+{
+    int             rc;
+    PRTTHREADINT    pThread = rtThreadGet(Thread);
+    if (pThread)
+    {
+        rc = RTSemEventMultiWait(pThread->EventUser, cMillies);
+        rtThreadRelease(pThread);
+    }
+    else
+        rc = VERR_INVALID_HANDLE;
+    return rc;
+}
+
+
+/**
+ * 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, unsigned cMillies)
+{
+    int             rc;
+    PRTTHREADINT    pThread = rtThreadGet(Thread);
+    if (pThread)
+    {
+        rc = RTSemEventMultiWaitNoResume(pThread->EventUser, cMillies);
+        rtThreadRelease(pThread);
+    }
+    else
+        rc = VERR_INVALID_HANDLE;
+    return rc;
+}
+
+
+/**
+ * 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;
+}
+
+
+/**
+ * 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, unsigned 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);
+                }
+            }
+            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, unsigned cMillies, int *prc)
+{
+    int rc = rtThreadWait(Thread, cMillies, prc, true);
+    Assert(rc != VERR_INTERRUPTED);
+    return rc;
+}
+
+
+/**
+ * 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, unsigned cMillies, int *prc)
+{
+    return rtThreadWait(Thread, cMillies, prc, false);
+}
+
+
+/**
+ * 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_TMP(Tmp);
+                RT_THREAD_LOCK_RW(Tmp);
+                rc = rtThreadNativeSetPriority(pThread, enmType);
+                if (RT_SUCCESS(rc))
+                    ASMAtomicXchgSize(&pThread->enmType, enmType);
+                RT_THREAD_UNLOCK_RW(Tmp);
+                if (RT_FAILURE(rc))
+                    Log(("RTThreadSetType: failed on thread %p (%s), rc=%Vrc!!!\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;
+}
+
+
+/**
+ * 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;
+}
+
+
+#ifdef IN_RING3
+
+/**
+ * Recalculates scheduling attributes for the 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.
+ */
+int rtThreadDoCalcDefaultPriority(RTTHREADTYPE enmType)
+{
+    RT_THREAD_LOCK_TMP(Tmp);
+    RT_THREAD_LOCK_RW(Tmp);
+    int rc = rtSchedNativeCalcDefaultPriority(enmType);
+    RT_THREAD_UNLOCK_RW(Tmp);
+    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;
+    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.
+ */
+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_TMP(Tmp);
+    RT_THREAD_LOCK_RW(Tmp);
+    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(Tmp);
+    LogFlow(("rtThreadDoSetProcPriority: returns %Vrc\n", rc));
+    return rc;
+}
+
+
+/**
+ * Bitch about a deadlock.
+ *
+ * @param   pThread     This thread.
+ * @param   pCur        The thread we're deadlocking with.
+ * @param   enmState    The sleep state.
+ * @param   u64Block    The block data. A pointer or handle.
+ * @param   pszFile     Where we are gonna block.
+ * @param   uLine       Where we are gonna block.
+ * @param   uId         Where we are gonna block.
+ */
+static void rtThreadDeadlock(PRTTHREADINT pThread, PRTTHREADINT pCur, RTTHREADSTATE enmState, uint64_t u64Block,
+                             const char *pszFile, unsigned uLine, RTUINTPTR uId)
+{
+    AssertMsg1(pCur == pThread ? "!!Deadlock detected!!" : "!!Deadlock exists!!", uLine, pszFile, "");
+
+    /*
+     * Print the threads and locks involved.
+     */
+    PRTTHREADINT    apSeenThreads[8] = {0,0,0,0,0,0,0,0};
+    unsigned        iSeenThread = 0;
+    pCur = pThread;
+    for (unsigned iEntry = 0; pCur && iEntry < 256; iEntry++)
+    {
+        /*
+         * Print info on pCur. Determin next while doing so.
+         */
+        AssertMsg2(" #%d: %RTthrd/%RTnthrd %s: %s(%u) %RTptr\n",
+                   iEntry, pCur, pCur->Core.Key, pCur->szName,
+                   pCur->pszBlockFile, pCur->uBlockLine, pCur->uBlockId);
+        PRTTHREADINT pNext = NULL;
+        switch (pCur->enmState)
+        {
+            case RTTHREADSTATE_CRITSECT:
+            {
+                PRTCRITSECT pCritSect = pCur->Block.pCritSect;
+                if (pCur->enmState != RTTHREADSTATE_CRITSECT)
+                {
+                    AssertMsg2("Impossible!!!\n");
+                    break;
+                }
+                if (VALID_PTR(pCritSect) && RTCritSectIsInitialized(pCritSect))
+                {
+                    AssertMsg2("     Waiting on CRITSECT %p: Entered %s(%u) %RTptr\n",
+                               pCritSect, pCritSect->Strict.pszEnterFile,
+                               pCritSect->Strict.u32EnterLine, pCritSect->Strict.uEnterId);
+                    pNext = pCritSect->Strict.ThreadOwner;
+                }
+                else
+                    AssertMsg2("     Waiting on CRITSECT %p: invalid pointer or uninitialized critsect\n", pCritSect);
+                break;
+            }
+
+            default:
+                AssertMsg2(" Impossible!!! enmState=%d\n", pCur->enmState);
+                break;
+        }
+
+        /*
+         * Check for cycle.
+         */
+        if (iEntry && pCur == pThread)
+            break;
+        for (unsigned i = 0; i < ELEMENTS(apSeenThreads); i++)
+            if (apSeenThreads[i] == pCur)
+            {
+                AssertMsg2(" Cycle!\n");
+                pNext = NULL;
+                break;
+            }
+
+        /*
+         * Advance to the next thread.
+         */
+        iSeenThread = (iSeenThread + 1) % ELEMENTS(apSeenThreads);
+        apSeenThreads[iSeenThread] = pCur;
+        pCur = pNext;
+    }
+    AssertBreakpoint();
+}
+
+
+/**
+ * Change the thread state to blocking and do deadlock detection.
+ *
+ * This is a RT_STRICT method for debugging locks and detecting deadlocks.
+ *
+ * @param   pThread     This thread.
+ * @param   enmState    The sleep state.
+ * @param   u64Block    The block data. A pointer or handle.
+ * @param   pszFile     Where we are blocking.
+ * @param   uLine       Where we are blocking.
+ * @param   uId         Where we are blocking.
+ */
+void rtThreadBlocking(PRTTHREADINT pThread, RTTHREADSTATE enmState, uint64_t u64Block,
+                     const char *pszFile, unsigned uLine, RTUINTPTR uId)
+{
+    Assert(RTTHREAD_IS_SLEEPING(enmState));
+    if (pThread && pThread->enmState == RTTHREADSTATE_RUNNING)
+    {
+        /** @todo This has to be serialized! The deadlock detection isn't 100% safe!!! */
+        pThread->Block.u64      = u64Block;
+        pThread->pszBlockFile   = pszFile;
+        pThread->uBlockLine     = uLine;
+        pThread->uBlockId       = uId;
+        ASMAtomicXchgSize(&pThread->enmState, enmState);
+
+        /*
+         * Do deadlock detection.
+         *
+         * Since we're missing proper serialization, we don't declare it a
+         * deadlock until we've got three runs with the same list length.
+         * While this isn't perfect, it should avoid out the most obvious
+         * races on SMP boxes.
+         */
+        PRTTHREADINT    pCur;
+        unsigned        cPrevLength = ~0U;
+        unsigned        cEqualRuns = 0;
+        unsigned        iParanoia = 256;
+        do
+        {
+            unsigned cLength = 0;
+            pCur = pThread;
+            for (;;)
+            {
+                /*
+                 * Get the next thread.
+                 */
+                for (;;)
+                {
+                    switch (pCur->enmState)
+                    {
+                        case RTTHREADSTATE_CRITSECT:
+                        {
+                            PRTCRITSECT pCritSect = pCur->Block.pCritSect;
+                            if (pCur->enmState != RTTHREADSTATE_CRITSECT)
+                                continue;
+                            pCur = pCritSect->Strict.ThreadOwner;
+                            break;
+                        }
+
+                        default:
+                            pCur = NULL;
+                            break;
+                    }
+                    break;
+                }
+                if (!pCur)
+                    return;
+
+                /*
+                 * If we've got back to the blocking thread id we've got a deadlock.
+                 * If we've got a chain of more than 256 items, there is some kind of cycle
+                 * in the list, which means that there is already a deadlock somewhere.
+                 */
+                if (pCur == pThread || cLength >= 256)
+                    break;
+                cLength++;
+            }
+
+            /* compare with previous list run. */
+            if (cLength != cPrevLength)
+            {
+                cPrevLength = cLength;
+                cEqualRuns = 0;
+            }
+            else
+                cEqualRuns++;
+        } while (cEqualRuns < 3 && --iParanoia > 0);
+
+        /*
+         * Ok, if we ever get here, it's most likely a genuine deadlock.
+         */
+        rtThreadDeadlock(pThread, pCur, enmState, u64Block, pszFile, uLine, uId);
+    }
+}
+
+
+/**
+ * Unblocks a thread.
+ *
+ * This function is paired with rtThreadBlocking.
+ *
+ * @param   pThread     The current thread.
+ * @param   enmCurState The current state, used to check for nested blocking.
+ *                      The new state will be running.
+ */
+void rtThreadUnblocked(PRTTHREADINT pThread, RTTHREADSTATE enmCurState)
+{
+    if (pThread && pThread->enmState == enmCurState)
+        ASMAtomicXchgSize(&pThread->enmState, RTTHREADSTATE_RUNNING);
+}
+
+#endif /* IN_RING3 */
+
Index: trunk/src/VBox/Runtime/common/misc/zip.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/misc/zip.cpp	(revision 5417)
+++ trunk/src/VBox/Runtime/common/misc/zip.cpp	(revision 5417)
@@ -0,0 +1,1572 @@
+/* $Id$ */
+/** @file
+ * innotek Portable Runtime - Compression.
+ */
+
+/*
+ * Copyright (C) 2006-2007 innotek GmbH
+ *
+ * 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 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.
+ */
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+#define RTZIP_USE_STORE 1
+//#define RTZIP_USE_ZLIB 1
+//#define RTZIP_USE_BZLIB 1
+#define RTZIP_USE_LZF 1
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#ifdef RTZIP_USE_BZLIB
+# include <bzlib.h>
+#endif
+#ifdef RTZIP_USE_ZLIB
+# include <zlib.h>
+#endif
+#ifdef RTZIP_USE_LZF
+# include <lzf.h>
+# include <iprt/crc32.h>
+#endif
+
+#include <iprt/zip.h>
+#include <iprt/alloc.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/log.h>
+#include <iprt/string.h>
+
+#include <errno.h>
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+
+#ifdef RTZIP_USE_LZF
+
+/**
+ * LZF block header.
+ */
+#pragma pack(1)                         /* paranoia */
+typedef struct RTZIPLZFHDR
+{
+    /** Magic word (RTZIPLZFHDR_MAGIC). */
+    uint16_t    u16Magic;
+    /** The number of bytes of data following this header. */
+    uint16_t    cbData;
+    /** The CRC32 of the block. */
+    uint32_t    u32CRC;
+    /** The size of the uncompressed data in bytes. */
+    uint16_t    cbUncompressed;
+} RTZIPLZFHDR;
+#pragma pack()
+/** Pointer to a LZF block header. */
+typedef RTZIPLZFHDR *PRTZIPLZFHDR;
+/** Pointer to a const LZF block header. */
+typedef const RTZIPLZFHDR *PCRTZIPLZFHDR;
+
+/** The magic of a LZF block header. */
+#define RTZIPLZFHDR_MAGIC                       ('Z' | ('V' << 8))
+
+/** The max compressed data size.
+ * The maximum size of a block is currently 16KB.
+ * This is very important so we don't have to move input buffers around. */
+#define RTZIPLZF_MAX_DATA_SIZE                  (16384 - sizeof(RTZIPLZFHDR))
+
+/** The max uncompressed data size.
+ * This is important so we don't overflow the spill buffer in the decompressor. */
+#define RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE     (32*_1K)
+
+#endif /* RTZIP_USE_LZF */
+
+
+/**
+ * Compressor/Decompressor instance data.
+ */
+typedef struct RTZIPCOMP
+{
+    /** Output buffer. */
+#ifdef RTZIP_USE_LZF
+    uint8_t             abBuffer[128 * 1024];
+#else
+    uint8_t             abBuffer[64 * 1024];
+#endif
+    /** Compression output consumer. */
+    PFNRTZIPOUT         pfnOut;
+    /** User argument for the callback. */
+    void               *pvUser;
+
+    /**
+     * @copydoc RTZipCompress
+     */
+    DECLCALLBACKMEMBER(int, pfnCompress)(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf);
+
+    /**
+     * @copydoc RTZipCompFinish
+     */
+    DECLCALLBACKMEMBER(int, pfnFinish)(PRTZIPCOMP pZip);
+
+    /**
+     * @copydoc RTZipCompDestroy
+     */
+    DECLCALLBACKMEMBER(int, pfnDestroy)(PRTZIPCOMP pZip);
+
+    /** Compression type. */
+    RTZIPTYPE           enmType;
+    /** Type specific data. */
+    union
+    {
+#ifdef RTZIP_USE_STORE
+        /** Simple storing. */
+        struct
+        {
+            /** Current buffer postition. (where to start write) */
+            uint8_t    *pb;
+        } Store;
+#endif
+#ifdef RTZIP_USE_ZLIB
+        /** Zlib stream. */
+        z_stream        Zlib;
+#endif
+#ifdef RTZIP_USE_BZLIB
+        /** BZlib stream. */
+        bz_stream       BZlib;
+#endif
+#ifdef RTZIP_USE_LZF
+        /** LZF stream. */
+        struct
+        {
+            /** Current output buffer postition. */
+            uint8_t    *pbOutput;
+            /** The input buffer position. */
+            uint8_t    *pbInput;
+            /** The number of free bytes in the input buffer. */
+            size_t      cbInputFree;
+            /** The input buffer. */
+            uint8_t     abInput[RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE];
+        } LZF;
+#endif
+
+    } u;
+} RTZIPCOMP;
+
+
+
+/**
+ * Decompressor instance data.
+ */
+typedef struct RTZIPDECOMP
+{
+    /** Input buffer. */
+    uint8_t             abBuffer[1024 * 64];
+    /** Decompression input producer. */
+    PFNRTZIPIN          pfnIn;
+    /** User argument for the callback. */
+    void               *pvUser;
+
+    /**
+     * @copydoc RTZipDecompress
+     */
+    DECLCALLBACKMEMBER(int, pfnDecompress)(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten);
+
+    /**
+     * @copydoc RTZipDecompDestroy
+     */
+    DECLCALLBACKMEMBER(int, pfnDestroy)(PRTZIPDECOMP pZip);
+
+    /** Compression type. */
+    RTZIPTYPE           enmType;
+    /** Type specific data. */
+    union
+    {
+#ifdef RTZIP_USE_STORE
+        /** Simple storing. */
+        struct
+        {
+            /** Current buffer postition. (where to start read) */
+            uint8_t    *pb;
+            /** Number of bytes left in the buffer. */
+            size_t      cbBuffer;
+        } Store;
+#endif
+#ifdef RTZIP_USE_ZLIB
+        /** Zlib stream. */
+        z_stream        Zlib;
+#endif
+#ifdef RTZIP_USE_BZLIB
+        /** BZlib stream. */
+        bz_stream       BZlib;
+#endif
+#ifdef RTZIP_USE_LZF
+        /** LZF 'stream'. */
+        struct
+        {
+            /** Current input buffer postition. */
+            uint8_t    *pbInput;
+            /** The number of bytes left in the input buffer. */
+            size_t      cbInput;
+            /** The spill buffer.
+             * LZF is a block based compressor and not a stream compressor. So,
+             * we have to decompress full blocks if we want to get any of the data.
+             * This buffer is to store the spill after decompressing a block. */
+            uint8_t     abSpill[RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE];
+            /** The number of bytes left spill buffer. */
+            unsigned    cbSpill;
+            /** The current spill buffer position. */
+            uint8_t    *pbSpill;
+        } LZF;
+#endif
+
+    } u;
+} RTZIPDECOM;
+
+
+
+#ifdef RTZIP_USE_STORE
+
+/**
+ * @copydoc RTZipCompress
+ */
+static DECLCALLBACK(int) rtZipStoreCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
+{
+    while (cbBuf)
+    {
+        /*
+         * Flush.
+         */
+        size_t cb = (uintptr_t)&pZip->abBuffer[sizeof(pZip->abBuffer)] - (uintptr_t)pZip->u.Store.pb;
+        if (cb <= 0)
+        {
+            int rc = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer));
+            if (RT_FAILURE(rc))
+                return rc;
+            cb = sizeof(pZip->abBuffer);
+            pZip->u.Store.pb = &pZip->abBuffer[0];
+        }
+
+        /*
+         * Add to the buffer and advance.
+         */
+        if (cbBuf < cb)
+            cb = cbBuf;
+        memcpy(pZip->u.Store.pb, pvBuf, cb);
+        pZip->u.Store.pb += cb;
+        cbBuf -= cb;
+        pvBuf = (uint8_t *)pvBuf + cb;
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @copydoc RTZipCompFinish
+ */
+static DECLCALLBACK(int) rtZipStoreCompFinish(PRTZIPCOMP pZip)
+{
+    size_t cb = (uintptr_t)pZip->u.Store.pb - (uintptr_t)&pZip->abBuffer[0];
+    if (cb > 0)
+    {
+        int rc = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], cb);
+        if (RT_FAILURE(rc))
+            return rc;
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @copydoc RTZipCompDestroy
+ */
+static DECLCALLBACK(int) rtZipStoreCompDestroy(PRTZIPCOMP pZip)
+{
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Initializes the compressor instance.
+ * @returns iprt status code.
+ * @param   pZip        The compressor instance.
+ * @param   enmLevel    The desired compression level.
+ */
+static DECLCALLBACK(int) rtZipStoreCompInit(PRTZIPCOMP pZip, RTZIPLEVEL enmLevel)
+{
+    pZip->pfnCompress = rtZipStoreCompress;
+    pZip->pfnFinish   = rtZipStoreCompFinish;
+    pZip->pfnDestroy  = rtZipStoreCompDestroy;
+
+    pZip->u.Store.pb = &pZip->abBuffer[1];
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @copydoc RTZipDecompress
+ */
+static DECLCALLBACK(int) rtZipStoreDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
+{
+    size_t cbWritten = 0;
+    while (cbBuf)
+    {
+        /*
+         * Fill buffer.
+         */
+        size_t cb = pZip->u.Store.cbBuffer;
+        if (cb <= 0)
+        {
+            int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer), &cb);
+            if (RT_FAILURE(rc))
+                return rc;
+            pZip->u.Store.cbBuffer = cb;
+            pZip->u.Store.pb = &pZip->abBuffer[0];
+        }
+
+        /*
+         * No more data?
+         */
+        if (cb == 0)
+        {
+            if (pcbWritten)
+            {
+                *pcbWritten = cbWritten;
+                return VINF_SUCCESS;
+            }
+            return VERR_NO_DATA;
+        }
+
+        /*
+         * Add to the buffer and advance.
+         */
+        if (cbBuf < cb)
+            cb = cbBuf;
+        memcpy(pvBuf, pZip->u.Store.pb, cb);
+        pZip->u.Store.pb += cb;
+        pZip->u.Store.cbBuffer -= cb;
+        cbBuf -= cb;
+        pvBuf = (char *)pvBuf + cb;
+        cbWritten += cb;
+    }
+    if (pcbWritten)
+        *pcbWritten = cbWritten;
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @copydoc RTZipDecompDestroy
+ */
+static DECLCALLBACK(int) rtZipStoreDecompDestroy(PRTZIPDECOMP pZip)
+{
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Initialize the decompressor instance.
+ * @returns iprt status code.
+ * @param   pZip        The decompressor instance.
+ */
+static DECLCALLBACK(int) rtZipStoreDecompInit(PRTZIPDECOMP pZip)
+{
+    pZip->pfnDecompress = rtZipStoreDecompress;
+    pZip->pfnDestroy = rtZipStoreDecompDestroy;
+
+    pZip->u.Store.pb = &pZip->abBuffer[0];
+    pZip->u.Store.cbBuffer = 0;
+    return VINF_SUCCESS;
+}
+
+#endif
+
+
+#ifdef RTZIP_USE_ZLIB
+/**
+ * Convert from zlib errno to iprt status code.
+ * @returns iprt status code.
+ * @param   rc      Zlib error code.
+ */
+static int zipErrConvertFromZlib(int rc)
+{
+    /** @todo proper zlib error convertion. */
+    switch (rc)
+    {
+        case Z_ERRNO:
+            return RTErrConvertFromErrno(errno);
+        case Z_STREAM_ERROR:
+        case Z_DATA_ERROR:
+        case Z_MEM_ERROR:
+        case Z_BUF_ERROR:
+        case Z_VERSION_ERROR:
+            return VERR_GENERAL_FAILURE;
+        default:
+            if (rc >= 0)
+                return VINF_SUCCESS;
+            return VERR_GENERAL_FAILURE;
+    }
+}
+
+
+/**
+ * @copydoc RTZipCompress
+ */
+static DECLCALLBACK(int) rtZipZlibCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
+{
+    pZip->u.Zlib.next_in  = (Bytef *)pvBuf;
+    pZip->u.Zlib.avail_in = cbBuf;
+    while (pZip->u.Zlib.avail_in > 0)
+    {
+        /*
+         * Flush output buffer?
+         */
+        if (pZip->u.Zlib.avail_out <= 0)
+        {
+            int rc = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer) - pZip->u.Zlib.avail_out);
+            if (RT_FAILURE(rc))
+                return rc;
+            pZip->u.Zlib.avail_out = sizeof(pZip->abBuffer);
+            pZip->u.Zlib.next_out = &pZip->abBuffer[0];
+        }
+
+        /*
+         * Pass it on to zlib.
+         */
+        int rc = deflate(&pZip->u.Zlib, Z_NO_FLUSH);
+        if (rc != Z_OK)
+            return zipErrConvertFromZlib(rc);
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @copydoc RTZipCompFinish
+ */
+static DECLCALLBACK(int) rtZipZlibCompFinish(PRTZIPCOMP pZip)
+{
+    int rc = Z_OK;
+    for (;;)
+    {
+        /*
+         * Flush outstanding stuff. writes.
+         */
+        if (rc == Z_STREAM_END || pZip->u.Zlib.avail_out <= 0)
+        {
+            int rc2 = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer) - pZip->u.Zlib.avail_out);
+            if (RT_FAILURE(rc2))
+                return rc2;
+            pZip->u.Zlib.avail_out = sizeof(pZip->abBuffer);
+            pZip->u.Zlib.next_out = &pZip->abBuffer[0];
+            if (rc == Z_STREAM_END)
+                return VINF_SUCCESS;
+        }
+
+        /*
+         * Tell zlib to flush.
+         */
+        rc = deflate(&pZip->u.Zlib, Z_FINISH);
+        if (rc != Z_OK && rc != Z_STREAM_END)
+            return zipErrConvertFromZlib(rc);
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @copydoc RTZipCompDestroy
+ */
+static DECLCALLBACK(int) rtZipZlibCompDestroy(PRTZIPCOMP pZip)
+{
+    /*
+     * Terminate the deflate instance.
+     */
+    int rc = deflateEnd(&pZip->u.Zlib);
+    if (rc != Z_OK)
+        rc = zipErrConvertFromZlib(rc);
+    return rc;
+}
+
+
+/**
+ * Initializes the compressor instance.
+ * @returns iprt status code.
+ * @param   pZip        The compressor instance.
+ * @param   enmLevel    The desired compression level.
+ */
+static DECLCALLBACK(int) rtZipZlibCompInit(PRTZIPCOMP pZip, RTZIPLEVEL enmLevel)
+{
+    pZip->pfnCompress = rtZipZlibCompress;
+    pZip->pfnFinish   = rtZipZlibCompFinish;
+    pZip->pfnDestroy  = rtZipZlibCompDestroy;
+
+    int iLevel = Z_DEFAULT_COMPRESSION;
+    switch (enmLevel)
+    {
+        case RTZIPLEVEL_STORE:      iLevel = 0; break;
+        case RTZIPLEVEL_FAST:       iLevel = 2; break;
+        case RTZIPLEVEL_DEFAULT:    iLevel = Z_DEFAULT_COMPRESSION; break;
+        case RTZIPLEVEL_MAX:        iLevel = 9; break;
+    }
+
+    memset(&pZip->u.Zlib, 0, sizeof(pZip->u.Zlib));
+    pZip->u.Zlib.next_out  = &pZip->abBuffer[1];
+    pZip->u.Zlib.avail_out = sizeof(pZip->abBuffer) - 1;
+    pZip->u.Zlib.opaque    = pZip;
+
+    int rc = deflateInit(&pZip->u.Zlib, enmLevel);
+    return rc >= 0 ? rc = VINF_SUCCESS : zipErrConvertFromZlib(rc);
+}
+
+
+/**
+ * @copydoc RTZipDecompress
+ */
+static DECLCALLBACK(int) rtZipZlibDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
+{
+    pZip->u.Zlib.next_out = (Bytef *)pvBuf;
+    pZip->u.Zlib.avail_out = cbBuf;
+    int rc = Z_OK;
+    while (pZip->u.Zlib.avail_out > 0)
+    {
+        /*
+         * Read more input?
+         */
+        if (pZip->u.Zlib.avail_in <= 0)
+        {
+            size_t cb = sizeof(pZip->abBuffer);
+            int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer), &cb);
+            if (RT_FAILURE(rc))
+                return rc;
+            pZip->u.Zlib.avail_in = cb;
+            pZip->u.Zlib.next_in = &pZip->abBuffer[0];
+        }
+
+        /*
+         * Pass it on to zlib.
+         */
+        rc = inflate(&pZip->u.Zlib, Z_NO_FLUSH);
+        if (rc == Z_STREAM_END)
+        {
+            if (pcbWritten)
+                *pcbWritten = cbBuf - pZip->u.Zlib.avail_out;
+            else if (pZip->u.Zlib.avail_out > 0)
+                return VERR_NO_DATA;
+            break;
+        }
+        if (rc != Z_OK)
+            return zipErrConvertFromZlib(rc);
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @copydoc RTZipDecompDestroy
+ */
+static DECLCALLBACK(int) rtZipZlibDecompDestroy(PRTZIPDECOMP pZip)
+{
+    /*
+     * Terminate the deflate instance.
+     */
+    int rc = inflateEnd(&pZip->u.Zlib);
+    if (rc != Z_OK)
+        rc = zipErrConvertFromZlib(rc);
+    return rc;
+}
+
+
+/**
+ * Initialize the decompressor instance.
+ * @returns iprt status code.
+ * @param   pZip        The decompressor instance.
+ */
+static DECLCALLBACK(int) rtZipZlibDecompInit(PRTZIPDECOMP pZip)
+{
+    pZip->pfnDecompress = rtZipZlibDecompress;
+    pZip->pfnDestroy = rtZipZlibDecompDestroy;
+
+    memset(&pZip->u.Zlib, 0, sizeof(pZip->u.Zlib));
+    pZip->u.Zlib.opaque    = pZip;
+
+    int rc = inflateInit(&pZip->u.Zlib);
+    return rc >= 0 ? VINF_SUCCESS : zipErrConvertFromZlib(rc);
+}
+
+#endif
+
+
+#ifdef RTZIP_USE_BZLIB
+/**
+ * Convert from BZlib errno to iprt status code.
+ * @returns iprt status code.
+ * @param   rc      BZlib error code.
+ */
+static int zipErrConvertFromBZlib(int rc)
+{
+    /** @todo proper bzlib error convertion. */
+    switch (rc)
+    {
+        case BZ_SEQUENCE_ERROR:
+            AssertMsgFailed(("BZ_SEQUENCE_ERROR shall not happen!\n"));
+            return VERR_GENERAL_FAILURE;
+        case BZ_PARAM_ERROR:
+            return VERR_INVALID_PARAMETER;
+        case BZ_MEM_ERROR:
+            return VERR_NO_MEMORY;
+        case BZ_DATA_ERROR:
+        case BZ_DATA_ERROR_MAGIC:
+        case BZ_IO_ERROR:
+        case BZ_UNEXPECTED_EOF:
+        case BZ_CONFIG_ERROR:
+            return VERR_GENERAL_FAILURE;
+        case BZ_OUTBUFF_FULL:
+            AssertMsgFailed(("BZ_OUTBUFF_FULL shall not happen!\n"));
+            return VERR_GENERAL_FAILURE;
+        default:
+            if (rc >= 0)
+                return VINF_SUCCESS;
+            return VERR_GENERAL_FAILURE;
+    }
+}
+
+
+/**
+ * @copydoc RTZipCompress
+ */
+static DECLCALLBACK(int) rtZipBZlibCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
+{
+    pZip->u.BZlib.next_in  = (char *)pvBuf;
+    pZip->u.BZlib.avail_in = cbBuf;
+    while (pZip->u.BZlib.avail_in > 0)
+    {
+        /*
+         * Flush output buffer?
+         */
+        if (pZip->u.BZlib.avail_out <= 0)
+        {
+            int rc = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer) - pZip->u.BZlib.avail_out);
+            if (RT_FAILURE(rc))
+                return rc;
+            pZip->u.BZlib.avail_out = sizeof(pZip->abBuffer);
+            pZip->u.BZlib.next_out = (char *)&pZip->abBuffer[0];
+        }
+
+        /*
+         * Pass it on to zlib.
+         */
+        int rc = BZ2_bzCompress(&pZip->u.BZlib, BZ_RUN);
+        if (rc < 0 && rc != BZ_OUTBUFF_FULL)
+            return zipErrConvertFromBZlib(rc);
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @copydoc RTZipCompFinish
+ */
+static DECLCALLBACK(int) rtZipBZlibCompFinish(PRTZIPCOMP pZip)
+{
+    int rc = BZ_FINISH_OK;
+    for (;;)
+    {
+        /*
+         * Flush output buffer?
+         */
+        if (rc == BZ_STREAM_END || pZip->u.BZlib.avail_out <= 0)
+        {
+            int rc2 = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer) - pZip->u.BZlib.avail_out);
+            if (RT_FAILURE(rc2))
+                return rc2;
+            pZip->u.BZlib.avail_out = sizeof(pZip->abBuffer);
+            pZip->u.BZlib.next_out = (char *)&pZip->abBuffer[0];
+            if (rc == BZ_STREAM_END)
+                return VINF_SUCCESS;
+        }
+
+        /*
+         * Tell BZlib to finish it.
+         */
+        rc = BZ2_bzCompress(&pZip->u.BZlib, BZ_FINISH);
+        if (rc < 0 && rc != BZ_OUTBUFF_FULL)
+            return zipErrConvertFromBZlib(rc);
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @copydoc RTZipCompDestroy
+ */
+static DECLCALLBACK(int) rtZipBZlibCompDestroy(PRTZIPCOMP pZip)
+{
+    /*
+     * Terminate the deflate instance.
+     */
+    int rc = BZ2_bzCompressEnd(&pZip->u.BZlib);
+    if (rc != BZ_OK)
+        rc = zipErrConvertFromBZlib(rc);
+    return rc;
+}
+
+
+/**
+ * Initializes the compressor instance.
+ * @returns iprt status code.
+ * @param   pZip        The compressor instance.
+ * @param   enmLevel    The desired compression level.
+ */
+static DECLCALLBACK(int) rtZipBZlibCompInit(PRTZIPCOMP pZip, RTZIPLEVEL enmLevel)
+{
+    pZip->pfnCompress = rtZipBZlibCompress;
+    pZip->pfnFinish   = rtZipBZlibCompFinish;
+    pZip->pfnDestroy  = rtZipBZlibCompDestroy;
+
+    int iSize = 6;
+    int iWork = 0;
+    switch (enmLevel)
+    {
+        case RTZIPLEVEL_STORE:      iSize = 1; iWork = 2; break;
+        case RTZIPLEVEL_FAST:       iSize = 2; iWork = 0; break;
+        case RTZIPLEVEL_DEFAULT:    iSize = 5; iWork = 0; break;
+        case RTZIPLEVEL_MAX:        iSize = 9; iWork = 0; break;
+    }
+
+    memset(&pZip->u.BZlib, 0, sizeof(pZip->u.BZlib));
+    pZip->u.BZlib.next_out  = (char *)&pZip->abBuffer[1];
+    pZip->u.BZlib.avail_out = sizeof(pZip->abBuffer) - 1;
+    pZip->u.BZlib.opaque    = pZip;
+
+    int rc = BZ2_bzCompressInit(&pZip->u.BZlib, iSize, 0, iWork);
+    return rc >= 0 ? VINF_SUCCESS : zipErrConvertFromBZlib(rc);;
+}
+
+
+/**
+ * @copydoc RTZipDecompress
+ */
+static DECLCALLBACK(int) rtZipBZlibDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
+{
+    pZip->u.BZlib.next_out  = (char *)pvBuf;
+    pZip->u.BZlib.avail_out = cbBuf;
+    while (pZip->u.BZlib.avail_out > 0)
+    {
+        /*
+         * Read more output buffer?
+         */
+        if (pZip->u.BZlib.avail_in <= 0)
+        {
+            size_t cb;
+            int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer), &cb);
+            if (RT_FAILURE(rc))
+                return rc;
+            pZip->u.BZlib.avail_in = cb;
+            pZip->u.BZlib.next_in = (char *)&pZip->abBuffer[0];
+        }
+
+        /*
+         * Pass it on to zlib.
+         */
+        int rc = BZ2_bzDecompress(&pZip->u.BZlib);
+        if (rc == BZ_STREAM_END || rc == BZ_OUTBUFF_FULL)
+        {
+            if (pcbWritten)
+                *pcbWritten = cbBuf - pZip->u.BZlib.avail_out;
+            else if (pZip->u.BZlib.avail_out > 0)
+                return VERR_NO_DATA;
+            break;
+        }
+        if (rc < 0)
+            return zipErrConvertFromBZlib(rc);
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @copydoc RTZipDecompDestroy
+ */
+static DECLCALLBACK(int) rtZipBZlibDecompDestroy(PRTZIPDECOMP pZip)
+{
+    /*
+     * Terminate the deflate instance.
+     */
+    int rc = BZ2_bzDecompressEnd(&pZip->u.BZlib);
+    if (rc != BZ_OK)
+        rc = zipErrConvertFromBZlib(rc);
+    return rc;
+}
+
+
+/**
+ * Initialize the decompressor instance.
+ * @returns iprt status code.
+ * @param   pZip        The decompressor instance.
+ */
+static DECLCALLBACK(int) rtZipBZlibDecompInit(PRTZIPDECOMP pZip)
+{
+    pZip->pfnDecompress = rtZipBZlibDecompress;
+    pZip->pfnDestroy = rtZipBZlibDecompDestroy;
+
+    memset(&pZip->u.BZlib, 0, sizeof(pZip->u.BZlib));
+    pZip->u.BZlib.opaque    = pZip;
+
+    int rc = BZ2_bzDecompressInit(&pZip->u.BZlib, 0, 0);
+    return rc >= 0 ? VINF_SUCCESS : zipErrConvertFromBZlib(rc);
+}
+
+#endif
+
+
+#ifdef RTZIP_USE_LZF
+
+/**
+ * Flushes the output buffer.
+ * @returns iprt status code.
+ * @param   pZip        The compressor instance.
+ */
+static int rtZipLZFCompFlushOutput(PRTZIPCOMP pZip)
+{
+    size_t      cb = pZip->u.LZF.pbOutput - &pZip->abBuffer[0];
+    pZip->u.LZF.pbOutput = &pZip->abBuffer[0];
+    return pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], cb);
+}
+
+
+/**
+ * Compresses a buffer using LZF.
+ *
+ * @returns VBox status code.
+ * @param   pZip        The compressor instance.
+ * @param   pbBuf       What to compress.
+ * @param   cbBuf       How much to compress.
+ */
+static int rtZipLZFCompressBuffer(PRTZIPCOMP pZip, const uint8_t *pbBuf, size_t cbBuf)
+{
+    bool fForceFlush = false;
+    while (cbBuf > 0)
+    {
+        /*
+         * Flush output buffer?
+         */
+        unsigned cbFree = sizeof(pZip->abBuffer) - (pZip->u.LZF.pbOutput - &pZip->abBuffer[0]);
+        if (    fForceFlush
+            ||  cbFree < RTZIPLZF_MAX_DATA_SIZE + sizeof(RTZIPLZFHDR))
+        {
+            int rc = rtZipLZFCompFlushOutput(pZip);
+            if (RT_FAILURE(rc))
+                return rc;
+            fForceFlush = false;
+            cbFree = sizeof(pZip->abBuffer);
+        }
+
+        /*
+         * Setup the block header.
+         */
+        PRTZIPLZFHDR pHdr = (PRTZIPLZFHDR)pZip->u.LZF.pbOutput; /* warning: This might be unaligned! */
+        pHdr->u16Magic = RTZIPLZFHDR_MAGIC;
+        pHdr->cbData = 0;
+        pHdr->u32CRC = 0;
+        pHdr->cbUncompressed = 0;
+        cbFree -= sizeof(*pHdr);
+        pZip->u.LZF.pbOutput += sizeof(*pHdr);
+
+        /*
+         * Compress data for the block.
+         *
+         * We try compress as much as we have freespace for at first,
+         * but if it turns out the compression is inefficient, we'll
+         * reduce the size of data we try compress till it fits the
+         * output space.
+         */
+        cbFree  = RT_MIN(cbFree, RTZIPLZF_MAX_DATA_SIZE);
+        unsigned cbInput = RT_MIN(RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE, cbBuf);
+        unsigned cbOutput = lzf_compress(pbBuf, cbInput, pZip->u.LZF.pbOutput, cbFree);
+        if (!cbOutput)
+        {
+            /** @todo add an alternative method which stores the raw data if bad compression. */
+            do
+            {
+                cbInput /= 2;
+                if (!cbInput)
+                {
+                    AssertMsgFailed(("lzf_compress bug! cbFree=%zu\n", cbFree));
+                    return VERR_INTERNAL_ERROR;
+                }
+                cbOutput = lzf_compress(pbBuf, cbInput, pZip->u.LZF.pbOutput, cbFree);
+            } while (!cbOutput);
+            fForceFlush = true;
+        }
+
+        /*
+         * Upate the header and advance the input buffer.
+         */
+        pHdr->cbData = cbOutput;
+        //pHdr->u32CRC = RTCrc32(pbBuf, cbInput); - too slow
+        pHdr->cbUncompressed = cbInput;
+
+        pZip->u.LZF.pbOutput += cbOutput;
+        cbBuf -= cbInput;
+        pbBuf += cbInput;
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Flushes the input buffer.
+ * @returns iprt status code.
+ * @param   pZip        The compressor instance.
+ */
+static int rtZipLZFCompFlushInput(PRTZIPCOMP pZip)
+{
+    size_t cb = pZip->u.LZF.pbInput - &pZip->u.LZF.abInput[0];
+    pZip->u.LZF.pbInput = &pZip->u.LZF.abInput[0];
+    pZip->u.LZF.cbInputFree = sizeof(pZip->u.LZF.abInput);
+    if (cb)
+        return rtZipLZFCompressBuffer(pZip, pZip->u.LZF.abInput, cb);
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @copydoc RTZipCompress
+ */
+static DECLCALLBACK(int) rtZipLZFCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
+{
+#define RTZIPLZF_SMALL_CHUNK (128)
+
+    /*
+     * Flush the input buffer if necessary.
+     */
+    if (    (   cbBuf <= RTZIPLZF_SMALL_CHUNK
+             && cbBuf > pZip->u.LZF.cbInputFree)
+        ||  (   cbBuf > RTZIPLZF_SMALL_CHUNK
+             && pZip->u.LZF.cbInputFree != sizeof(pZip->u.LZF.abInput))
+       )
+    {
+        int rc = rtZipLZFCompFlushInput(pZip);
+        if (RT_FAILURE(rc))
+            return rc;
+    }
+
+    /*
+     * If it's a relativly small block put it in the input buffer, elsewise
+     * compress directly it.
+     */
+    if (cbBuf <= RTZIPLZF_SMALL_CHUNK)
+    {
+        Assert(pZip->u.LZF.cbInputFree >= cbBuf);
+        memcpy(pZip->u.LZF.pbInput, pvBuf, cbBuf);
+        pZip->u.LZF.pbInput += cbBuf;
+        pZip->u.LZF.cbInputFree -= cbBuf;
+    }
+    else
+    {
+        Assert(pZip->u.LZF.cbInputFree == sizeof(pZip->u.LZF.abInput));
+        int rc = rtZipLZFCompressBuffer(pZip, (const uint8_t *)pvBuf, cbBuf);
+        if (RT_FAILURE(rc))
+            return rc;
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @copydoc RTZipCompFinish
+ */
+static DECLCALLBACK(int) rtZipLZFCompFinish(PRTZIPCOMP pZip)
+{
+    int rc = rtZipLZFCompFlushInput(pZip);
+    if (RT_SUCCESS(rc))
+        rc = rtZipLZFCompFlushOutput(pZip);
+    return rc;
+}
+
+
+/**
+ * @copydoc RTZipCompDestroy
+ */
+static DECLCALLBACK(int) rtZipLZFCompDestroy(PRTZIPCOMP pZip)
+{
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Initializes the compressor instance.
+ * @returns iprt status code.
+ * @param   pZip        The compressor instance.
+ * @param   enmLevel    The desired compression level.
+ */
+static DECLCALLBACK(int) rtZipLZFCompInit(PRTZIPCOMP pZip, RTZIPLEVEL enmLevel)
+{
+    pZip->pfnCompress = rtZipLZFCompress;
+    pZip->pfnFinish   = rtZipLZFCompFinish;
+    pZip->pfnDestroy  = rtZipLZFCompDestroy;
+
+    pZip->u.LZF.pbOutput = &pZip->abBuffer[1];
+    pZip->u.LZF.pbInput  = &pZip->u.LZF.abInput[0];
+    pZip->u.LZF.cbInputFree = sizeof(pZip->u.LZF.abInput);
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * This will validate a header and to all the necessary bitching if it's invalid.
+ * @returns true if valid.
+ * @returns false if invalid.
+ * @param   pHdr        Pointer to the header.\
+ */
+static bool rtZipLZFValidHeader(PCRTZIPLZFHDR pHdr)
+{
+    if (    pHdr->u16Magic != RTZIPLZFHDR_MAGIC
+        ||  !pHdr->cbData
+        ||  pHdr->cbData > RTZIPLZF_MAX_DATA_SIZE
+        ||  !pHdr->cbUncompressed
+        ||  pHdr->cbUncompressed > RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE
+       )
+    {
+        AssertMsgFailed(("Invalid LZF header! %.*%Rhxs\n", sizeof(pHdr), pHdr));
+        return false;
+    }
+    return true;
+}
+
+
+/**
+ * @copydoc RTZipDecompress
+ */
+static DECLCALLBACK(int) rtZipLZFDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
+{
+    /*
+     * Decompression loop.
+     *
+     * This a bit ugly because we have to deal with reading block...
+     * To simplify matters we've put a max block size and will never
+     * fill the input buffer with more than allows us to complete
+     * any partially read blocks.
+     *
+     * When possible we decompress directly to the user buffer, when
+     * not possible we'll use the spill buffer.
+     */
+    while (cbBuf > 0)
+    {
+        /*
+         * Anything in the spill buffer?
+         */
+        if (pZip->u.LZF.cbSpill > 0)
+        {
+            size_t cb = RT_MIN(pZip->u.LZF.cbSpill, cbBuf);
+            memcpy(pvBuf, pZip->u.LZF.pbSpill, cb);
+            pZip->u.LZF.pbSpill += cb;
+            pZip->u.LZF.cbSpill -= cb;
+            cbBuf -= cb;
+            if (pcbWritten)
+                *pcbWritten = cb;
+            if (!cbBuf)
+                break;
+            pvBuf = (uint8_t *)pvBuf + cb;
+        }
+
+        /*
+         * Incomplete header or nothing at all.
+         */
+        PCRTZIPLZFHDR pHdr;
+        if (pZip->u.LZF.cbInput < sizeof(RTZIPLZFHDR))
+        {
+            if (pZip->u.LZF.cbInput <= 0)
+            {
+                /* empty, fill the buffer. */
+                size_t cb = 0;
+                int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0],
+                                     sizeof(pZip->abBuffer) - RTZIPLZF_MAX_DATA_SIZE, &cb);
+                if (RT_FAILURE(rc))
+                    return rc;
+                pZip->u.LZF.pbInput = &pZip->abBuffer[0];
+                pZip->u.LZF.cbInput = cb;
+                pHdr = (PCRTZIPLZFHDR)pZip->u.LZF.pbInput;
+            }
+            else
+            {
+                /* move the header up and fill the buffer. */
+                size_t cbCur = pZip->u.LZF.cbInput;
+                memmove(&pZip->abBuffer[0], pZip->u.LZF.pbInput, cbCur);
+                pZip->u.LZF.pbInput = &pZip->abBuffer[0];
+
+                size_t cb = 0;
+                int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[cbCur],
+                                     sizeof(pZip->abBuffer) - RTZIPLZF_MAX_DATA_SIZE - cbCur, &cb);
+                if (RT_FAILURE(rc))
+                    return rc;
+                pHdr = (PCRTZIPLZFHDR)pZip->u.LZF.pbInput;
+                pZip->u.LZF.cbInput += cb;
+            }
+
+            /*
+             * Validate the header.
+             */
+            if (!rtZipLZFValidHeader(pHdr))
+                return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
+        }
+        else
+        {
+            /*
+             * Validate the header and check if it's an incomplete block.
+             */
+            pHdr = (PCRTZIPLZFHDR)pZip->u.LZF.pbInput;
+            if (!rtZipLZFValidHeader(pHdr))
+                return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
+
+            if (pHdr->cbData > pZip->u.LZF.cbInput - sizeof(*pHdr))
+            {
+                /* read the remainder of the block. */
+                size_t cbToRead = pHdr->cbData - (pZip->u.LZF.cbInput - sizeof(*pHdr));
+                Assert(&pZip->u.LZF.pbInput[pZip->u.LZF.cbInput + cbToRead] <= &pZip->u.LZF.pbInput[sizeof(pZip->abBuffer)]);
+                int rc = pZip->pfnIn(pZip->pvUser, &pZip->u.LZF.pbInput[pZip->u.LZF.cbInput],
+                                     cbToRead, NULL);
+                if (RT_FAILURE(rc))
+                    return rc;
+                pZip->u.LZF.cbInput += cbToRead;
+            }
+        }
+        AssertMsgReturn(sizeof(*pHdr) + pHdr->cbData <= pZip->u.LZF.cbInput,
+                        ("cbData=%#x cbInput=%#x\n", pHdr->cbData, pZip->u.LZF.cbInput),
+                        VERR_GENERAL_FAILURE); /** @todo Get better error codes for RTZip! */
+
+        /*
+         * Does the uncompressed data fit into the supplied buffer?
+         * If so we uncompress it directly into the user buffer, else we'll have to use the spill buffer.
+         */
+        unsigned cbUncompressed = pHdr->cbUncompressed;
+        if (cbUncompressed <= cbBuf)
+        {
+            unsigned cbOutput = lzf_decompress(pHdr + 1, pHdr->cbData, pvBuf, cbUncompressed);
+            if (cbOutput != cbUncompressed)
+            {
+                AssertMsgFailed(("Decompression error, errno=%d. cbOutput=%#x cbUncompressed=%#x\n",
+                                 errno, cbOutput, cbUncompressed));
+                return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
+            }
+            cbBuf -= cbUncompressed;
+            pvBuf = (uint8_t *)pvBuf + cbUncompressed;
+        }
+        else
+        {
+            unsigned cbOutput = lzf_decompress(pHdr + 1, pHdr->cbData, pZip->u.LZF.abSpill, cbUncompressed);
+            if (cbOutput != cbUncompressed)
+            {
+                AssertMsgFailed(("Decompression error, errno=%d. cbOutput=%#x cbUncompressed=%#x\n",
+                                 errno, cbOutput, cbUncompressed));
+                return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
+            }
+            pZip->u.LZF.pbSpill = &pZip->u.LZF.abSpill[0];
+            pZip->u.LZF.cbSpill = cbUncompressed;
+        }
+
+        /* advance the input buffer */
+        pZip->u.LZF.cbInput -= pHdr->cbData + sizeof(*pHdr);
+        pZip->u.LZF.pbInput += pHdr->cbData + sizeof(*pHdr);
+        if (pcbWritten)
+            *pcbWritten += cbUncompressed;
+    }
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @copydoc RTZipDecompDestroy
+ */
+static DECLCALLBACK(int) rtZipLZFDecompDestroy(PRTZIPDECOMP pZip)
+{
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Initalize the decompressor instance.
+ * @returns iprt status code.
+ * @param   pZip        The decompressor instance.
+ */
+static DECLCALLBACK(int) rtZipLZFDecompInit(PRTZIPDECOMP pZip)
+{
+    pZip->pfnDecompress = rtZipLZFDecompress;
+    pZip->pfnDestroy = rtZipLZFDecompDestroy;
+
+    pZip->u.LZF.pbInput    = NULL;
+    pZip->u.LZF.cbInput    = 0;
+    pZip->u.LZF.cbSpill    = 0;
+    pZip->u.LZF.pbSpill    = NULL;
+
+    return VINF_SUCCESS;
+}
+
+#endif /* RTZIP_USE_LZF */
+
+
+/**
+ * Create a compressor instance.
+ *
+ * @returns iprt status code.
+ * @param   ppZip       Where to store the instance handle.
+ * @param   pvUser      User argument which will be passed on to pfnOut and pfnIn.
+ * @param   pfnOut      Callback for consuming output of compression.
+ * @param   enmType     Type of compressor to create.
+ * @param   enmLevel    Compression level.
+ */
+RTDECL(int)     RTZipCompCreate(PRTZIPCOMP *ppZip, void *pvUser, PFNRTZIPOUT pfnOut, RTZIPTYPE enmType, RTZIPLEVEL enmLevel)
+{
+    /*
+     * Validate input.
+     */
+    if (    enmType < RTZIPTYPE_AUTO
+        ||  enmType > RTZIPTYPE_LZF)
+    {
+        AssertMsgFailed(("Invalid enmType=%d\n", enmType));
+        return VERR_INVALID_PARAMETER;
+    }
+    if (    enmLevel < RTZIPLEVEL_STORE
+        ||  enmLevel > RTZIPLEVEL_MAX)
+    {
+        AssertMsgFailed(("Invalid enmLevel=%d\n", enmLevel));
+        return VERR_INVALID_PARAMETER;
+    }
+    if (!pfnOut || !ppZip)
+    {
+        AssertMsgFailed(("Must supply pfnOut and ppZip!\n"));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    /*
+     * Allocate memory for the instance data.
+     */
+    PRTZIPCOMP pZip = (PRTZIPCOMP)RTMemAlloc(sizeof(RTZIPCOMP));
+    if (!pZip)
+        return VERR_NO_MEMORY;
+
+    /*
+     * Determin auto type.
+     */
+    if (enmType == RTZIPTYPE_AUTO)
+    {
+        if (enmLevel == RTZIPLEVEL_STORE)
+            enmType = RTZIPTYPE_STORE;
+        else
+        {
+#if defined(RTZIP_USE_ZLIB) && defined(RTZIP_USE_BZLIB)
+            if (enmLevel == RTZIPLEVEL_MAX)
+                enmType = RTZIPTYPE_BZLIB;
+            else
+                enmType = RTZIPTYPE_ZLIB;
+#elif defined(RTZIP_USE_ZLIB)
+            enmType = RTZIPTYPE_ZLIB;
+#elif defined(RTZIP_USE_BZLIB)
+            enmType = RTZIPTYPE_BZLIB;
+#else
+            enmType = RTZIPTYPE_STORE;
+#endif
+        }
+    }
+
+    /*
+     * Init instance.
+     */
+    pZip->pfnOut  = pfnOut;
+    pZip->enmType = enmType;
+    pZip->pvUser  = pvUser;
+    pZip->abBuffer[0] = enmType;       /* first byte is the compression type. */
+    int rc = VINF_SUCCESS;
+    switch (enmType)
+    {
+#ifdef RTZIP_USE_STORE
+        case RTZIPTYPE_STORE:
+            rc = rtZipStoreCompInit(pZip, enmLevel);
+            break;
+#endif
+
+#ifdef RTZIP_USE_ZLIB
+        case RTZIPTYPE_ZLIB:
+            rc = rtZipZlibCompInit(pZip, enmLevel);
+            break;
+#endif
+
+#ifdef RTZIP_USE_BZLIB
+        case RTZIPTYPE_BZLIB:
+            rc = rtZipBZlibCompInit(pZip, enmLevel);
+            break;
+#endif
+
+#ifdef RTZIP_USE_LZF
+        case RTZIPTYPE_LZF:
+            rc = rtZipLZFCompInit(pZip, enmLevel);
+            break;
+#endif
+
+        default:
+            AssertMsgFailed(("Not implemented!\n"));
+            rc = VERR_NOT_IMPLEMENTED;
+            break;
+    }
+
+    if (RT_SUCCESS(rc))
+        *ppZip = pZip;
+    else
+        RTMemFree(pZip);
+    return rc;
+}
+
+
+/**
+ * Compresses a chunk of memory.
+ *
+ * @returns iprt status code.
+ * @param   pZip        The compressor instance.
+ * @param   pvBuf       Pointer to buffer containing the bits to compress.
+ * @param   cbBuf       Number of bytes to compress.
+ */
+RTDECL(int)     RTZipCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
+{
+    if (!cbBuf)
+        return VINF_SUCCESS;
+    return pZip->pfnCompress(pZip, pvBuf, cbBuf);
+}
+
+
+/**
+ * Finishes the compression.
+ * This will flush all data and terminate the compression data stream.
+ *
+ * @returns iprt status code.
+ * @param   pZip        The compressor instance.
+ */
+RTDECL(int)     RTZipCompFinish(PRTZIPCOMP pZip)
+{
+    return pZip->pfnFinish(pZip);
+}
+
+
+/**
+ * Destroys the compressor instance.
+ *
+ * @returns iprt status code.
+ * @param   pZip        The compressor instance.
+ */
+RTDECL(int)     RTZipCompDestroy(PRTZIPCOMP pZip)
+{
+    /*
+     * Compressor specific destruction attempt first.
+     */
+    int rc = pZip->pfnDestroy(pZip);
+    AssertRCReturn(rc, rc);
+
+    /*
+     * Free the instance memory.
+     */
+    pZip->enmType = RTZIPTYPE_INVALID;
+    RTMemFree(pZip);
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @copydoc RTZipDecompress
+ */
+static DECLCALLBACK(int) rtZipStubDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
+{
+    return VERR_NOT_SUPPORTED;
+}
+
+
+/**
+ * @copydoc RTZipDecompDestroy
+ */
+static DECLCALLBACK(int) rtZipStubDecompDestroy(PRTZIPDECOMP pZip)
+{
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Create a decompressor instance.
+ *
+ * @returns iprt status code.
+ * @param   ppZip       Where to store the instance handle.
+ * @param   pvUser      User argument which will be passed on to pfnOut and pfnIn.
+ * @param   pfnIn       Callback for producing input for decompression.
+ */
+RTDECL(int)     RTZipDecompCreate(PRTZIPDECOMP *ppZip, void *pvUser, PFNRTZIPIN pfnIn)
+{
+    /*
+     * Validate input.
+     */
+    if (!pfnIn || !ppZip)
+    {
+        AssertMsgFailed(("Must supply pfnIn and ppZip!\n"));
+        return VERR_INVALID_PARAMETER;
+    }
+
+    /*
+     * Allocate memory for the instance data.
+     */
+    PRTZIPDECOMP pZip = (PRTZIPDECOMP)RTMemAlloc(sizeof(RTZIPDECOMP));
+    if (!pZip)
+        return VERR_NO_MEMORY;
+
+    /*
+     * Init instance.
+     */
+    pZip->pfnIn   = pfnIn;
+    pZip->enmType = RTZIPTYPE_INVALID;
+    pZip->pvUser  = pvUser;
+    pZip->pfnDecompress = NULL;
+    pZip->pfnDestroy = rtZipStubDecompDestroy;
+
+    *ppZip = pZip;
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Lazy init of the decompressor.
+ * @returns iprt status code.
+ * @param   pZip        The decompressor instance.
+ */
+static int rtzipDecompInit(PRTZIPDECOMP pZip)
+{
+    /*
+     * Read the first byte from the stream so we can determin the type.
+     */
+    uint8_t u8Type;
+    int rc = pZip->pfnIn(pZip->pvUser, &u8Type, sizeof(u8Type), NULL);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    /*
+     * Determin type and do type specific init.
+     */
+    pZip->enmType = (RTZIPTYPE)u8Type;
+    switch (pZip->enmType)
+    {
+#ifdef RTZIP_USE_STORE
+        case RTZIPTYPE_STORE:
+            rc = rtZipStoreDecompInit(pZip);
+            break;
+#endif
+
+        case RTZIPTYPE_ZLIB:
+#ifdef RTZIP_USE_ZLIB
+            rc = rtZipZlibDecompInit(pZip);
+#else
+            AssertMsgFailedReturn(("Zlib is not include in this build!\n"), VERR_NOT_IMPLEMENTED);
+#endif
+            break;
+
+        case RTZIPTYPE_BZLIB:
+#ifdef RTZIP_USE_BZLIB
+            rc = rtZipBZlibDecompInit(pZip);
+#else
+            AssertMsgFailedReturn(("BZlib is not include in this build!\n"), VERR_NOT_IMPLEMENTED);
+#endif
+            break;
+
+        case RTZIPTYPE_LZF:
+#ifdef RTZIP_USE_LZF
+            rc = rtZipLZFDecompInit(pZip);
+#else
+            AssertMsgFailedReturn(("LZF is not include in this build!\n"), VERR_NOT_IMPLEMENTED);
+#endif
+            break;
+
+        case RTZIPTYPE_INVALID:
+            AssertMsgFailed(("Invalid compression type RTZIPTYPE_INVALID!\n"));
+            rc = VERR_NOT_IMPLEMENTED;
+            break;
+
+        case RTZIPTYPE_AUTO:
+            AssertMsgFailed(("Invalid compression type RTZIPTYPE_AUTO!\n"));
+            rc = VERR_INVALID_MAGIC;
+            break;
+
+        default:
+            AssertMsgFailed(("Unknown compression type %d\n\n", pZip->enmType));
+            rc = VERR_INVALID_MAGIC;
+            break;
+    }
+    if (RT_FAILURE(rc))
+    {
+        pZip->pfnDecompress = rtZipStubDecompress;
+        pZip->pfnDestroy = rtZipStubDecompDestroy;
+    }
+
+    return rc;
+}
+
+/**
+ * Decompresses a chunk of memory.
+ *
+ * @returns iprt status code.
+ * @param   pZip        The decompressor instance.
+ * @param   pvBuf       Where to store the decompressed data.
+ * @param   cbBuf       Number of bytes to produce. If pcbWritten is set
+ *                      any number of bytes up to cbBuf might be returned.
+ * @param   pcbWritten  Number of bytes actually written to the buffer. If NULL
+ *                      cbBuf number of bytes must be written.
+ */
+RTDECL(int)     RTZipDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
+{
+    /*
+     * Skip empty requests.
+     */
+    if (!cbBuf)
+        return VINF_SUCCESS;
+
+    /*
+     * Lazy init.
+     */
+    if (!pZip->pfnDecompress)
+    {
+        int rc = rtzipDecompInit(pZip);
+        if (RT_FAILURE(rc))
+            return rc;
+    }
+
+    /*
+     * 'Read' the decompressed stream.
+     */
+    return pZip->pfnDecompress(pZip, pvBuf, cbBuf, pcbWritten);
+}
+
+/**
+ * Destroys the decompressor instance.
+ *
+ * @returns iprt status code.
+ * @param   pZip        The decompressor instance.
+ */
+RTDECL(int)     RTZipDecompDestroy(PRTZIPDECOMP pZip)
+{
+    /*
+     * Destroy compressor instance and flush the output buffer.
+     */
+    int rc = pZip->pfnDestroy(pZip);
+    AssertRCReturn(rc, rc);
+
+    /*
+     * Free the instance memory.
+     */
+    pZip->enmType = RTZIPTYPE_INVALID;
+    RTMemFree(pZip);
+    return rc;
+}
+
+
