Exemplo n.º 1
0
DECLCALLBACK(int) SpawnerThread(RTTHREAD Thread, void *pvUser)
{
    PSPAWNERARGS pArgs = (PSPAWNERARGS)pvUser;
    pArgs->Process = NIL_RTPROCESS;
    const char *apszArgs[3] = { pArgs->pszExe, "child", NULL };
    return RTProcCreate(apszArgs[0], apszArgs, RTENV_DEFAULT, 0, &pArgs->Process);
}
Exemplo n.º 2
0
static int NetIfAdpCtl(const char * pcszIfName, const char *pszAddr, const char *pszOption, const char *pszMask)
{
    const char *args[] = { NULL, pcszIfName, pszAddr, pszOption, pszMask, NULL };

    char szAdpCtl[RTPATH_MAX];
    int rc = RTPathExecDir(szAdpCtl, sizeof(szAdpCtl) - sizeof("/" VBOXNETADPCTL_NAME));
    if (RT_FAILURE(rc))
    {
        LogRel(("NetIfAdpCtl: failed to get program path, rc=%Rrc.\n", rc));
        return rc;
    }
    strcat(szAdpCtl, "/" VBOXNETADPCTL_NAME);
    args[0] = szAdpCtl;
    if (!RTPathExists(szAdpCtl))
    {
        LogRel(("NetIfAdpCtl: path %s does not exist. Failed to run " VBOXNETADPCTL_NAME " helper.\n",
                szAdpCtl));
        return VERR_FILE_NOT_FOUND;
    }

    RTPROCESS pid;
    rc = RTProcCreate(szAdpCtl, args, RTENV_DEFAULT, 0, &pid);
    if (RT_SUCCESS(rc))
    {
        RTPROCSTATUS Status;
        rc = RTProcWait(pid, 0, &Status);
        if (   RT_SUCCESS(rc)
            && Status.iStatus == 0
            && Status.enmReason == RTPROCEXITREASON_NORMAL)
            return VINF_SUCCESS;
    }
    else
        LogRel(("NetIfAdpCtl: failed to create process for %s: %Rrc\n", szAdpCtl, rc));
    return rc;
}
Exemplo n.º 3
0
static void tstRTPipe5(void)
{
    RTTestISub("Inherit non-standard pipe handle, read end");

    char    szPathSelf[RTPATH_MAX];
    RTTESTI_CHECK_RETV(RTProcGetExecutablePath(szPathSelf, sizeof(szPathSelf)) == szPathSelf);

    RTPIPE  hPipeR;
    RTPIPE  hPipeW;
    RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_READ), VINF_SUCCESS);

    RTHCINTPTR hNative = RTPipeToNative(hPipeR);
    RTTESTI_CHECK_RETV(hNative != -1);

    char szNative[64];
    RTStrPrintf(szNative, sizeof(szNative), "%RHi", hNative);
    const char *papszArgs[4] = { szPathSelf, "--child-5", szNative, NULL };

    RTPROCESS hChild;
    RTTESTI_CHECK_RC_RETV(RTProcCreate(szPathSelf, papszArgs, RTENV_DEFAULT, 0 /*fFlags*/, &hChild), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTPipeClose(hPipeR), VINF_SUCCESS);

    RTTESTI_CHECK_RC(RTPipeWriteBlocking(hPipeW, g_szTest5Message, sizeof(g_szTest5Message) - 1, NULL), VINF_SUCCESS);
    int rc;
    RTTESTI_CHECK_RC(rc = RTPipeClose(hPipeW), VINF_SUCCESS);
    if (RT_FAILURE(rc))
        RTTESTI_CHECK_RC(RTProcTerminate(hChild), VINF_SUCCESS);

    RTPROCSTATUS ProcStatus;
    RTTESTI_CHECK_RC(rc = RTProcWait(hChild, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
    if (RT_FAILURE(rc))
        return;
    RTTESTI_CHECK(   ProcStatus.enmReason == RTPROCEXITREASON_NORMAL
                  && ProcStatus.iStatus   == 0);
}
RTDECL(int) RTSystemShutdown(RTMSINTERVAL cMsDelay, uint32_t fFlags, const char *pszLogMsg)
{
    AssertPtrReturn(pszLogMsg, VERR_INVALID_POINTER);
    AssertReturn(!(fFlags & ~RTSYSTEM_SHUTDOWN_VALID_MASK), VERR_INVALID_PARAMETER);

    /*
     * Assemble the argument vector.
     */
    int         iArg = 0;
    const char *apszArgs[6];

    RT_BZERO(apszArgs, sizeof(apszArgs));

    apszArgs[iArg++] = "/sbin/shutdown";
    switch (fFlags & RTSYSTEM_SHUTDOWN_ACTION_MASK)
    {
        case RTSYSTEM_SHUTDOWN_HALT:
            apszArgs[iArg++] = "-h";
            apszArgs[iArg++] = "-H";
            break;
        case RTSYSTEM_SHUTDOWN_REBOOT:
            apszArgs[iArg++] = "-r";
            break;
        case RTSYSTEM_SHUTDOWN_POWER_OFF:
        case RTSYSTEM_SHUTDOWN_POWER_OFF_HALT:
            apszArgs[iArg++] = "-h";
            apszArgs[iArg++] = "-P";
            break;
    }

    char szWhen[80];
    if (cMsDelay < 500)
        strcpy(szWhen, "now");
    else
        RTStrPrintf(szWhen, sizeof(szWhen), "%u", (unsigned)((cMsDelay + 499) / 1000));
    apszArgs[iArg++] = szWhen;

    apszArgs[iArg++] = pszLogMsg;


    /*
     * Start the shutdown process and wait for it to complete.
     */
    RTPROCESS hProc;
    int rc = RTProcCreate(apszArgs[0], apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, &hProc);
    if (RT_FAILURE(rc))
        return rc;

    RTPROCSTATUS ProcStatus;
    rc = RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus);
    if (RT_SUCCESS(rc))
    {
        if (   ProcStatus.enmReason != RTPROCEXITREASON_NORMAL
            || ProcStatus.iStatus   != 0)
            rc = VERR_SYS_SHUTDOWN_FAILED;
    }

    return rc;
}
Exemplo n.º 5
0
static int testServerListenAndCancel2(const char *pszExecPath)
{
    const char *apszArgs[4] = { pszExecPath, "child", "testServerListenAndCancel", NULL };
    RTPROCESS hProc;
    int rc = RTProcCreate(pszExecPath, apszArgs, RTENV_DEFAULT, 0 /* fFlags*/, &hProc);

    return rc;
}
Exemplo n.º 6
0
bool RTCALL VBoxOglIs3DAccelerationSupported(void)
{
    if (RTEnvExist("VBOX_CROGL_FORCE_SUPPORTED"))
    {
        LogRel(("VBOX_CROGL_FORCE_SUPPORTED is specified, skipping 3D test, and treating as supported\n"));
        return true;
    }

    static char pszVBoxPath[RTPATH_MAX];
    const char *papszArgs[4] = { NULL, "-test", "3D", NULL};
    int rc;
    RTPROCESS Process;
    RTPROCSTATUS ProcStatus;
    uint64_t StartTS;

    rc = RTPathExecDir(pszVBoxPath, RTPATH_MAX); AssertRCReturn(rc, false);
#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
    rc = RTPathAppend(pszVBoxPath, RTPATH_MAX, "VBoxTestOGL.exe");
#else
    rc = RTPathAppend(pszVBoxPath, RTPATH_MAX, "VBoxTestOGL");
#endif
    papszArgs[0] = pszVBoxPath;         /* argv[0] */
    AssertRCReturn(rc, false);

    rc = RTProcCreate(pszVBoxPath, papszArgs, RTENV_DEFAULT, 0, &Process);
    if (RT_FAILURE(rc))
        return false;

    StartTS = RTTimeMilliTS();

    while (1)
    {
        rc = RTProcWait(Process, RTPROCWAIT_FLAGS_NOBLOCK, &ProcStatus);
        if (rc != VERR_PROCESS_RUNNING)
            break;

#ifndef DEBUG_misha
        if (RTTimeMilliTS() - StartTS > 30*1000 /* 30 sec */)
        {
            RTProcTerminate(Process);
            RTThreadSleep(100);
            RTProcWait(Process, RTPROCWAIT_FLAGS_NOBLOCK, &ProcStatus);
            return false;
        }
#endif
        RTThreadSleep(100);
    }

    if (RT_SUCCESS(rc))
    {
        if ((ProcStatus.enmReason==RTPROCEXITREASON_NORMAL) && (ProcStatus.iStatus==0))
        {
            return true;
        }
    }

    return false;
}
Exemplo n.º 7
0
/**
 * The parent main routine.
 * @param   argv0       The executable name (or whatever).
 */
static int mainParent(const char *argv0)
{
    /*
     * Init.
     */
    RTTEST hTest;
    int rc = RTTestInitAndCreate("tstSupSem-Zombie", &hTest);
    if (rc)
        return rc;
    RTTestBanner(hTest);

    /*
     * Spin of the child process which may or may not turn into a zombie
     */
    for (uint32_t iPass = 0; iPass < 32; iPass++)
    {
        RTTestSubF(hTest, "Pass %u", iPass);

        RTPROCESS hProcess;
        const char *apszArgs[3] = { argv0, "--child", NULL };
        RTTESTI_CHECK_RC_OK(rc = RTProcCreate(argv0, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, &hProcess));
        if (RT_SUCCESS(rc))
        {
            /*
             * Wait for 60 seconds then give up.
             */
            RTPROCSTATUS    Status;
            uint64_t        StartTS = RTTimeMilliTS();
            for (;;)
            {
                rc = RTProcWait(hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &Status);
                if (RT_SUCCESS(rc))
                    break;
                uint64_t cElapsed = RTTimeMilliTS() - StartTS;
                if (cElapsed > 60*1000)
                    break;
                RTThreadSleep(cElapsed < 60 ? 30 : cElapsed < 200 ? 10 : 100);
            }
            RTTESTI_CHECK_RC_OK(rc);
            if (    RT_SUCCESS(rc)
                &&  (   Status.enmReason != RTPROCEXITREASON_NORMAL
                     || Status.iStatus != 0))
            {
                RTTestIFailed("child %d (%#x) reason %d\n", Status.iStatus, Status.iStatus, Status.enmReason);
                rc = VERR_PERMISSION_DENIED;
            }
        }
        /* one zombie process is enough. */
        if (RT_FAILURE(rc))
            break;
    }

    return RTTestSummaryAndDestroy(hTest);
}
Exemplo n.º 8
0
bool is3DAccelerationSupported()
{
    static char pszVBoxPath[RTPATH_MAX];
    const char *papszArgs[4] = { NULL, "-test", "3D", NULL};
    int rc;
    RTPROCESS Process;
    RTPROCSTATUS ProcStatus;
    uint64_t StartTS;

    rc = RTPathExecDir(pszVBoxPath, RTPATH_MAX);
    AssertRCReturn(rc, false);
#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
    rc = RTPathAppend(pszVBoxPath, RTPATH_MAX, "VBoxTestOGL.exe");
#else
    rc = RTPathAppend(pszVBoxPath, RTPATH_MAX, "VBoxTestOGL");
#endif
    papszArgs[0] = pszVBoxPath;         /* argv[0] */
    AssertRCReturn(rc, false);

    rc = RTProcCreate(pszVBoxPath, papszArgs, RTENV_DEFAULT, 0, &Process);
    if (RT_FAILURE(rc))
        return false;

    StartTS = RTTimeMilliTS();

    while (1)
    {
        rc = RTProcWait(Process, RTPROCWAIT_FLAGS_NOBLOCK, &ProcStatus);
        if (rc != VERR_PROCESS_RUNNING)
            break;

        if (RTTimeMilliTS() - StartTS > 30*1000 /* 30 sec */)
        {
            RTProcTerminate(Process);
            RTThreadSleep(100);
            RTProcWait(Process, RTPROCWAIT_FLAGS_NOBLOCK, &ProcStatus);
            return false;
        }
        RTThreadSleep(100);
    }

    if (RT_SUCCESS(rc))
    {
        if ((ProcStatus.enmReason==RTPROCEXITREASON_NORMAL) && (ProcStatus.iStatus==0))
        {
            return true;
        }
    }

    return false;
}
Exemplo n.º 9
0
static int testSessionWait(RTTEST hTest, const char *pszExecPath)
{
    RTTestSub(hTest, "testSessionWait");

    RTLOCALIPCSERVER ipcServer;
    int rc = RTLocalIpcServerCreate(&ipcServer, "tstRTLocalIpcSessionWait",
                                    RTLOCALIPC_FLAGS_MULTI_SESSION);
    if (RT_SUCCESS(rc))
    {
        LOCALIPCTHREADCTX threadCtx = { ipcServer, hTest };

        /* Spawn a simple worker thread and let it listen for incoming connections.
         * In the meanwhile we try to cancel the server and see what happens. */
        RTTHREAD hThread;
        rc = RTThreadCreate(&hThread, testSessionWaitThread,
                            &threadCtx, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc3");
        if (RT_SUCCESS(rc))
        {
            do
            {
                RTPROCESS hProc;
                const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionWaitFork", NULL };
                RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs,
                                      RTENV_DEFAULT, 0 /* fFlags*/, &hProc), VINF_SUCCESS);
                RTThreadSleep(5000); /* Let the server run for some time ... */
                RTTestPrintf(hTest, RTTESTLVL_INFO, "Cancelling server listening\n");
                RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerCancel(ipcServer), VINF_SUCCESS);
                /* Wait for the server thread to terminate. */
                int threadRc;
                RTTEST_CHECK_RC(hTest, RTThreadWait(hThread,
                                                    30 * 1000 /* 30s timeout */, &threadRc), VINF_SUCCESS);
                RTTEST_CHECK_RC_BREAK(hTest, threadRc, VERR_CANCELLED);
                RTTEST_CHECK_RC(hTest, RTLocalIpcServerDestroy(ipcServer), VINF_SUCCESS);
                RTTestPrintf(hTest, RTTESTLVL_INFO, "Server thread terminated successfully\n");
                /* Check if the child ran successfully. */
                RTPROCSTATUS stsChild;
                RTTEST_CHECK_RC_BREAK(hTest, RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &stsChild), VINF_SUCCESS);
                RTTestPrintf(hTest, RTTESTLVL_INFO, "Child terminated\n");
                RTTEST_CHECK_BREAK(hTest, stsChild.enmReason == RTPROCEXITREASON_NORMAL);
                RTTEST_CHECK_BREAK(hTest, stsChild.iStatus == 0);
            }
            while (0);
        }
        else
            RTTestFailed(hTest, "Unable to create thread for cancelling server, rc=%Rrc\n", rc);
    }
    else
        RTTestFailed(hTest, "Unable to create IPC server, rc=%Rrc\n", rc);

    return VINF_SUCCESS;
}
Exemplo n.º 10
0
static void tstRTPipe4(void)
{
    RTTestISub("Inherit non-standard pipe handle, write end");

    char    szPathSelf[RTPATH_MAX];
    RTTESTI_CHECK_RETV(RTProcGetExecutablePath(szPathSelf, sizeof(szPathSelf)) == szPathSelf);

    RTPIPE  hPipeR;
    RTPIPE  hPipeW;
    RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);

    RTHCINTPTR hNative = RTPipeToNative(hPipeW);
    RTTESTI_CHECK_RETV(hNative != -1);

    char szNative[64];
    RTStrPrintf(szNative, sizeof(szNative), "%RHi", hNative);
    const char *papszArgs[4] = { szPathSelf, "--child-4", szNative, NULL };

    RTPROCESS hChild;
    RTTESTI_CHECK_RC_RETV(RTProcCreate(szPathSelf, papszArgs, RTENV_DEFAULT, 0 /*fFlags*/, &hChild), VINF_SUCCESS);
    RTTESTI_CHECK_RC_RETV(RTPipeClose(hPipeW), VINF_SUCCESS);

    char    szTmp[1024];
    size_t  cbRead = 0;
    int     rc;
    RTTESTI_CHECK_RC(rc = RTPipeReadBlocking(hPipeR, szTmp, sizeof(szTmp) - 1, &cbRead), VINF_SUCCESS);
    if (RT_FAILURE(rc))
        cbRead = 0;
    RTTESTI_CHECK_RETV(cbRead < sizeof(szTmp));
    szTmp[cbRead] = '\0';

    size_t cbRead2;
    char szTmp2[4];
    RTTESTI_CHECK_RC(RTPipeReadBlocking(hPipeR, szTmp2, sizeof(szTmp2), &cbRead2), VERR_BROKEN_PIPE);
    RTTESTI_CHECK_RC(rc = RTPipeClose(hPipeR), VINF_SUCCESS);
    if (RT_FAILURE(rc))
        RTTESTI_CHECK_RC(RTProcTerminate(hChild), VINF_SUCCESS);

    RTPROCSTATUS ProcStatus;
    RTTESTI_CHECK_RC(rc = RTProcWait(hChild, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
    if (RT_FAILURE(rc))
        return;
    RTTESTI_CHECK(   ProcStatus.enmReason == RTPROCEXITREASON_NORMAL
                  && ProcStatus.iStatus   == 0);
    if (memcmp(szTmp, g_szTest4Message, sizeof(g_szTest4Message)))
        RTTestIFailed("Message mismatch.\n:Expected '%s'\nGot     '%s'\n", g_szTest4Message, szTmp);
}
int NetworkServiceRunner::start()
{
    if (isRunning())
        return VINF_ALREADY_INITIALIZED;

    const char * args[NETCFG_NOTOPT_MAXVAL * 2];

    /* get the path to the executable */
    char exePathBuf[RTPATH_MAX];
    const char *exePath = RTProcGetExecutablePath(exePathBuf, RTPATH_MAX);
    char *substrSl = strrchr(exePathBuf, '/');
    char *substrBs = strrchr(exePathBuf, '\\');
    char *suffix = substrSl ? substrSl : substrBs;

    if (suffix)
    {
        suffix++;
        strcpy(suffix, mProcName);
    }

    int index = 0;

    args[index++] = exePath;

    for (unsigned i = 0; i < NETCFG_NOTOPT_MAXVAL; i++)
    {
        if (mOptionEnabled[i])
        {
            const ARGDEF *pArgDef = getArgDef((NETCFG)i);
            if (!pArgDef)
                continue;
            args[index++] = pArgDef->Name;

            if (mOptions[i].length())
                args[index++] = mOptions[i].c_str();  // value
        }
    }

    args[index++] = NULL;

    int rc = RTProcCreate(suffix ? exePath : mProcName, args, RTENV_DEFAULT, 0, &mProcess);
    if (RT_FAILURE(rc))
        mProcess = NIL_RTPROCESS;

    return rc;
}
Exemplo n.º 12
0
int main(int argc, char **argv)
{
    /* the child response. */
    if (argc != 1)
        return 0;

    RTTEST hTest;
    RTEXITCODE rcExit = RTTestInitAndCreate("tstRTProcCreatePrf", &hTest);
    if (rcExit)
        return rcExit;
    RTTestBanner(hTest);

    char szExecPath[RTPATH_MAX];
    if (!RTProcGetExecutablePath(szExecPath, sizeof(szExecPath)))
        RTStrCopy(szExecPath, sizeof(szExecPath), argv[0]);

    const char *apszArgs[4] = { szExecPath, "child", "process", NULL };

    uint64_t NsStart = RTTimeNanoTS();
    uint32_t i;
#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) || defined(RT_OS_DARWIN)
    for (i = 0; i < 1000; i++)
#else
    for (i = 0; i < 10000; i++)
#endif
    {
        RTPROCESS hProc;
        RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(szExecPath, apszArgs, RTENV_DEFAULT, 0 /* fFlags*/, &hProc), VINF_SUCCESS);
        RTPROCSTATUS ChildStatus;
        RTTEST_CHECK_RC_BREAK(hTest, RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ChildStatus), VINF_SUCCESS);
        RTTEST_CHECK_BREAK(hTest, ChildStatus.enmReason == RTPROCEXITREASON_NORMAL);
        RTTEST_CHECK_BREAK(hTest, ChildStatus.iStatus == 0);
    }
    uint64_t cNsElapsed = RTTimeNanoTS() - NsStart;
    if (i)
    {
        RTTestValue(hTest, "Time per process", cNsElapsed / i, RTTESTUNIT_NS);
    }

    /*
     * Summary.
     */
    return RTTestSummaryAndDestroy(hTest);
}
Exemplo n.º 13
0
int NetworkServiceRunner::start(bool aKillProcOnStop)
{
    if (isRunning())
        return VINF_ALREADY_INITIALIZED;

    const char * args[10*2];

    AssertReturn(m->mOptions.size() < 10, VERR_INTERNAL_ERROR);

    /* get the path to the executable */
    char exePathBuf[RTPATH_MAX];
    const char *exePath = RTProcGetExecutablePath(exePathBuf, RTPATH_MAX);
    char *substrSl = strrchr(exePathBuf, '/');
    char *substrBs = strrchr(exePathBuf, '\\');
    char *suffix = substrSl ? substrSl : substrBs;

    if (suffix)
    {
        suffix++;
        strcpy(suffix, m->mProcName);
    }

    int index = 0;

    args[index++] = exePath;

    std::map<std::string, std::string>::const_iterator it;
    for(it = m->mOptions.begin(); it != m->mOptions.end(); ++it)
    {
        args[index++] = it->first.c_str();
        args[index++] = it->second.c_str();
    }

    args[index++] = NULL;

    int rc = RTProcCreate(suffix ? exePath : m->mProcName, args, RTENV_DEFAULT, 0, &m->mProcess);
    if (RT_FAILURE(rc))
        m->mProcess = NIL_RTPROCESS;

    m->mKillProcOnStop = aKillProcOnStop;
    return rc;
}
Exemplo n.º 14
0
static int testSessionConnection(RTTEST hTest, const char *pszExecPath)
{
    RTTestSub(hTest, "testSessionConnection");

    RTLOCALIPCSERVER ipcServer;
    int rc = RTLocalIpcServerCreate(&ipcServer, "tstRTLocalIpcSessionConnection",
                                    RTLOCALIPC_FLAGS_MULTI_SESSION);
    if (RT_SUCCESS(rc))
    {
#ifndef VBOX_TESTCASES_WITH_NO_THREADING
        LOCALIPCTHREADCTX threadCtx = { ipcServer, hTest };

        /* Spawn a simple worker thread and let it listen for incoming connections.
         * In the meanwhile we try to cancel the server and see what happens. */
        RTTHREAD hThread;
        rc = RTThreadCreate(&hThread, testSessionConnectionThread,
                            &threadCtx, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc2");
        if (RT_SUCCESS(rc))
        {
            do
            {
                RTPROCESS hProc;
                const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionConnectionFork", NULL };
                RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs,
                                      RTENV_DEFAULT, 0 /* fFlags*/, &hProc), VINF_SUCCESS);
                RTPROCSTATUS stsChild;
                RTTEST_CHECK_RC_BREAK(hTest, RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &stsChild), VINF_SUCCESS);
                RTTestPrintf(hTest, RTTESTLVL_INFO, "Child terminated, waiting for server thread ...\n");
                RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerCancel(ipcServer), VINF_SUCCESS);
                int threadRc;
                RTTEST_CHECK_RC(hTest, RTThreadWait(hThread,
                                                    30 * 1000 /* 30s timeout */, &threadRc), VINF_SUCCESS);
                RTTEST_CHECK_RC_BREAK(hTest, threadRc,  VERR_CANCELLED);
                RTTestPrintf(hTest, RTTESTLVL_INFO, "Server thread terminated successfully\n");
                RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerDestroy(ipcServer), VINF_SUCCESS);
                RTTEST_CHECK_BREAK(hTest, stsChild.enmReason == RTPROCEXITREASON_NORMAL);
                RTTEST_CHECK_BREAK(hTest, stsChild.iStatus == 0);
            }
            while (0);
        }
        else
            RTTestFailed(hTest, "Unable to create thread for cancelling server, rc=%Rrc\n", rc);
#else
        do
        {
            RTPROCESS hProc;
            const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionConnectionFork", NULL };
            RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs,
                                  RTENV_DEFAULT, 0 /* fFlags*/, &hProc), VINF_SUCCESS);
            RTLOCALIPCSESSION ipcSession;
            rc = RTLocalIpcServerListen(ipcServer, &ipcSession);
            if (RT_SUCCESS(rc))
            {
                RTTestPrintf(hTest, RTTESTLVL_INFO, "testSessionConnectionThread: Got new client connection\n");
            }
            else
                RTTestFailed(hTest, "Error while listening, rc=%Rrc\n", rc);

        } while (0);
#endif
    }
    else
        RTTestFailed(hTest, "Unable to create IPC server, rc=%Rrc\n", rc);

    return VINF_SUCCESS;
}
Exemplo n.º 15
0
/**
 * Worker that we can wrap with error variable saving and restoring.
 */
static bool rtAssertShouldPanicWorker(void)
{
    /*
     * Check for the VBOX_ASSERT variable.
     */
    const char *psz = RTEnvGet("VBOX_ASSERT");

    /* not defined => default behaviour. */
    if (!psz)
        return true;

    /* 'breakpoint' or 'panic' means default behaviour. */
    if (!strcmp(psz, "breakpoint") || !strcmp(psz, "panic"))
        return true;

#ifdef VBOX_RTASSERT_WITH_GDB
    /* 'gdb' - means try launch a gdb session in xterm. */
    if (!strcmp(psz, "gdb"))
    {
        /* Did we already fire up gdb? If so, just hit the breakpoint. */
        static bool volatile s_fAlreadyLaunchedGdb = false;
        if (ASMAtomicUoReadBool(&s_fAlreadyLaunchedGdb))
            return true;

        /* Try find a suitable terminal program. */
        const char *pszTerm = RTEnvGet("VBOX_ASSERT_TERM");
        if (    !pszTerm
            ||  !RTPathExists(pszTerm))
        {
            pszTerm = "/usr/bin/gnome-terminal";
            if (!RTPathExists(pszTerm))
            {
                pszTerm = "/usr/X11R6/bin/xterm";
                if (!RTPathExists(pszTerm))
                {
                    pszTerm ="/usr/bin/xterm";
                    if (!RTPathExists(pszTerm))
                        return true;
                }
            }
        }

        /* And find gdb. */
        const char *pszGdb = RTEnvGet("VBOX_ASSERT_GDB");
        if (    !pszGdb
            ||  !RTPathExists(pszGdb))
        {
            pszGdb = "/usr/bin/gdb";
            if (!RTPathExists(pszGdb))
                pszGdb = "gdb";
        }

        /* Try spawn the process. */
        char    szCmd[512];
        size_t  cch = RTStrPrintf(szCmd, sizeof(szCmd), "%s -p %d ", pszGdb, RTProcSelf());
        if (cch < sizeof(szCmd))
        {
            char *pszExecName = &szCmd[cch];
            if (!RTProcGetExecutablePath(pszExecName, sizeof(szCmd) - cch))
                *pszExecName = '\0';
        }
        const char *apszArgs[] =
        {
            pszTerm,
            "-e",
            szCmd,
            NULL
        };
        RTPROCESS Process;
        int rc = RTProcCreate(apszArgs[0], &apszArgs[0], RTENV_DEFAULT, 0, &Process);
        if (RT_FAILURE(rc))
            return false;

        ASMAtomicWriteBool(&s_fAlreadyLaunchedGdb, true);

        /* Wait for gdb to attach. */
        RTThreadSleep(15000);
        return true;
    }
#endif

    /* '*' - don't hit the breakpoint. */
    return false;
}
Exemplo n.º 16
0
/**
 * Process the testcases found in the filter.
 *
 * @param   pszFilter   The filter (winnt) to pass to RTDirOpenFiltered for
 *                      selecting the testcases.
 * @param   pszDir      The directory we're processing.
 */
static void Process(const char *pszFilter, const char *pszDir)
{
    /*
     * Open and enumerate the directory.
     */
    PRTDIR pDir;
    int rc = RTDirOpenFiltered(&pDir, pszFilter, RTDIRFILTER_WINNT, 0);
    if (RT_SUCCESS(rc))
    {
        for (;;)
        {
            RTDIRENTRY DirEntry;
            rc = RTDirRead(pDir, &DirEntry, NULL);
            if (RT_FAILURE(rc))
            {
                if (rc == VERR_NO_MORE_FILES)
                    rc = VINF_SUCCESS;
                else
                    RTPrintf("tstRunTestcases: reading '%s' -> %Rrc\n", pszFilter, rc);
                break;
            }

            /*
             * Construct the testcase name.
             */
            char *pszTestcase;
            RTStrAPrintf(&pszTestcase, "%s/%s", pszDir, DirEntry.szName);
            if (!pszTestcase)
            {
                RTPrintf("tstRunTestcases: out of memory!\n");
                rc = VERR_NO_MEMORY;
                break;
            }
            if (IsTestcaseIncluded(pszTestcase))
            {
                /*
                 * Execute the testcase.
                 */
                RTPrintf("*** %s: Executing...\n", pszTestcase);  RTStrmFlush(g_pStdOut);
                const char *papszArgs[2];
                papszArgs[0] = pszTestcase;
                papszArgs[1] = NULL;
                RTPROCESS Process;
                rc = RTProcCreate(pszTestcase, papszArgs, RTENV_DEFAULT, 0, &Process);
                if (RT_SUCCESS(rc))
                {
                    /*
                     * Wait for the process and collect it's return code.
                     * If it takes too long, we'll terminate it and continue.
                     */
                    RTTIMESPEC Start;
                    RTTimeNow(&Start);
                    RTPROCSTATUS ProcStatus;
                    for (;;)
                    {
                        rc = RTProcWait(Process, RTPROCWAIT_FLAGS_NOBLOCK, &ProcStatus);
                        if (rc != VERR_PROCESS_RUNNING)
                            break;
                        RTTIMESPEC Now;
                        if (RTTimeSpecGetMilli(RTTimeSpecSub(RTTimeNow(&Now), &Start)) > 120*1000 /* 1 min */)
                        {
                            RTPrintf("*** %s: FAILED - timed out. killing it.\n", pszTestcase);
                            RTProcTerminate(Process);
                            RTThreadSleep(100);
                            RTProcWait(Process, RTPROCWAIT_FLAGS_NOBLOCK, &ProcStatus);
                            g_cFailures++;
                            break;
                        }
                        RTThreadSleep(100);
                    }

                    /*
                     * Examin the exit status.
                     */
                    if (RT_SUCCESS(rc))
                    {
                        if (    ProcStatus.enmReason == RTPROCEXITREASON_NORMAL
                            &&  ProcStatus.iStatus == 0)
                        {
                            RTPrintf("*** %s: PASSED\n", pszTestcase);
                            g_cPasses++;
                        }
                        else
                        {
                            RTPrintf("*** %s: FAILED\n", pszTestcase);
                            g_cFailures++;
                        }
                    }
                    else if (rc != VERR_PROCESS_RUNNING)
                    {
                        RTPrintf("tstRunTestcases: %s: RTProcWait failed -> %Rrc\n", pszTestcase, rc);
                        g_cFailures++;
                    }
                }
                else
                {
                    RTPrintf("tstRunTestcases: %s: failed to start -> %Rrc\n", pszTestcase, rc);
                    g_cFailures++;
                }

            }
            else
            {
                RTPrintf("tstRunTestcases: %s: SKIPPED\n", pszTestcase);
                g_cSkipped++;
            }
            RTStrFree(pszTestcase);
        } /* enumeration loop */

        RTDirClose(pDir);
    }
    else
        RTPrintf("tstRunTestcases: opening '%s' -> %Rrc\n", pszDir, rc);
}
Exemplo n.º 17
0
void measurePerformance(pm::CollectorHAL *collector, const char *pszName, int cVMs)
{

    static const char * const args[] = { pszName, "-child", NULL };
    pm::CollectorHints hints;
    std::vector<RTPROCESS> processes;

    hints.collectHostCpuLoad();
    hints.collectHostRamUsage();
    /* Start fake VMs */
    for (int i = 0; i < cVMs; ++i)
    {
        RTPROCESS pid;
        int rc = RTProcCreate(pszName, args, RTENV_DEFAULT, 0, &pid);
        if (RT_FAILURE(rc))
        {
            hints.getProcesses(processes);
            std::for_each(processes.begin(), processes.end(), std::ptr_fun(RTProcTerminate));
            RTPrintf("tstCollector: RTProcCreate() -> %Rrc\n", rc);
            return;
        }
        hints.collectProcessCpuLoad(pid);
        hints.collectProcessRamUsage(pid);
    }

    hints.getProcesses(processes);
    RTThreadSleep(30000); // Let children settle for half a minute

    int rc;
    ULONG tmp;
    uint64_t tmp64;
    uint64_t start;
    unsigned int nCalls;
    /* Pre-collect */
    CALLS_PER_SECOND(preCollect(hints, 0));
    /* Host CPU load */
    CALLS_PER_SECOND(getRawHostCpuLoad(&tmp64, &tmp64, &tmp64));
    /* Process CPU load */
    CALLS_PER_SECOND(getRawProcessCpuLoad(processes[nCalls%cVMs], &tmp64, &tmp64, &tmp64));
    /* Host CPU speed */
    CALLS_PER_SECOND(getHostCpuMHz(&tmp));
    /* Host RAM usage */
    CALLS_PER_SECOND(getHostMemoryUsage(&tmp, &tmp, &tmp));
    /* Process RAM usage */
    CALLS_PER_SECOND(getProcessMemoryUsage(processes[nCalls%cVMs], &tmp));

    start = RTTimeNanoTS();

    int times;
    for (times = 0; times < 100; times++)
    {
        /* Pre-collect */
        N_CALLS(1, preCollect(hints, 0));
        /* Host CPU load */
        N_CALLS(1, getRawHostCpuLoad(&tmp64, &tmp64, &tmp64));
        /* Host CPU speed */
        N_CALLS(1, getHostCpuMHz(&tmp));
        /* Host RAM usage */
        N_CALLS(1, getHostMemoryUsage(&tmp, &tmp, &tmp));
        /* Process CPU load */
        N_CALLS(cVMs, getRawProcessCpuLoad(processes[call], &tmp64, &tmp64, &tmp64));
        /* Process RAM usage */
        N_CALLS(cVMs, getProcessMemoryUsage(processes[call], &tmp));
    }
    printf("\n%u VMs -- %.2f%% of CPU time\n", cVMs, (RTTimeNanoTS() - start) / 10000000. / times);

    /* Shut down fake VMs */
    std::for_each(processes.begin(), processes.end(), std::ptr_fun(RTProcTerminate));
}
Exemplo n.º 18
0
static int testSessionData(RTTEST hTest, const char *pszExecPath)
{
    RTTestSub(hTest, "testSessionData");

    RTLOCALIPCSERVER ipcServer;
    int rc = RTLocalIpcServerCreate(&ipcServer, "tstRTLocalIpcSessionData",
                                    RTLOCALIPC_FLAGS_MULTI_SESSION);
    if (RT_SUCCESS(rc))
    {
        LOCALIPCTHREADCTX threadCtx = { ipcServer, hTest };
#if 0
        /* Run server + client in threads instead of fork'ed processes (useful for debugging). */
        RTTHREAD hThreadServer, hThreadClient;
        rc = RTThreadCreate(&hThreadServer, testSessionDataThread,
                            &threadCtx, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc4");
        if (RT_SUCCESS(rc))
            rc = RTThreadCreate(&hThreadClient, testSessionDataChildAsThread,
                                &hTest, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc5");
        if (RT_SUCCESS(rc))
        {
            do
            {
                int threadRc;
                RTTEST_CHECK_RC(hTest, RTThreadWait(hThreadServer,
                                                    5 * 60 * 1000 /* 5 minutes timeout */, &threadRc), VINF_SUCCESS);
                RTTEST_CHECK_RC_BREAK(hTest, threadRc, VINF_SUCCESS);
                RTTEST_CHECK_RC(hTest, RTThreadWait(hThreadClient,
                                                    5 * 60 * 1000 /* 5 minutes timeout */, &threadRc), VINF_SUCCESS);
                RTTEST_CHECK_RC_BREAK(hTest, threadRc, VINF_SUCCESS);

            } while (0);
        }
#else
        /* Spawn a simple worker thread and let it listen for incoming connections.
         * In the meanwhile we try to cancel the server and see what happens. */
        RTTHREAD hThread;
        rc = RTThreadCreate(&hThread, testSessionDataThread,
                            &threadCtx, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc4");
        if (RT_SUCCESS(rc))
        {
            do
            {
                RTPROCESS hProc;
                const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionDataFork", NULL };
                RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs,
                                      RTENV_DEFAULT, 0 /* fFlags*/, &hProc), VINF_SUCCESS);
                /* Wait for the server thread to terminate. */
                int threadRc;
                RTTEST_CHECK_RC(hTest, RTThreadWait(hThread,
                                                    5 * 60 * 1000 /* 5 minutes timeout */, &threadRc), VINF_SUCCESS);
                RTTEST_CHECK_RC_BREAK(hTest, threadRc, VINF_SUCCESS);
                RTTEST_CHECK_RC(hTest, RTLocalIpcServerDestroy(ipcServer), VINF_SUCCESS);
                RTTestPrintf(hTest, RTTESTLVL_INFO, "Server thread terminated successfully\n");
                /* Check if the child ran successfully. */
                RTPROCSTATUS stsChild;
                RTTEST_CHECK_RC_BREAK(hTest, RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &stsChild), VINF_SUCCESS);
                RTTestPrintf(hTest, RTTESTLVL_INFO, "Child terminated\n");
                RTTEST_CHECK_BREAK(hTest, stsChild.enmReason == RTPROCEXITREASON_NORMAL);
                RTTEST_CHECK_BREAK(hTest, stsChild.iStatus == 0);
            }
            while (0);
        }
        else
            RTTestFailed(hTest, "Unable to create thread for cancelling server, rc=%Rrc\n", rc);
#endif
    }
    else
        RTTestFailed(hTest, "Unable to create IPC server, rc=%Rrc\n", rc);

    return !RTTestErrorCount(hTest) ? VINF_SUCCESS : VERR_GENERAL_FAILURE /* Doesn't matter */;
}
Exemplo n.º 19
0
int main(int argc, char **argv)
{
    /*
     * Init IPRT.
     */
    int rc = RTR3InitExe(argc, &argv, 0);
    if (RT_FAILURE(rc))
        return RTMsgInitFailure(rc);

    /*
     * Locate a native DTrace command binary.
     */
    bool fIsNativeDTrace = false;
    char szDTraceCmd[RTPATH_MAX];
    szDTraceCmd[0] = '\0';

#if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
    /*
     * 1. Try native first on platforms where it's applicable.
     */
    static const char * const s_apszNativeDTrace[] =
    {
        "/usr/sbin/dtrace",
        "/sbin/dtrace",
        "/usr/bin/dtrace",
        "/bin/dtrace",
        "/usr/local/sbin/dtrace",
        "/usr/local/bin/dtrace"
    };
    if (!RTEnvExist("VBOX_DTRACE_NO_NATIVE"))
        for (uint32_t i = 0; i < RT_ELEMENTS(s_apszNativeDTrace); i++)
            if (RTFileExists(s_apszNativeDTrace[i]))
            {
                fIsNativeDTrace = true;
                strcpy(szDTraceCmd, s_apszNativeDTrace[i]);
# ifdef RT_OS_LINUX
                /** @todo Warn if the dtrace modules haven't been loaded or vboxdrv isn't
                 *        compiled against them. */
# endif
                break;
            }
    if (szDTraceCmd[0] == '\0')
#endif
    {
        /*
         * 2. VBoxDTrace extension pack installed?
         *
         * Note! We cannot use the COM API here because this program is usually
         *       run thru sudo or directly as root, even if the target
         *       VirtualBox process is running as regular user.  This is due to
         *       the privileges required to run dtrace scripts on a host.
         */
        rc = RTPathAppPrivateArch(szDTraceCmd, sizeof(szDTraceCmd));
        if (RT_SUCCESS(rc))
            rc = RTPathAppend(szDTraceCmd, sizeof(szDTraceCmd),
                              VBOX_EXTPACK_INSTALL_DIR RTPATH_SLASH_STR VBOX_EXTPACK_VBOXDTRACE_MANGLED_NAME);
        if (RT_SUCCESS(rc))
            rc = RTPathAppend(szDTraceCmd, sizeof(szDTraceCmd), RTBldCfgTargetDotArch());
        if (RT_SUCCESS(rc))
            rc = RTPathAppend(szDTraceCmd, sizeof(szDTraceCmd), "VBoxDTraceCmd");
        if (RT_SUCCESS(rc))
            rc = RTStrCat(szDTraceCmd, sizeof(szDTraceCmd), RTLdrGetSuff());
        if (RT_FAILURE(rc))
            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing extension pack path: %Rrc", rc);
        if (!RTFileExists(szDTraceCmd))
            return RTMsgErrorExit(RTEXITCODE_FAILURE,
                                  "Unable to find a DTrace implementation. VBoxDTrace Extension Pack installed?");
        fIsNativeDTrace = false;
    }


    /*
     * Construct a new command line that includes our libary.
     */
    char szDTraceLibDir[RTPATH_MAX];
    rc = RTPathAppPrivateNoArch(szDTraceLibDir, sizeof(szDTraceLibDir));
    if (RT_SUCCESS(rc))
        rc = RTPathAppend(szDTraceLibDir, sizeof(szDTraceLibDir), "dtrace" RTPATH_SLASH_STR "lib");
    if (RT_SUCCESS(rc))
        rc = RTPathAppend(szDTraceLibDir, sizeof(szDTraceLibDir), RTBldCfgTargetArch());
    if (RT_FAILURE(rc))
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error constructing dtrace library path for VBox: %Rrc", rc);

    char **papszArgs = (char **)RTMemAlloc((argc + 3) * sizeof(char *));
    if (!papszArgs)
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "No memory for argument list.");

    int cArgs    = 1;
    papszArgs[0] = fIsNativeDTrace ? szDTraceCmd : argv[0];
    if (argc > 1)
    {
        papszArgs[cArgs++] = (char *)"-L";
        papszArgs[cArgs++] = szDTraceLibDir;
    }
    for (int i = 1; i < argc; i++)
        papszArgs[cArgs++] = argv[i];
    papszArgs[cArgs] = NULL;
    Assert(cArgs <= argc + 3);


    /*
     * The native DTrace we execute as a sub-process and wait for.
     */
    RTEXITCODE rcExit;
    if (fIsNativeDTrace)
    {
        RTPROCESS hProc;
        rc = RTProcCreate(szDTraceCmd, papszArgs, RTENV_DEFAULT, 0, &hProc);
        if (RT_SUCCESS(rc))
        {
            RTPROCSTATUS Status;
            rc = RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &Status);
            if (RT_SUCCESS(rc))
            {
                if (Status.enmReason == RTPROCEXITREASON_NORMAL)
                    rcExit = (RTEXITCODE)Status.iStatus;
                else
                    rcExit = RTEXITCODE_FAILURE;
            }
            else
                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error waiting for child process: %Rrc", rc);
        }
        else
            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error executing '%s': %Rrc", szDTraceCmd, rc);
    }
    /*
     * While the VBoxDTrace we load and call the main function of.
     */
    else
    {
        RTERRINFOSTATIC ErrInfo;
        RTLDRMOD hMod;
        rc = SUPR3HardenedLdrLoadPlugIn(szDTraceCmd, &hMod, RTErrInfoInitStatic(&ErrInfo));
        if (RT_SUCCESS(rc))
        {
            PFNVBOXDTRACEMAIN pfnVBoxDTraceMain;
            rc = RTLdrGetSymbol(hMod, "VBoxDTraceMain", (void **)&pfnVBoxDTraceMain);
            if (RT_SUCCESS(rc))
                rcExit = (RTEXITCODE)pfnVBoxDTraceMain(cArgs, papszArgs);
            else
                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error locating 'VBoxDTraceMain' in '%s': %Rrc", szDTraceCmd, rc);
        }
        else
            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error loading '%s': %Rrc (%s)", szDTraceCmd, rc, ErrInfo.szMsg);
    }
    return rcExit;
}
Exemplo n.º 20
0
int main(int argc, char **argv)
{
    bool fSys = true;
    bool fGip = false;
#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
    fGip = true;
#endif

    /*
     * Init.
     */
    int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
    if (RT_FAILURE(rc))
        return RTMsgInitFailure(rc);

    if (argc == 2 && !strcmp(argv[1], "child"))
    {
        RTThreadSleep(300);
        return 0;
    }

    RTTEST hTest;
    rc = RTTestCreate("tstSupSem", &hTest);
    if (RT_FAILURE(rc))
    {
        RTPrintf("tstSupSem: fatal error: RTTestCreate failed with rc=%Rrc\n", rc);
        return 1;
    }
    g_hTest = hTest;

    PSUPDRVSESSION pSession;
    rc = SUPR3Init(&pSession);
    if (RT_FAILURE(rc))
    {
        RTTestFailed(hTest, "SUPR3Init failed with rc=%Rrc\n", rc);
        return RTTestSummaryAndDestroy(hTest);
    }
    g_pSession = pSession;
    RTTestBanner(hTest);

    /*
     * Basic API checks.
     */
    RTTestSub(hTest, "Single Release Event (SRE) API");
    SUPSEMEVENT hEvent = NIL_SUPSEMEVENT;
    RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent),          VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 0),  VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 1),  VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 2),  VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 8),  VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent,20),  VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent),           VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 0),  VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent),           VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 1),  VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent),           VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 2),  VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent),           VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 8),  VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent),           VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 20), VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent),           VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent,1000),VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent),           VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent),           VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 0),  VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 0),  VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 1),  VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 2),  VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 8),  VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent,20),  VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent),            VINF_OBJECT_DESTROYED);
    RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent),            VERR_INVALID_HANDLE);
    RTTESTI_CHECK_RC(SUPSemEventClose(pSession, NIL_SUPSEMEVENT),   VINF_SUCCESS);

    RTTestSub(hTest, "Multiple Release Event (MRE) API");
    SUPSEMEVENTMULTI hEventMulti = NIL_SUPSEMEVENT;
    RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEventMulti),            VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0),    VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 1),    VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 2),    VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 8),    VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti,20),    VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventMultiSignal(pSession, hEventMulti),             VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0),    VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0),    VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0),    VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 1),    VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 2),    VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 8),    VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti,20),    VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti,1000),  VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiSignal(pSession, hEventMulti),             VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiSignal(pSession, hEventMulti),             VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0),    VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiReset(pSession, hEventMulti),              VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0),    VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 1),    VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 2),    VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 8),    VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti,20),    VERR_TIMEOUT);
    RTTESTI_CHECK_RC(SUPSemEventMultiSignal(pSession, hEventMulti),             VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0),    VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 1),    VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 2),    VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 8),    VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 20),   VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti,1000),  VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEventMulti),              VINF_OBJECT_DESTROYED);
    RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEventMulti),              VERR_INVALID_HANDLE);
    RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, NIL_SUPSEMEVENTMULTI),     VINF_SUCCESS);

#if !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS)
    RTTestSub(hTest, "SRE Interruptibility");
    RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS);
    g_cMillies = RT_INDEFINITE_WAIT;
    RTTHREAD hThread = NIL_RTTHREAD;
    RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleSRE, (void *)hEvent, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntSRE"), VINF_SUCCESS);
    RTTESTI_CHECK_RC(RTThreadUserWait(hThread, 60*1000), VINF_SUCCESS);
    RTThreadSleep(120);
    RTThreadPoke(hThread);
    int rcThread = VINF_SUCCESS;
    RTTESTI_CHECK_RC(RTThreadWait(hThread, 60*1000, &rcThread), VINF_SUCCESS);
    RTTESTI_CHECK_RC(rcThread, VERR_INTERRUPTED);
    RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED);

    RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS);
    g_cMillies = 120*1000;
    hThread = NIL_RTTHREAD;
    RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleSRE, (void *)hEvent, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntSRE"), VINF_SUCCESS);
    RTTESTI_CHECK_RC(RTThreadUserWait(hThread, 60*1000), VINF_SUCCESS);
    RTThreadSleep(120);
    RTThreadPoke(hThread);
    rcThread = VINF_SUCCESS;
    RTTESTI_CHECK_RC(RTThreadWait(hThread, 60*1000, &rcThread), VINF_SUCCESS);
    RTTESTI_CHECK_RC(rcThread, VERR_INTERRUPTED);
    RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED);


    RTTestSub(hTest, "MRE Interruptibility");
    RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEventMulti), VINF_SUCCESS);
    g_cMillies = RT_INDEFINITE_WAIT;
    hThread = NIL_RTTHREAD;
    RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleMRE, (void *)hEventMulti, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntMRE"), VINF_SUCCESS);
    RTTESTI_CHECK_RC(RTThreadUserWait(hThread, 60*1000), VINF_SUCCESS);
    RTThreadSleep(120);
    RTThreadPoke(hThread);
    rcThread = VINF_SUCCESS;
    RTTESTI_CHECK_RC(RTThreadWait(hThread, 60*1000, &rcThread), VINF_SUCCESS);
    RTTESTI_CHECK_RC(rcThread, VERR_INTERRUPTED);
    RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEventMulti), VINF_OBJECT_DESTROYED);

    RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEventMulti), VINF_SUCCESS);
    g_cMillies = 120*1000;
    hThread = NIL_RTTHREAD;
    RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleMRE, (void *)hEventMulti, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntMRE"), VINF_SUCCESS);
    RTTESTI_CHECK_RC(RTThreadUserWait(hThread, 60*1000), VINF_SUCCESS);
    RTThreadSleep(120);
    RTThreadPoke(hThread);
    rcThread = VINF_SUCCESS;
    RTTESTI_CHECK_RC(RTThreadWait(hThread, 60*1000, &rcThread), VINF_SUCCESS);
    RTTESTI_CHECK_RC(rcThread, VERR_INTERRUPTED);
    RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEventMulti), VINF_OBJECT_DESTROYED);

    /*
     * Fork test.
     * Spawn a thread waiting for an event, then spawn a new child process (of
     * ourselves) and make sure that this does not alter the intended behaviour
     * of our event semaphore implementation (see @bugref{5090}).
     */
    RTTestSub(hTest, "SRE Process Spawn");
    hThread = NIL_RTTHREAD;
    g_cMillies = 120*1000;
    RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS);
    RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleSRE, (void *)hEvent, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntSRE"), VINF_SUCCESS);

    const char *apszArgs[3] = { argv[0], "child", NULL };
    RTPROCESS Process = NIL_RTPROCESS;
    RTThreadSleep(250);
    RTTESTI_CHECK_RC(RTProcCreate(apszArgs[0], apszArgs, RTENV_DEFAULT, 0, &Process), VINF_SUCCESS);

    RTThreadSleep(250);
    RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS);

    rcThread = VERR_GENERAL_FAILURE;
    RTTESTI_CHECK_RC(RTThreadWait(hThread, 120*1000, &rcThread), VINF_SUCCESS);
    RTTESTI_CHECK_RC(rcThread, VINF_SUCCESS);
    RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED);


    RTTestSub(hTest, "MRE Process Spawn");
    hThread = NIL_RTTHREAD;
    g_cMillies = 120*1000;
    RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEvent), VINF_SUCCESS);
    RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleMRE, (void *)hEvent, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntSRE"), VINF_SUCCESS);

    RTTHREAD hThread2 = NIL_RTTHREAD;
    RTTESTI_CHECK_RC(RTThreadCreate(&hThread2, tstSupSemInterruptibleMRE, (void *)hEvent, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntSRE"), VINF_SUCCESS);

    Process = NIL_RTPROCESS;
    RTThreadSleep(250);
    RTTESTI_CHECK_RC(RTProcCreate(apszArgs[0], apszArgs, RTENV_DEFAULT, 0, &Process), VINF_SUCCESS);

    RTThreadSleep(250);
    RTTESTI_CHECK_RC(SUPSemEventMultiSignal(pSession, hEvent), VINF_SUCCESS);

    rcThread = VERR_GENERAL_FAILURE;
    RTTESTI_CHECK_RC(RTThreadWait(hThread, 120*1000, &rcThread), VINF_SUCCESS);
    RTTESTI_CHECK_RC(rcThread, VINF_SUCCESS);

    int rcThread2 = VERR_GENERAL_FAILURE;
    RTTESTI_CHECK_RC(RTThreadWait(hThread2, 120*1000, &rcThread2), VINF_SUCCESS);
    RTTESTI_CHECK_RC(rcThread2, VINF_SUCCESS);

    RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEvent), VINF_OBJECT_DESTROYED);

#endif /* !OS2 && !WINDOWS */

    {

#define LOOP_COUNT 20
        static unsigned const s_acMsIntervals[] = { 0, 1, 2, 3, 4, 8, 10, 16, 32 };
        if (RTTestErrorCount(hTest) == 0)
        {
            RTTestSub(hTest, "SRE Timeout Accuracy (ms)");
            RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS);

            uint32_t cInterrupted = 0;
            for (unsigned i = 0; i < RT_ELEMENTS(s_acMsIntervals); i++)
            {
                uint64_t cMs        = s_acMsIntervals[i];
                uint64_t cNsMinSys  = UINT64_MAX;
                uint64_t cNsMin     = UINT64_MAX;
                uint64_t cNsTotalSys= 0;
                uint64_t cNsTotal   = 0;
                unsigned cLoops     = 0;
                while (cLoops < LOOP_COUNT)
                {
                    uint64_t u64StartSys = RTTimeSystemNanoTS();
                    uint64_t u64Start    = RTTimeNanoTS();
                    int rcX = SUPSemEventWaitNoResume(pSession, hEvent, cMs);
                    uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys;
                    uint64_t cNsElapsed    = RTTimeNanoTS()       - u64Start;

                    if (rcX == VERR_INTERRUPTED)
                    {
                        cInterrupted++;
                        continue; /* retry */
                    }
                    if (rcX != VERR_TIMEOUT)
                        RTTestFailed(hTest, "%Rrc cLoops=%u cMs=%u", rcX, cLoops, cMs);

                    if (cNsElapsedSys < cNsMinSys)
                        cNsMinSys = cNsElapsedSys;
                    if (cNsElapsed < cNsMin)
                        cNsMin = cNsElapsed;
                    cNsTotalSys += cNsElapsedSys;
                    cNsTotal    += cNsElapsed;
                    cLoops++;
                }
                if (fSys)
                {
                    RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS,            "%u ms min (clock=sys)", cMs);
                    RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%u ms avg (clock=sys)", cMs);
                }
                if (fGip)
                {
                    RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS,               "%u ms min (clock=gip)", cMs);
                    RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS,    "%u ms avg (clock=gip)", cMs);
                }
            }

            RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED);
            RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned");
        }

        if (RTTestErrorCount(hTest) == 0)
        {
            RTTestSub(hTest, "MRE Timeout Accuracy (ms)");
            RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEvent), VINF_SUCCESS);

            uint32_t cInterrupted = 0;
            for (unsigned i = 0; i < RT_ELEMENTS(s_acMsIntervals); i++)
            {
                uint64_t cMs        = s_acMsIntervals[i];
                uint64_t cNsMinSys  = UINT64_MAX;
                uint64_t cNsMin     = UINT64_MAX;
                uint64_t cNsTotalSys= 0;
                uint64_t cNsTotal   = 0;
                unsigned cLoops     = 0;
                while (cLoops < LOOP_COUNT)
                {
                    uint64_t u64StartSys = RTTimeSystemNanoTS();
                    uint64_t u64Start    = RTTimeNanoTS();
                    int rcX = SUPSemEventMultiWaitNoResume(pSession, hEvent, cMs);
                    uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys;
                    uint64_t cNsElapsed    = RTTimeNanoTS()       - u64Start;

                    if (rcX == VERR_INTERRUPTED)
                    {
                        cInterrupted++;
                        continue; /* retry */
                    }
                    if (rcX != VERR_TIMEOUT)
                        RTTestFailed(hTest, "%Rrc cLoops=%u cMs=%u", rcX, cLoops, cMs);

                    if (cNsElapsedSys < cNsMinSys)
                        cNsMinSys = cNsElapsedSys;
                    if (cNsElapsed < cNsMin)
                        cNsMin = cNsElapsed;
                    cNsTotalSys += cNsElapsedSys;
                    cNsTotal    += cNsElapsed;
                    cLoops++;
                }
                if (fSys)
                {
                    RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS,            "%u ms min (clock=sys)", cMs);
                    RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%u ms avg (clock=sys)", cMs);
                }
                if (fGip)
                {
                    RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS,               "%u ms min (clock=gip)", cMs);
                    RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS,    "%u ms avg (clock=gip)", cMs);
                }
            }

            RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEvent), VINF_OBJECT_DESTROYED);
            RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned");
        }
    }

    {
        static uint32_t const s_acNsIntervals[] =
        {
            0, 1000, 5000, 15000, 30000, 50000, 100000, 250000, 500000, 750000, 900000, 1500000, 2200000
        };

        if (RTTestErrorCount(hTest) == 0)
        {
            RTTestSub(hTest, "SUPSemEventWaitNsRelIntr Accuracy");
            RTTestValueF(hTest, SUPSemEventGetResolution(pSession), RTTESTUNIT_NS, "SRE resolution");
            RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS);

            uint32_t cInterrupted = 0;
            for (unsigned i = 0; i < RT_ELEMENTS(s_acNsIntervals); i++)
            {
                uint64_t cNs        = s_acNsIntervals[i];
                uint64_t cNsMinSys  = UINT64_MAX;
                uint64_t cNsMin     = UINT64_MAX;
                uint64_t cNsTotalSys= 0;
                uint64_t cNsTotal   = 0;
                unsigned cLoops     = 0;
                while (cLoops < LOOP_COUNT)
                {
                    uint64_t u64StartSys = RTTimeSystemNanoTS();
                    uint64_t u64Start    = RTTimeNanoTS();
                    int rcX = SUPSemEventWaitNsRelIntr(pSession, hEvent, cNs);
                    uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys;
                    uint64_t cNsElapsed    = RTTimeNanoTS()       - u64Start;

                    if (rcX == VERR_INTERRUPTED)
                    {
                        cInterrupted++;
                        continue; /* retry */
                    }
                    if (rcX != VERR_TIMEOUT)
                        RTTestFailed(hTest, "%Rrc cLoops=%u cNs=%u", rcX, cLoops, cNs);

                    if (cNsElapsedSys < cNsMinSys)
                        cNsMinSys = cNsElapsedSys;
                    if (cNsElapsed < cNsMin)
                        cNsMin = cNsElapsed;
                    cNsTotalSys += cNsElapsedSys;
                    cNsTotal    += cNsElapsed;
                    cLoops++;
                }
                if (fSys)
                {
                    RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS,            "%'u ns min (clock=sys)", cNs);
                    RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=sys)", cNs);
                }
                if (fGip)
                {
                    RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS,               "%'u ns min (clock=gip)", cNs);
                    RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS,    "%'u ns avg (clock=gip)", cNs);
                }
            }

            RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED);
            RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned");
        }

        if (RTTestErrorCount(hTest) == 0)
        {
            RTTestSub(hTest, "SUPSemEventMultiWaitNsRelIntr Accuracy");
            RTTestValueF(hTest, SUPSemEventMultiGetResolution(pSession), RTTESTUNIT_NS, "MRE resolution");
            RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEvent), VINF_SUCCESS);

            uint32_t cInterrupted = 0;
            for (unsigned i = 0; i < RT_ELEMENTS(s_acNsIntervals); i++)
            {
                uint64_t cNs        = s_acNsIntervals[i];
                uint64_t cNsMinSys  = UINT64_MAX;
                uint64_t cNsMin     = UINT64_MAX;
                uint64_t cNsTotalSys= 0;
                uint64_t cNsTotal   = 0;
                unsigned cLoops     = 0;
                while (cLoops < LOOP_COUNT)
                {
                    uint64_t u64StartSys = RTTimeSystemNanoTS();
                    uint64_t u64Start    = RTTimeNanoTS();
                    int rcX = SUPSemEventMultiWaitNsRelIntr(pSession, hEvent, cNs);
                    uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys;
                    uint64_t cNsElapsed    = RTTimeNanoTS()       - u64Start;

                    if (rcX == VERR_INTERRUPTED)
                    {
                        cInterrupted++;
                        continue; /* retry */
                    }
                    if (rcX != VERR_TIMEOUT)
                        RTTestFailed(hTest, "%Rrc cLoops=%u cNs=%u", rcX, cLoops, cNs);

                    if (cNsElapsedSys < cNsMinSys)
                        cNsMinSys = cNsElapsedSys;
                    if (cNsElapsed < cNsMin)
                        cNsMin = cNsElapsed;
                    cNsTotalSys += cNsElapsedSys;
                    cNsTotal    += cNsElapsed;
                    cLoops++;
                }
                if (fSys)
                {
                    RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS,            "%'u ns min (clock=sys)", cNs);
                    RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=sys)", cNs);
                }
                if (fGip)
                {
                    RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS,               "%'u ns min (clock=gip)", cNs);
                    RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS,    "%'u ns avg (clock=gip)", cNs);
                }
            }

            RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEvent), VINF_OBJECT_DESTROYED);
            RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned");
        }

        if (RTTestErrorCount(hTest) == 0)
        {
            RTTestSub(hTest, "SUPSemEventWaitNsAbsIntr Accuracy");
            RTTestValueF(hTest, SUPSemEventGetResolution(pSession), RTTESTUNIT_NS, "MRE resolution");
            RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS);

            uint32_t cInterrupted = 0;
            for (unsigned i = 0; i < RT_ELEMENTS(s_acNsIntervals); i++)
            {
                uint64_t cNs        = s_acNsIntervals[i];
                uint64_t cNsMinSys  = UINT64_MAX;
                uint64_t cNsMin     = UINT64_MAX;
                uint64_t cNsTotalSys= 0;
                uint64_t cNsTotal   = 0;
                unsigned cLoops     = 0;
                while (cLoops < LOOP_COUNT)
                {
                    uint64_t u64StartSys   = RTTimeSystemNanoTS();
                    uint64_t u64Start      = RTTimeNanoTS();
                    uint64_t uAbsDeadline  = (fGip ? u64Start : u64StartSys) + cNs;
                    int rcX = SUPSemEventWaitNsAbsIntr(pSession, hEvent, uAbsDeadline);
                    uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys;
                    uint64_t cNsElapsed    = RTTimeNanoTS()       - u64Start;

                    if (rcX == VERR_INTERRUPTED)
                    {
                        cInterrupted++;
                        continue; /* retry */
                    }
                    if (rcX != VERR_TIMEOUT)
                        RTTestFailed(hTest, "%Rrc cLoops=%u cNs=%u", rcX, cLoops, cNs);

                    if (cNsElapsedSys < cNsMinSys)
                        cNsMinSys = cNsElapsedSys;
                    if (cNsElapsed < cNsMin)
                        cNsMin = cNsElapsed;
                    cNsTotalSys += cNsElapsedSys;
                    cNsTotal    += cNsElapsed;
                    cLoops++;
                }
                if (fSys)
                {
                    RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS,            "%'u ns min (clock=sys)", cNs);
                    RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=sys)", cNs);
                }
                if (fGip)
                {
                    RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS,               "%'u ns min (clock=gip)", cNs);
                    RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS,    "%'u ns avg (clock=gip)", cNs);
                }
            }

            RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED);
            RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned");
        }


        if (RTTestErrorCount(hTest) == 0)
        {
            RTTestSub(hTest, "SUPSemEventMultiWaitNsAbsIntr Accuracy");
            RTTestValueF(hTest, SUPSemEventMultiGetResolution(pSession), RTTESTUNIT_NS, "MRE resolution");
            RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEvent), VINF_SUCCESS);

            uint32_t cInterrupted = 0;
            for (unsigned i = 0; i < RT_ELEMENTS(s_acNsIntervals); i++)
            {
                uint64_t cNs        = s_acNsIntervals[i];
                uint64_t cNsMinSys  = UINT64_MAX;
                uint64_t cNsMin     = UINT64_MAX;
                uint64_t cNsTotalSys= 0;
                uint64_t cNsTotal   = 0;
                unsigned cLoops     = 0;
                while (cLoops < LOOP_COUNT)
                {
                    uint64_t u64StartSys   = RTTimeSystemNanoTS();
                    uint64_t u64Start      = RTTimeNanoTS();
                    uint64_t uAbsDeadline  = (fGip ? u64Start : u64StartSys) + cNs;
                    int rcX = SUPSemEventMultiWaitNsAbsIntr(pSession, hEvent, uAbsDeadline);
                    uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys;
                    uint64_t cNsElapsed    = RTTimeNanoTS()       - u64Start;

                    if (rcX == VERR_INTERRUPTED)
                    {
                        cInterrupted++;
                        continue; /* retry */
                    }
                    if (rcX != VERR_TIMEOUT)
                        RTTestFailed(hTest, "%Rrc cLoops=%u cNs=%u", rcX, cLoops, cNs);

                    if (cNsElapsedSys < cNsMinSys)
                        cNsMinSys = cNsElapsedSys;
                    if (cNsElapsed < cNsMin)
                        cNsMin = cNsElapsed;
                    cNsTotalSys += cNsElapsedSys;
                    cNsTotal    += cNsElapsed;
                    cLoops++;
                }
                if (fSys)
                {
                    RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS,            "%'u ns min (clock=sys)", cNs);
                    RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=sys)", cNs);
                }
                if (fGip)
                {
                    RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS,               "%'u ns min (clock=gip)", cNs);
                    RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS,    "%'u ns avg (clock=gip)", cNs);
                }
            }

            RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEvent), VINF_OBJECT_DESTROYED);
            RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned");
        }

    }


    /*
     * Done.
     */
    return RTTestSummaryAndDestroy(hTest);
}