예제 #1
0
DECLVBGL(void) VbglTerminate (void)
{
# ifdef VBOX_WITH_HGCM
    vbglR0HGCMTerminate ();
# endif

    /* driver open could fail, which does not prevent VbglInit from succeeding,
     * close the driver only if it is opened */
    if (vbglDriverIsOpened(&g_vbgldata.driver))
        vbglDriverClose(&g_vbgldata.driver);
    RTSemMutexDestroy(g_vbgldata.mutexDriverInit);
    g_vbgldata.mutexDriverInit = NIL_RTSEMMUTEX;

    /* note: do vbglTerminateCommon as a last step since it zeroez up the g_vbgldata
     * conceptually, doing vbglTerminateCommon last is correct
     * since this is the reverse order to how init is done */
    vbglTerminateCommon ();

    return;
}
예제 #2
0
DECLVBGL(int) VbglInitClient(void)
{
    int rc = VINF_SUCCESS;

    if (   g_vbgldata.status == VbglStatusInitializing
        || g_vbgldata.status == VbglStatusReady)
    {
        /* Initialization is already in process. */
        return rc;
    }

    rc = vbglInitCommon ();

    if (RT_SUCCESS(rc))
    {
        rc = RTSemMutexCreate(&g_vbgldata.mutexDriverInit);
        if (RT_SUCCESS(rc))
        {
            /* Try to obtain VMMDev port via IOCTL to VBoxGuest main driver. */
            vbglQueryDriverInfo ();

# ifdef VBOX_WITH_HGCM
            rc = vbglR0HGCMInit ();
# endif /* VBOX_WITH_HGCM */

            if (RT_FAILURE(rc))
            {
                RTSemMutexDestroy(g_vbgldata.mutexDriverInit);
                g_vbgldata.mutexDriverInit = NIL_RTSEMMUTEX;
            }
        }

        if (RT_FAILURE(rc))
        {
            vbglTerminateCommon ();
        }

    }

    return rc;
}
예제 #3
0
/**
 * Service request callback function.
 *
 * @returns VBox status code.
 * @param   pSession    The caller's session.
 * @param   u64Arg      64-bit integer argument.
 * @param   pReqHdr     The request header. Input / Output. Optional.
 */
DECLEXPORT(int) TSTRTR0SemMutexSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOperation,
                                             uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
{
    NOREF(pSession);
    if (!VALID_PTR(pReqHdr))
        return VERR_INVALID_PARAMETER;
    char   *pszErr = (char *)(pReqHdr + 1);
    size_t  cchErr = pReqHdr->cbReq - sizeof(*pReqHdr);
    if (cchErr < 32 || cchErr >= 0x10000)
        return VERR_INVALID_PARAMETER;
    *pszErr = '\0';

#define SET_ERROR(szFmt)                do { if (!*pszErr) RTStrPrintf(pszErr, cchErr, "!" szFmt); } while (0)
#define SET_ERROR1(szFmt, a1)           do { if (!*pszErr) RTStrPrintf(pszErr, cchErr, "!" szFmt, a1); } while (0)
#define SET_ERROR2(szFmt, a1, a2)       do { if (!*pszErr) RTStrPrintf(pszErr, cchErr, "!" szFmt, a1, a2); } while (0)
#define SET_ERROR3(szFmt, a1, a2, a3)   do { if (!*pszErr) RTStrPrintf(pszErr, cchErr, "!" szFmt, a1, a2, a3); } while (0)
#define CHECK_RC_BREAK(rc, rcExpect, szOp) \
        if ((rc) != (rcExpect)) \
        { \
            RTStrPrintf(pszErr, cchErr, "!%s -> %Rrc, expected %Rrc. line %u", szOp, rc, rcExpect, __LINE__); \
            SUPR0Printf("%s -> %d, expected %d. line %u", szOp, rc, rcExpect, __LINE__); \
            break; \
        }

    /*
     * Set up test timeout (when applicable).
     */
    if (u64Arg > 120)
    {
        SET_ERROR1("Timeout is too large (max 120): %lld",  u64Arg);
        return VINF_SUCCESS;
    }
    uint64_t const  StartTS = RTTimeSystemMilliTS();
    uint32_t const  cMsMax  = (uint32_t)u64Arg * 1000;

    /*
     * The big switch.
     */
    RTSEMMUTEX      hMtx;
    int             rc;
    switch (uOperation)
    {
        case TSTRTR0SEMMUTEX_SANITY_OK:
            break;

        case TSTRTR0SEMMUTEX_SANITY_FAILURE:
            SET_ERROR1("42failure42%1024s", "");
            break;

        case TSTRTR0SEMMUTEX_BASIC:
            rc = RTSemMutexCreate(&hMtx);
            CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexCreate");
            do
            {
                /*
                 * The interruptible version first.
                 */
                /* simple request and release, polling. */
                rc = RTSemMutexRequestNoResume(hMtx, 0);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume");
                rc = RTSemMutexRelease(hMtx);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease");

                /* simple request and release, wait for ever. */
                rc = RTSemMutexRequestNoResume(hMtx, RT_INDEFINITE_WAIT);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume(indef_wait)");
                rc = RTSemMutexRelease(hMtx);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease");

                /* simple request and release, wait a tiny while. */
                rc = RTSemMutexRequestNoResume(hMtx, 133);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume(133)");
                rc = RTSemMutexRelease(hMtx);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease");

                /* nested request and release. */
                rc = RTSemMutexRequestNoResume(hMtx, RT_INDEFINITE_WAIT);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume#1");
                rc = RTSemMutexRequestNoResume(hMtx, RT_INDEFINITE_WAIT);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume#2");
                rc = RTSemMutexRequestNoResume(hMtx, RT_INDEFINITE_WAIT);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume#3");
                rc = RTSemMutexRelease(hMtx);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease#3");
                rc = RTSemMutexRequestNoResume(hMtx, RT_INDEFINITE_WAIT);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume#3b");
                rc = RTSemMutexRelease(hMtx);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease#3b");
                rc = RTSemMutexRelease(hMtx);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease#2");
                rc = RTSemMutexRelease(hMtx);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease#1");

                /*
                 * The uninterruptible variant.
                 */
                /* simple request and release, polling. */
                rc = RTSemMutexRequest(hMtx, 0);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequest");
                rc = RTSemMutexRelease(hMtx);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease");

                /* simple request and release, wait for ever. */
                rc = RTSemMutexRequest(hMtx, RT_INDEFINITE_WAIT);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequest(indef_wait)");
                rc = RTSemMutexRelease(hMtx);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease");

                /* simple request and release, wait a tiny while. */
                rc = RTSemMutexRequest(hMtx, 133);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequest(133)");
                rc = RTSemMutexRelease(hMtx);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease");

                /* nested request and release. */
                rc = RTSemMutexRequest(hMtx, RT_INDEFINITE_WAIT);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequest#1");
                rc = RTSemMutexRequest(hMtx, RT_INDEFINITE_WAIT);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequest#2");
                rc = RTSemMutexRequest(hMtx, RT_INDEFINITE_WAIT);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequest#3");
                rc = RTSemMutexRelease(hMtx);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease#3");
                rc = RTSemMutexRequest(hMtx, RT_INDEFINITE_WAIT);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequest#3b");
                rc = RTSemMutexRelease(hMtx);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease#3b");
                rc = RTSemMutexRelease(hMtx);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease#2");
                rc = RTSemMutexRelease(hMtx);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease#1");

            } while (false);

            rc = RTSemMutexDestroy(hMtx);
            CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexDestroy");
            break;

        case TSTRTR0SEMMUTEX_TEST2_SETUP:
        case TSTRTR0SEMMUTEX_TEST3_SETUP:
        case TSTRTR0SEMMUTEX_TEST4_SETUP:
            rc = RTSemMutexCreate(&g_hMtxTest2);
            CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexCreate");
            break;

        case TSTRTR0SEMMUTEX_TEST2_DO:
            for (unsigned i = 0; i < 200; i++)
            {
                if (i & 1)
                {
                    rc = RTSemMutexRequestNoResume(g_hMtxTest2, RT_INDEFINITE_WAIT);
                    CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume(,indef_wait)");
                }
                else
                {
                    rc = RTSemMutexRequestNoResume(g_hMtxTest2, 30000);
                    CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume(,30000)");
                }
                RTThreadSleep(1);
                rc = RTSemMutexRelease(g_hMtxTest2);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease");

                if ((i % 16) == 15 && RTTimeSystemMilliTS() - StartTS >= cMsMax)
                    break;
            }
            break;


        case TSTRTR0SEMMUTEX_TEST3_DO:
            for (unsigned i = 0; i < 1000000; i++)
            {
                if (i & 1)
                {
                    rc = RTSemMutexRequestNoResume(g_hMtxTest2, RT_INDEFINITE_WAIT);
                    CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume(,indef_wait)");
                }
                else
                {
                    rc = RTSemMutexRequestNoResume(g_hMtxTest2, 30000);
                    CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume(,30000)");
                }
                rc = RTSemMutexRelease(g_hMtxTest2);
                CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease");

                if ((i % 256) == 255 && RTTimeSystemMilliTS() - StartTS >= cMsMax)
                    break;
            }
            break;

        case TSTRTR0SEMMUTEX_TEST4_DO:
            for (unsigned i = 0; i < 1024; i++)
            {
                rc = RTSemMutexRequestNoResume(g_hMtxTest2, (i % 32));
                if (rc != VERR_TIMEOUT)
                {
                    CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRequestNoResume");
                    RTThreadSleep(1000);

                    rc = RTSemMutexRelease(g_hMtxTest2);
                    CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexRelease");
                }

                if (RTTimeSystemMilliTS() - StartTS >= cMsMax)
                    break;
            }
            break;

        case TSTRTR0SEMMUTEX_TEST2_CLEANUP:
        case TSTRTR0SEMMUTEX_TEST3_CLEANUP:
        case TSTRTR0SEMMUTEX_TEST4_CLEANUP:
            rc = RTSemMutexDestroy(g_hMtxTest2);
            CHECK_RC_BREAK(rc, VINF_SUCCESS, "RTSemMutexCreate");
            g_hMtxTest2 = NIL_RTSEMMUTEX;
            break;


        default:
            SET_ERROR1("Unknown test #%d", uOperation);
            break;
    }

    /* The error indicator is the '!' in the message buffer. */
    return VINF_SUCCESS;
}
static int Test1(unsigned cThreads, unsigned cSeconds, bool fYield, bool fQuiet)
{
    int rc;
    unsigned i;
    uint64_t g_au64[32];
    RTTHREAD aThreads[RT_ELEMENTS(g_au64)];
    AssertRelease(cThreads <= RT_ELEMENTS(g_au64));

    /*
     * Init globals.
     */
    g_fYield = fYield;
    g_fQuiet = fQuiet;
    g_fTerminate = false;

    rc = RTSemMutexCreate(&g_hMutex);
    if (RT_FAILURE(rc))
        return PrintError("RTSemMutexCreate failed (rc=%Rrc)\n", rc);

    /*
     * Create the threads and let them block on the mutex.
     */
    rc = RTSemMutexRequest(g_hMutex, RT_INDEFINITE_WAIT);
    if (RT_FAILURE(rc))
        return PrintError("RTSemMutexRequest failed (rc=%Rrc)\n", rc);

    for (i = 0; i < cThreads; i++)
    {
        g_au64[i] = 0;
        rc = RTThreadCreate(&aThreads[i], ThreadTest1, &g_au64[i], 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test");
        if (RT_FAILURE(rc))
            return PrintError("RTThreadCreate failed for thread %u (rc=%Rrc)\n", i, rc);
    }

    if (!fQuiet)
        RTPrintf("tstSemMutex: %zu Threads created. Racing them for %u seconds (%s) ...\n",
                 cThreads, cSeconds, g_fYield ? "yielding" : "no yielding");

    uint64_t u64StartTS = RTTimeNanoTS();
    rc = RTSemMutexRelease(g_hMutex);
    if (RT_FAILURE(rc))
        PrintError("RTSemMutexRelease failed (rc=%Rrc)\n", rc);
    RTThreadSleep(cSeconds * 1000);
    ASMAtomicXchgBool(&g_fTerminate, true);
    uint64_t ElapsedNS = RTTimeNanoTS() - u64StartTS;

    for (i = 0; i < cThreads; i++)
    {
        rc = RTThreadWait(aThreads[i], 5000, NULL);
        if (RT_FAILURE(rc))
            PrintError("RTThreadWait failed for thread %u (rc=%Rrc)\n", i, rc);
    }

    rc = RTSemMutexDestroy(g_hMutex);
    if (RT_FAILURE(rc))
        PrintError("RTSemMutexDestroy failed - %Rrc\n", rc);
    g_hMutex = NIL_RTSEMMUTEX;
    if (g_cErrors)
        RTThreadSleep(100);

    /*
     * Collect and display the results.
     */
    uint64_t Total = g_au64[0];
    for (i = 1; i < cThreads; i++)
        Total += g_au64[i];

    uint64_t Normal = Total / cThreads;
    uint64_t MaxDeviation = 0;
    for (i = 0; i < cThreads; i++)
    {
        uint64_t Delta = RT_ABS((int64_t)(g_au64[i] - Normal));
        if (Delta > Normal / 2)
            RTPrintf("tstSemMutex: Warning! Thread %d deviates by more than 50%% - %llu (it) vs. %llu (avg)\n",
                     i, g_au64[i], Normal);
        if (Delta > MaxDeviation)
            MaxDeviation = Delta;

    }

    RTPrintf("tstSemMutex: Threads: %u  Total: %llu  Per Sec: %llu  Avg: %llu ns  Max dev: %llu%%\n",
             cThreads,
             Total,
             Total / cSeconds,
             ElapsedNS / Total,
             MaxDeviation * 100 / Normal
             );
    return 0;
}