blob: 2eac067baa422e39e8a92b4a42de3f6d86a243e8 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "MutexTest.h"
using namespace std;
using namespace decaf;
using namespace decaf::lang;
using namespace decaf::util;
using namespace decaf::util::concurrent;
///////////////////////////////////////////////////////////////////////////////
void MutexTest::testTimedWait(){
try
{
MyTimedWaitingThread test;
time_t startTime = time( NULL );
test.start();
test.join();
time_t endTime = time( NULL );
time_t delta = endTime - startTime;
CPPUNIT_ASSERT( delta >= 1 && delta <= 3 );
}
catch(lang::Exception& ex)
{
std::cout << ex.getMessage() << std::endl;
}
}
void MutexTest::testWait(){
try
{
MyWaitingThread test;
test.start();
Thread::sleep( 1000 );
synchronized( &test )
{
for( int ix=0; ix<100; ix++ ){
test.value += 1;
}
test.notify();
}
test.join();
CPPUNIT_ASSERT( test.value == 2500 );
} catch( lang::Exception& ex ) {
ex.setMark( __FILE__, __LINE__ );
}
}
void MutexTest::test()
{
MyThread test;
synchronized(&test){
test.start();
for( int ix=0; ix<100; ix++ ){
test.value += 1;
}
}
test.join();
CPPUNIT_ASSERT( test.value == 2500 );
}
void MutexTest::testNotify()
{
try{
Mutex mutex;
Mutex started;
Mutex completed;
const int numThreads = 30;
MyNotifiedThread* threads[numThreads];
// Create and start all the threads.
for( int ix=0; ix<numThreads; ++ix ){
threads[ix] = new MyNotifiedThread( &mutex, &started, &completed );
threads[ix]->start();
}
synchronized( &started )
{
int count = 0;
while( count < ( numThreads ) )
{
started.wait( 30 );
count++;
}
}
synchronized(&mutex)
{
mutex.notify();
}
Thread::sleep( 1000 );
int counter = 0;
for( int ix=0; ix<numThreads; ++ix ){
if( threads[ix]->done ){
counter++;
}
}
// Make sure only 1 thread was notified.
CPPUNIT_ASSERT( counter == 1 );
synchronized(&mutex)
{
// Notify all threads.
for( int ix=0; ix<numThreads-1; ++ix ){
mutex.notify();
}
}
synchronized( &started )
{
int count = 0;
while( count < ( numThreads ) )
{
started.wait( 30 );
count++;
}
}
int numComplete = 0;
for( int ix=0; ix<numThreads; ++ix ){
if( threads[ix]->done ){
numComplete++;
}
}
CPPUNIT_ASSERT( numComplete == numThreads );
synchronized( &mutex )
{
mutex.wait( 5 );
}
synchronized( &mutex )
{
mutex.notifyAll();
}
// Delete all the threads.
for( int ix=0; ix<numThreads; ++ix ){
delete threads[ix];
}
}catch( lang::Exception& ex ){
ex.setMark( __FILE__, __LINE__ );
}
}
void MutexTest::testNotifyAll()
{
try{
Mutex mutex;
Mutex started;
Mutex completed;
const int numThreads = 100;
MyNotifiedThread* threads[numThreads];
// Create and start all the threads.
for( int ix=0; ix<numThreads; ++ix ){
threads[ix] = new MyNotifiedThread( &mutex, &started, &completed );
threads[ix]->start();
}
synchronized( &started )
{
int count = 0;
while( count < ( numThreads ) )
{
started.wait( 30 );
count++;
}
}
for( int ix=0; ix<numThreads; ++ix )
{
if( threads[ix]->done == true ){
printf("threads[%d] is done prematurely\n", ix );
}
CPPUNIT_ASSERT( threads[ix]->done == false );
}
// Notify all threads.
synchronized( &mutex ){
mutex.notifyAll();
}
synchronized( &completed )
{
int count = 0;
while( count < ( numThreads ) )
{
completed.wait( 30 );
count++;
}
}
int numComplete = 0;
for( int ix=0; ix<numThreads; ++ix ){
if( threads[ix]->done ){
numComplete++;
}
}
//printf("numComplete: %d, numThreads: %d\n", numComplete, numThreads );
CPPUNIT_ASSERT( numComplete == numThreads );
// Delete all the threads.
for( int ix=0; ix<numThreads; ++ix ){
threads[ix]->join();
delete threads[ix];
}
}catch( lang::Exception& ex ){
ex.setMark( __FILE__, __LINE__ );
}
}
void MutexTest::testRecursiveLock()
{
try{
Mutex mutex;
const int numThreads = 30;
MyRecursiveLockThread* threads[numThreads];
// Create and start all the threads.
for( int ix=0; ix<numThreads; ++ix ){
threads[ix] = new MyRecursiveLockThread( &mutex );
threads[ix]->start();
}
// Sleep so all the threads can get to the wait.
Thread::sleep( 1000 );
for( int ix=0; ix<numThreads; ++ix ){
if( threads[ix]->done == true ){
std::cout << "threads[" << ix
<< "] is done prematurely\n";
}
CPPUNIT_ASSERT( threads[ix]->done == false );
}
// Notify all threads.
synchronized( &mutex )
{
synchronized( &mutex )
{
mutex.notifyAll();
}
}
// Sleep to give the threads time to wake up.
Thread::sleep( 1000 );
for( int ix=0; ix<numThreads; ++ix ){
if( threads[ix]->done != true ){
std::cout<< "threads[" << ix << "] is not done\n";
}
CPPUNIT_ASSERT( threads[ix]->done == true );
}
// Delete all the threads.
for( int ix=0; ix<numThreads; ++ix ){
delete threads[ix];
}
}catch( lang::Exception& ex ){
ex.setMark( __FILE__, __LINE__ );
}
}
void MutexTest::testDoubleLock()
{
try{
Mutex mutex1;
Mutex mutex2;
MyDoubleLockThread thread(&mutex1, &mutex2);
thread.start();
// Let the thread get both locks
Thread::sleep( 200 );
// Lock mutex 2, thread is waiting on it
synchronized(&mutex2)
{
mutex2.notify();
}
// Let the thread die
thread.join();
CPPUNIT_ASSERT( thread.done );
}catch( lang::Exception& ex ){
ex.setMark( __FILE__, __LINE__ );
}
}
///////////////////////////////////////////////////////////////////////////////
void MutexTest::testStressMutex(){
MyStoppableThread tester;
tester.start();
CPPUNIT_ASSERT( tester.isStarted() );
for( int i = 0; i < 100; ++i ) {
tester.stop();
tester.start();
}
CPPUNIT_ASSERT( true );
}