//--------------------------------------------------------- // Multi wait test // Ensures that no deadlock from waiting/signalling conditions //--------------------------------------------------------- #include #include #include #include #include #include static const unsigned long N = 2_500ul; #ifndef PREEMPTION_RATE #define PREEMPTION_RATE 10_000ul #endif unsigned int default_preemption() { return PREEMPTION_RATE; } monitor global_t {}; global_t globalA; global_t globalB; global_t globalC; condition condAB, condAC, condBC, condABC; thread Signaler {}; thread WaiterAB {}; thread WaiterAC {}; thread WaiterBC {}; thread WaiterABC{}; volatile int waiter_left; //---------------------------------------------------------------------------------------------------- // Tools void signal( condition * cond, global_t & mutex a, global_t & mutex b ) { signal( cond ); } void signal( condition * cond, global_t & mutex a, global_t & mutex b, global_t & mutex c ) { signal( cond ); } void wait( condition * cond, global_t & mutex a, global_t & mutex b ) { wait( cond ); } void wait( condition * cond, global_t & mutex a, global_t & mutex b, global_t & mutex c ) { wait( cond ); } //---------------------------------------------------------------------------------------------------- // Signaler void main( Signaler & this ) { while( waiter_left != 0 ) { unsigned action = (unsigned)rand48() % 4; switch( action ) { case 0: signal( &condABC, globalA, globalB, globalC ); break; case 1: signal( &condAB , globalA, globalB ); break; case 2: signal( &condBC , globalB, globalC ); break; case 3: signal( &condAC , globalA, globalC ); break; default: sout | "Something went wrong" | endl; abort(); } yield(); } } //---------------------------------------------------------------------------------------------------- // Waiter ABC void main( WaiterABC & this ) { for( int i = 0; i < N; i++ ) { wait( &condABC, globalA, globalB, globalC ); } __sync_fetch_and_sub_4( &waiter_left, 1); } //---------------------------------------------------------------------------------------------------- // Waiter AB void main( WaiterAB & this ) { for( int i = 0; i < N; i++ ) { wait( &condAB , globalA, globalB ); } __sync_fetch_and_sub_4( &waiter_left, 1); } //---------------------------------------------------------------------------------------------------- // Waiter AC void main( WaiterAC & this ) { for( int i = 0; i < N; i++ ) { wait( &condAC , globalA, globalC ); } __sync_fetch_and_sub_4( &waiter_left, 1); } //---------------------------------------------------------------------------------------------------- // Waiter BC void main( WaiterBC & this ) { for( int i = 0; i < N; i++ ) { wait( &condBC , globalB, globalC ); } __sync_fetch_and_sub_4( &waiter_left, 1); } //---------------------------------------------------------------------------------------------------- // Main int main(int argc, char* argv[]) { rand48seed( time( NULL ) ); waiter_left = 4; processor p[2]; sout | "Starting" | endl; { Signaler e; { WaiterABC a; WaiterAB b; WaiterBC c; WaiterAC d; } } sout | "Done" | endl; }