Esempio n. 1
0
bool RandomizeMutexOrder( LevelMutexInfo::MutexContainer & mutexes )
{
    unsigned int count = mutexes.size();
    if ( count < 2 )
        return false;

    LevelMutexInfo::MutexContainer randomMutexes;
    for ( unsigned int ii = 0; ii < count; ++ii )
    {
        volatile LevelMutexInfo * mutex = nullptr;
        const unsigned int sizeNow = mutexes.size();
        if ( 1 < sizeNow )
        {
            unsigned int index = ( ::rand() % sizeNow );
            mutex = mutexes[ index ];
            if ( index < sizeNow - 1 )
                mutexes[ index ] = mutexes[ sizeNow - 1 ];
        }
        else
        {
            mutex = mutexes[ 0 ];
        }
        mutexes.pop_back();
        randomMutexes.push_back( mutex );
    }

    mutexes = randomMutexes;
    return true;
}
Esempio n. 2
0
void UnlockThese( SomeThingPool & pool )
{

    const unsigned int count = pool.size();
    assert( 0 != count );
    SortByLevel( pool );

    volatile SomeThing * thing = pool[ 0 ];
    assert( NULL != thing );
    unsigned int level = thing->GetLevel();
    LevelMutexInfo::MutexContainer mutexes;
    MutexErrors::Type result = MutexErrors::Success;
    unsigned int ii = 0;

    for ( ii = 0; ii < count; ++ii )
    {
        thing = pool[ ii ];
        assert( NULL != thing );
        if ( level != thing->GetLevel() )
        {
            assert( mutexes.size() != 0 );
            result = LevelMutexInfo::MultiUnlock( mutexes );
            assert( result == MutexErrors::Success );
            mutexes.clear();
            level = thing->GetLevel();
        }
        mutexes.push_back( &thing->GetMutex() );
    }

    assert( mutexes.size() != 0 );
    result = LevelMutexInfo::MultiUnlock( mutexes );
    assert( result == MutexErrors::Success );

    for ( ii = 0; ii < count; ++ii )
    {
        thing = pool[ ii ];
        assert( NULL != thing );
        assert( !thing->GetMutex().IsLockedByCurrentThread() );
    }
}
Esempio n. 3
0
void * MultiLockRandomSafeThread( void * p )
{
    const unsigned int value = reinterpret_cast< unsigned int >( p );
    unsigned int testCount = 0;
    unsigned int failCount = 0;
    volatile Thing * thing = nullptr;
    Thing::ThingPool pool;
    LevelMutexInfo::MutexContainer mutexes;
    mutexes.reserve( thingCount );

    unsigned int jj = 0;
    unsigned int place = 0;
    try
    {
        for ( unsigned int ii = 0; ii < thingCount; ++ii )
        {

            pool.clear();
            pool.reserve( thingCount );
            for ( place = 0; place < thingCount; ++place )
            {
                place += ::rand() % 3;
                if ( thingCount <= place )
                    break;
                thing = Thing::GetFromPool( place );
                assert( nullptr != thing );
                pool.push_back( thing );
            }
            const unsigned int poolCount = pool.size();

            mutexes.clear();
            for ( jj = 0; jj < poolCount; ++jj )
            {
                thing = pool[ jj ];
                assert( nullptr != thing );
                mutexes.push_back( &thing->GetMutex() );
            }

            MultiMutexLocker locker( mutexes );
            (void)locker;
            for ( jj = 0; jj < poolCount; ++jj )
            {
                thing = pool[ jj ];
                assert( nullptr != thing );
                thing->SetValue( value );
            }
            ::GoToSleep( 3 );

            for ( jj = 0; jj < poolCount; ++jj )
            {
                thing = pool[ jj ];
                assert( nullptr != thing );
                if ( thing->GetValue() != value )
                    failCount++;
                testCount++;
            }
        }
    }
    catch ( ... )
    {
        assert( false );
    }

    TestResults::GetIt()->SetResult( value, testCount, failCount );

    return nullptr;
}
Esempio n. 4
0
void SingleThreadComplexMultiLockTest( bool doSetup )
{

    ::srand( static_cast< unsigned int >( time( nullptr ) ) );
    if ( doSetup )
    {
        Thing::MakePool( thingCount );
    }

    const unsigned int priorLevel      = GetCurrentThreadsLevel();
    const unsigned int priorLockCount  = CountLocksInCurrentThread();
    const unsigned int priorMutexCount = CountMutexesInCurrentThread();
    const unsigned int priorLevelMutexCount = CountMutexesAtCurrentLevel();
    if ( LevelMutexInfo::UnlockedLevel == priorLevel )
    {
        assert( priorLockCount  == 0 );
        assert( priorMutexCount == 0 );
        assert( priorLevelMutexCount == 0 );
    }
    else
    {
        assert( priorLockCount  != 0 );
        assert( priorMutexCount != 0 );
        assert( priorLevelMutexCount != 0 );
        assert( priorLevelMutexCount <= priorMutexCount );
        assert( priorMutexCount <= priorLockCount );
    }

    volatile Thing * thing0 = Thing::GetFromPool( 0 );
    volatile Thing * thing1 = Thing::GetFromPool( 1 );
    volatile Thing * thing2 = Thing::GetFromPool( 2 );
    volatile Thing * thing3 = Thing::GetFromPool( 3 );
    volatile Thing * thing4 = Thing::GetFromPool( 4 );
    volatile Thing * thing5 = Thing::GetFromPool( 5 );
    volatile Thing * thing6 = Thing::GetFromPool( 6 );
    volatile Thing * thing7 = Thing::GetFromPool( 7 );
    assert( nullptr != thing0 );
    assert( nullptr != thing1 );
    assert( nullptr != thing2 );
    assert( nullptr != thing3 );
    assert( nullptr != thing4 );
    assert( nullptr != thing5 );
    assert( nullptr != thing6 );
    assert( nullptr != thing7 );

    LevelMutexInfo::MutexContainer mutexes;
    mutexes.reserve( thingCount );
    MutexErrors::Type result = LevelMutexInfo::MultiLock( mutexes );
    assert( result == MutexErrors::EmptyContainer );

    mutexes.push_back( &thing0->GetMutex() );
    mutexes.push_back( &thing1->GetMutex() );
    mutexes.push_back( &thing2->GetMutex() );
    mutexes.push_back( &thing3->GetMutex() );
    mutexes.push_back( &thing4->GetMutex() );
    mutexes.push_back( &thing5->GetMutex() );
    mutexes.push_back( &thing6->GetMutex() );
    mutexes.push_back( &thing7->GetMutex() );

    result = LevelMutexInfo::MultiLock( mutexes );
    assert( result == MutexErrors::Success );
    assert( GetCurrentThreadsLevel()      == thing0->GetMutex().GetLevel() );
    assert( CountLocksInCurrentThread()   == priorLockCount  + thingCount );
    result = LevelMutexInfo::MultiUnlock( mutexes );
    assert( result == MutexErrors::Success );
    assert( GetCurrentThreadsLevel()      == priorLevel );
    assert( CountLocksInCurrentThread()   == priorLockCount );
    assert( CountMutexesInCurrentThread() == priorMutexCount );
    assert( CountMutexesAtCurrentLevel()  == priorLevelMutexCount );

    mutexes.clear();
    mutexes.push_back( &thing7->GetMutex() );
    mutexes.push_back( &thing6->GetMutex() );
    mutexes.push_back( &thing5->GetMutex() );
    mutexes.push_back( &thing4->GetMutex() );
    mutexes.push_back( &thing3->GetMutex() );
    mutexes.push_back( &thing2->GetMutex() );
    mutexes.push_back( &thing1->GetMutex() );
    mutexes.push_back( &thing0->GetMutex() );
    result = LevelMutexInfo::MultiLock( mutexes );
    assert( result == MutexErrors::Success );
    assert( GetCurrentThreadsLevel()      == thing0->GetMutex().GetLevel() );
    assert( CountLocksInCurrentThread()   == priorLockCount  + thingCount );
    result = LevelMutexInfo::MultiUnlock( mutexes );
    assert( result == MutexErrors::Success );
    assert( GetCurrentThreadsLevel()      == priorLevel );
    assert( CountLocksInCurrentThread()   == priorLockCount );
    assert( CountMutexesInCurrentThread() == priorMutexCount );
    assert( CountMutexesAtCurrentLevel()  == priorLevelMutexCount );

    RandomizeMutexOrder( mutexes );
    result = LevelMutexInfo::MultiLock( mutexes );
    assert( result == MutexErrors::Success );
    assert( GetCurrentThreadsLevel()      == thing0->GetMutex().GetLevel() );
    assert( CountLocksInCurrentThread()   == priorLockCount  + thingCount );
    result = LevelMutexInfo::MultiUnlock( mutexes );
    assert( result == MutexErrors::Success );
    assert( GetCurrentThreadsLevel()      == priorLevel );
    assert( CountLocksInCurrentThread()   == priorLockCount );
    assert( CountMutexesInCurrentThread() == priorMutexCount );
    assert( CountMutexesAtCurrentLevel()  == priorLevelMutexCount );

    if ( doSetup )
        Thing::DestroyPool();
}
Esempio n. 5
0
void SingleThreadExceptionTest( void )
{
    cout << "Starting SingleThreadExceptionTest." << endl;

    const unsigned int priorLevel = GetCurrentThreadsLevel();
    const unsigned int priorLockCount  = CountLocksInCurrentThread();
    const unsigned int priorMutexCount = CountMutexesInCurrentThread();
    const unsigned int priorLevelMutexCount = CountMutexesAtCurrentLevel();
    if ( LevelMutexInfo::UnlockedLevel == priorLevel )
    {
        assert( priorLockCount  == 0 );
        assert( priorMutexCount == 0 );
        assert( priorLevelMutexCount == 0 );
    }
    else
    {
        assert( priorLockCount  != 0 );
        assert( priorMutexCount != 0 );
        assert( priorLevelMutexCount != 0 );
        assert( priorLevelMutexCount <= priorMutexCount );
        assert( priorMutexCount <= priorLockCount );
    }

    ExceptionMutex mutex1a( 1 );
    mutex1a.GetMutexPolicy().SetTossPolicy( ExceptionTossingMutex::Always );
    ExceptionMutex mutex2a( 2 );
    mutex2a.GetMutexPolicy().SetTossPolicy( ExceptionTossingMutex::Never );
    MutexErrors::Type result = MutexErrors::Success;
    try
    {
        mutex1a.Lock();
        assert( false );
    }
    catch ( ... )
    {
        assert( true );
    }

    try
    {
        result = mutex2a.Lock();
        assert( MutexErrors::Success == result );
        mutex1a.GetMutexPolicy().SetTossPolicy( ExceptionTossingMutex::Never );
        result = mutex1a.Lock();
        assert( MutexErrors::Success == result );
        result = mutex1a.Unlock();
        assert( MutexErrors::Success == result );
        result = mutex2a.Unlock();
        assert( MutexErrors::Success == result );
    }
    catch ( ... )
    {
        assert( false );
    }

    ExceptionMutex mutex2b( 2 );
    mutex2b.GetMutexPolicy().SetTossPolicy( ExceptionTossingMutex::Always );
    ExceptionMutex mutex2c( 2 );
    mutex2c.GetMutexPolicy().SetTossPolicy( ExceptionTossingMutex::Never );
    ExceptionMutex mutex2d( 2 );
    mutex2d.GetMutexPolicy().SetTossPolicy( ExceptionTossingMutex::Never );
    LevelMutexInfo::MutexContainer mutexes;

    try
    {
        mutexes.push_back( &mutex2a );
        mutexes.push_back( &mutex2b );
        mutexes.push_back( &mutex2c );
        mutexes.push_back( &mutex2d );
        result = LevelMutexInfo::MultiLock( mutexes );
        assert( false );
    }
    catch ( ... )
    {
        assert( true );
    }

    bool okay = ( !mutex2a.IsLockedByCurrentThread() );
    assert( okay );
    okay = ( !mutex2b.IsLockedByCurrentThread() );
    assert( okay );
    okay = ( !mutex2c.IsLockedByCurrentThread() );
    assert( okay );
    okay = ( !mutex2d.IsLockedByCurrentThread() );
    assert( okay );

    mutex2b.GetMutexPolicy().SetTossPolicy( ExceptionTossingMutex::Never );

    ExceptionMutex mutex3a( 3 );
    mutex3a.GetMutexPolicy().SetTossPolicy( ExceptionTossingMutex::Never );
    ExceptionMutex mutex3b( 3 );
    mutex3b.GetMutexPolicy().SetTossPolicy( ExceptionTossingMutex::Never );
    mutexes.clear();

    try
    {
        mutexes.push_back( &mutex3a );
        mutexes.push_back( &mutex3b );
        result = LevelMutexInfo::MultiLock( mutexes ); // 3a, 3b
        assert( true );
        assert( MutexErrors::Success == result );
        okay = ( mutex3a.IsLockedByCurrentThread() );
        assert( okay );
        okay = ( mutex3b.IsLockedByCurrentThread() );
        assert( okay );
    }
    catch ( ... )
    {
        assert( false );
    }

    try
    {
        mutex2c.GetMutexPolicy().SetTossPolicy( ExceptionTossingMutex::Always );
        mutexes.clear();
        mutexes.push_back( &mutex2a );
        mutexes.push_back( &mutex2b );
        mutexes.push_back( &mutex2c );
        mutexes.push_back( &mutex2d );
        result = LevelMutexInfo::MultiLock( mutexes );
        assert( false );
    }
    catch ( ... )
    {
        assert( true );
        okay = ( !mutex2a.IsLockedByCurrentThread() );
        assert( okay );
        okay = ( !mutex2b.IsLockedByCurrentThread() );
        assert( okay );
        okay = ( !mutex2c.IsLockedByCurrentThread() );
        assert( okay );
        okay = ( !mutex2d.IsLockedByCurrentThread() );
        assert( okay );
        okay = ( mutex3a.IsLockedByCurrentThread() );
        assert( okay );
        okay = ( mutex3b.IsLockedByCurrentThread() );
        assert( okay );
    }

    mutexes.clear();
    mutexes.push_back( &mutex3a );
    mutexes.push_back( &mutex3b );
    result = LevelMutexInfo::MultiUnlock( mutexes );
    assert( MutexErrors::Success == result );

    okay = ( GetCurrentThreadsLevel() == priorLevel );
    assert( okay );
    okay = ( CountLocksInCurrentThread() == priorLockCount );
    assert( okay );
    okay = ( CountMutexesInCurrentThread() == priorMutexCount );
    assert( okay );
    okay = ( CountMutexesAtCurrentLevel()  == priorLevelMutexCount );
    assert( okay );

    cout << "Finished SingleThreadExceptionTest." << endl;
}
Esempio n. 6
0
void SingleThreadSimpleMultiLockTest( void )
{
    cout << "Finished SingleThreadSimpleMultiLockTest." << endl;

    const unsigned int priorLevel = GetCurrentThreadsLevel();
    const unsigned int priorLockCount  = CountLocksInCurrentThread();
    const unsigned int priorMutexCount = CountMutexesInCurrentThread();
    const unsigned int priorLevelMutexCount = CountMutexesAtCurrentLevel();
    if ( LevelMutexInfo::UnlockedLevel == priorLevel )
    {
        assert( priorLockCount  == 0 );
        assert( priorMutexCount == 0 );
        assert( priorLevelMutexCount == 0 );
    }
    else
    {
        assert( priorLockCount  != 0 );
        assert( priorMutexCount != 0 );
        assert( priorLevelMutexCount != 0 );
        assert( priorLevelMutexCount <= priorMutexCount );
        assert( priorMutexCount <= priorLockCount );
    }

    SpinMutex mutex1( 1 );
    SpinMutex mutex2( 1 );
    bool okay = ( mutex2.GetLevel() == mutex1.GetLevel() );
    assert( okay );

    okay = ( GetCurrentThreadsLevel() == priorLevel );
    assert( okay );
    LevelMutexInfo::MutexContainer mutexes;
    mutexes.push_back( &mutex1 );
    mutexes.push_back( &mutex2 );

    MutexErrors::Type result = LevelMutexInfo::MultiLock( mutexes );  // locks: 1, 2
    assert( MutexErrors::Success == result );
    okay = ( GetCurrentThreadsLevel() == mutex1.GetLevel() );
    assert( okay );
    result = LevelMutexInfo::MultiUnlock( mutexes );    // locks: none
    assert( MutexErrors::Success == result );
    okay = ( CountMutexesAtCurrentLevel()  == priorLevelMutexCount );
    assert( okay );

    mutexes.clear();
    mutexes.push_back( &mutex1 );
    mutexes.push_back( &mutex2 );
    mutexes.push_back( &mutex1 );
    result = LevelMutexInfo::MultiLock( mutexes );      // locks: none
    assert( MutexErrors::DuplicateMutex == result );
    okay = ( CountMutexesAtCurrentLevel()  == priorLevelMutexCount );
    assert( okay );
    okay = ( GetCurrentThreadsLevel() == priorLevel );
    assert( okay );

    mutexes.clear();
    mutexes.push_back( &mutex1 );
    mutexes.push_back( nullptr );
    mutexes.push_back( &mutex2 );
    result = LevelMutexInfo::MultiLock( mutexes );      // locks: none
    assert( MutexErrors::NullMutexPointer == result );
    okay = ( CountMutexesAtCurrentLevel()  == priorLevelMutexCount );
    assert( okay );
    okay = ( GetCurrentThreadsLevel() == priorLevel );
    assert( okay );

    SpinMutex mutex3( 3 );
    mutexes.clear();
    mutexes.push_back( &mutex1 );
    mutexes.push_back( &mutex2 );
    mutexes.push_back( &mutex3 );
    result = LevelMutexInfo::MultiLock( mutexes );      // locks: none
    assert( MutexErrors::WrongLevel == result );
    okay = ( CountMutexesAtCurrentLevel()  == priorLevelMutexCount );
    assert( okay );
    okay = ( GetCurrentThreadsLevel() == priorLevel );
    assert( okay );

    result = mutex1.Lock();                         // locks: 1
    assert( MutexErrors::Success == result );
    mutexes.clear();
    mutexes.push_back( &mutex1 );
    mutexes.push_back( &mutex2 );
    try
    {
        result = LevelMutexInfo::MultiLock( mutexes );  // locks: 1
    }
    catch ( const MutexException & ex1 )
    {
        assert( MutexErrors::LevelTooHigh == ex1.GetReason() );
    }
    catch ( ... )
    {
        assert( false );
    }
    result = mutex1.Unlock();                       // locks: none
    assert( MutexErrors::Success == result );

    result = LevelMutexInfo::MultiLock( mutexes );      // locks: 1, 2
    assert( MutexErrors::Success == result );
    const bool m1IsFirst = ( &mutex1 > &mutex2 );
    LevelMutexInfo * first  = ( m1IsFirst ) ? &mutex1 : &mutex2;
    LevelMutexInfo * second = ( m1IsFirst ) ? &mutex2 : &mutex1;
    result = first->Unlock();                       // locks: 2
    assert( MutexErrors::Success == result );
    result = LevelMutexInfo::MultiUnlock( mutexes );    // locks: 2
    assert( MutexErrors::NotRecentLock == result );
    result = second->Unlock();                      // locks: none
    assert( MutexErrors::Success == result );

    // Now combine some calls to TryLock with a call to MultiLock.
    mutexes.clear();
    mutexes.push_back( &mutex1 );
    mutexes.push_back( &mutex2 );
    result = LevelMutexInfo::MultiLock( mutexes );      // locks: 1, 2
    assert( MutexErrors::Success == result );
    result = mutex2.TryLock();                      // locks: 1, 2+
    assert( MutexErrors::Success == result );
    okay = ( mutex2.GetLockCount() == 2 );
    assert( okay );
    result = mutex2.Unlock();                       // locks: 1, 2
    assert( MutexErrors::Success == result );
    result = mutex1.TryLock();                      // locks: 1+, 2
    assert( result == MutexErrors::Success );
    okay = ( mutex1.GetLockCount() == 2 );
    assert( okay );
    result = mutex2.TryLock();                      // locks: 1+, 2+
    assert( result == MutexErrors::Success );
    okay = ( mutex2.GetLockCount() == 2 );
    assert( okay );
    result = mutex2.Unlock();                       // locks: 1+, 2
    assert( MutexErrors::Success == result );
    result = mutex1.Unlock();                       // locks: 1, 2
    assert( MutexErrors::Success == result );
    result = LevelMutexInfo::MultiUnlock( mutexes );    // locks: 1, 2
    assert( MutexErrors::Success == result );

    okay = ( GetCurrentThreadsLevel() == priorLevel );
    assert( okay );
    okay = ( CountMutexesAtCurrentLevel()  == priorLevelMutexCount );
    assert( okay );

    SpinMutex mutex4( 1 );
    result = mutex4.Lock();
    assert( MutexErrors::Success == result );
    mutexes.clear();
    mutexes.push_back( &mutex1 );
    mutexes.push_back( &mutex2 );

    try
    {
        result = LevelMutexInfo::MultiLock( mutexes );
    }
    catch ( const MutexException & ex1 )
    {
        assert( MutexErrors::LevelTooHigh == ex1.GetReason() );
    }
    catch ( ... )
    {
        assert( false );
    }
    mutexes.clear();
    mutexes.push_back( &mutex1 );
    mutexes.push_back( &mutex4 );
    result = LevelMutexInfo::MultiUnlock( mutexes );
    assert( MutexErrors::NotRecentLock == result );

    mutexes.clear();
    mutexes.push_back( &mutex1 );
    mutexes.push_back( &mutex2 );
    result = LevelMutexInfo::MultiUnlock( mutexes );
    assert( MutexErrors::NotRecentLock == result );
    result = mutex4.Unlock();
    assert( MutexErrors::Success == result );

    // Make sure current thread has released locks acquired in this function.
    okay = ( GetCurrentThreadsLevel() == priorLevel );
    assert( okay );
    okay = ( CountMutexesAtCurrentLevel()  == priorLevelMutexCount );
    assert( okay );

    // What if this tries to unlock multiple mutexes when nothing is locked?
    mutexes.clear();
    mutexes.push_back( &mutex1 );
    mutexes.push_back( &mutex2 );
    result = LevelMutexInfo::MultiUnlock( mutexes );
    assert( MutexErrors::NotRecentLock == result );

    okay = ( GetCurrentThreadsLevel() == priorLevel );
    assert( okay );
    okay = ( CountLocksInCurrentThread() == priorLockCount );
    assert( okay );
    okay = ( CountMutexesInCurrentThread() == priorMutexCount );
    assert( okay );
    okay = ( CountMutexesAtCurrentLevel()  == priorLevelMutexCount );
    assert( okay );

    cout << "Finished SingleThreadSimpleMultiLockTest." << endl;
}