tstRTSemRW.cpp revision 81c25d660627bd01becee294f774f2e0036f9d91
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * IPRT Testcase - Reader/Writer Semaphore.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * Copyright (C) 2009-2010 Oracle Corporation
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * available from http://www.virtualbox.org. This file is free software;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * General Public License (GPL) as published by the Free Software
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * The contents of this file may alternatively be used under the terms
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * of the Common Development and Distribution License Version 1.0
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * VirtualBox OSE distribution, in which case the provisions of the
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * CDDL are applicable instead of those of the GPL.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * You may elect to license modified versions of this file under the
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * terms and conditions of either the GPL or the CDDL or both.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/*******************************************************************************
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync* Header Files *
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync*******************************************************************************/
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync/*******************************************************************************
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync* Global Variables *
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync*******************************************************************************/
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic bool volatile g_fTerminate;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic unsigned g_uWritePercent;
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsyncstatic DECLCALLBACK(int) Test4Thread(RTTHREAD ThreadSelf, void *pvUser)
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync /* Use randomization to get a little more variation of the sync pattern.
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync We use a pseudo random generator here so that we don't end up testing
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync the speed of the /dev/urandom implementation, but rather the read-write
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync semaphores. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync RTTEST_CHECK_RC_OK_RET(g_hTest, rc = RTRandAdvCreateParkMiller(&hRand), rc);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync RTTEST_CHECK_RC_OK_RET(g_hTest, rc = RTRandAdvSeed(hRand, (uintptr_t)ThreadSelf), rc);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync /* Don't overdo recursion testing. */
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync for (unsigned i = 0; i <= writerec; i++)
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync rc = RTSemRWRequestWriteNoResume(g_hSemRW, RT_INDEFINITE_WAIT);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync RTTestFailed(g_hTest, "Write recursion %u on %s failed with rc=%Rrc", i, RTThreadSelfName(), rc);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync RTTestFailed(g_hTest, "g_cConcurrentWriters=%u on %s after write locking it",
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync RTTestFailed(g_hTest, "g_cConcurrentReaders=%u on %s after write locking it",
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync rc = RTSemRWRequestReadNoResume(g_hSemRW, RT_INDEFINITE_WAIT);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync RTTestFailed(g_hTest, "Read locking on %s failed with rc=%Rrc", RTThreadSelfName(), rc);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync RTTestFailed(g_hTest, "g_cConcurrentWriters=%u on %s after read locking it",
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync for (unsigned i = 0; i < readrec; i++)
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync rc = RTSemRWRequestReadNoResume(g_hSemRW, RT_INDEFINITE_WAIT);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync RTTestFailed(g_hTest, "Read recursion %u on %s failed with rc=%Rrc", i, RTThreadSelfName(), rc);
a3f3701cea1ba388e7c877955252bb7375eedebdvboxsync * Check for fairness: The values of the threads should not differ too much
(*pcItr)++;
if (g_fYield)
for (unsigned i = 0; i < readrec; i++)
if (fWrite)
if (g_cConcurrentReaders != 0)
for (unsigned i = 0; i <= writerec; i++)
if (g_cConcurrentWriters != 0)
if (g_fTerminate)
c100++;
if (!g_fQuiet)
RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Thread %s exited with %lld\n", RTThreadSelfName(), *pcItr);
return VINF_SUCCESS;
static void Test4(unsigned cThreads, unsigned cSeconds, unsigned uWritePercent, bool fYield, bool fQuiet)
g_fTerminate = false;
g_cConcurrentWriters = 0;
g_cConcurrentReaders = 0;
for (i = 0; i < cThreads; i++)
acIterations[i] = 0;
for (i = 0; i < cThreads; i++)
RTTEST_CHECK_MSG(g_hTest, g_cConcurrentWriters == 0, (g_hTest, "g_cConcurrentWriters=%u at end of test\n", g_cConcurrentWriters));
RTTEST_CHECK_MSG(g_hTest, g_cConcurrentReaders == 0, (g_hTest, "g_cConcurrentReaders=%u at end of test\n", g_cConcurrentReaders));
for (i = 0; i < cThreads; i++)
RTTestFailed(g_hTest, "Thread %u did less than 5%% of the iterations - %llu (it) vs. %llu (5%%) - %llu%%\n",
RTTestValue(g_hTest, "Thruput", cItrTotal * UINT32_C(1000000000) / ElapsedNS, RTTESTUNIT_CALLS_PER_SEC);
return VINF_SUCCESS;
static void Test3(void)
RTTEST_CHECK_RC(g_hTest, RTSemRWReleaseWrite(hSemRW), VERR_WRONG_ORDER); /* cannot release the final write before the reads. */
static void Test2(void)
static bool Test1(void)
if (rc)
if (Test1())
Test2();
Test3();