/** * @file * * This test exercises the POSIX Spinlock manager. */ /* * COPYRIGHT (c) 1989-2012. * On-Line Applications Research Corporation (OAR). * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "tmacros.h" #include #include #include #include #include /* for task creation */ const char rtems_test_name[] = "PSXSPIN 1"; /* forward declarations to avoid warnings */ int test_main(void); rtems_task SpinlockThread(rtems_task_argument arg); pthread_spinlock_t Spinlock; volatile int mainThreadSpinning; rtems_task SpinlockThread(rtems_task_argument arg) { int status; if ( mainThreadSpinning ) { puts( "main thread is not supposed to be spinning yet" ); exit(0); } puts( "pthread_spin_lock( &Spinlock ) from Thread -- OK" ); status = pthread_spin_lock( &Spinlock ); rtems_test_assert( status == 0 ); puts( "sleep to allow main thread to run" ); sleep( 1 ); if ( !mainThreadSpinning ) { puts( "main thread is not spinning on lock" ); exit(0); } puts( "pthread_spin_unlock( &Spinlock ) from Thread -- OK" ); status = pthread_spin_unlock( &Spinlock ); rtems_test_assert( status == 0 ); rtems_task_delete( RTEMS_SELF ); } /* * main entry point to the test */ #if defined(__rtems__) int test_main(void) #else int main( int argc, char **argv ) #endif { pthread_spinlock_t spinlock; int status; rtems_status_code rstatus; rtems_id taskid; TEST_BEGIN(); puts( "pthread_spin_init( NULL, PTHREAD_PROCESS_PRIVATE ) -- EINVAL" ); status = pthread_spin_init( NULL, PTHREAD_PROCESS_PRIVATE ); rtems_test_assert( status == EINVAL ); puts( "pthread_spin_init( NULL, PTHREAD_PROCESS_SHARED ) -- EINVAL" ); status = pthread_spin_init( NULL, PTHREAD_PROCESS_PRIVATE ); rtems_test_assert( status == EINVAL ); puts( "pthread_spin_init( &spinlock, 0x1234 ) -- EINVAL" ); status = pthread_spin_init( &spinlock, 0x1234 ); rtems_test_assert( status == EINVAL ); puts( "pthread_spin_init( &spinlock, PTHREAD_PROCESS_SHARED ) -- EINVAL" ); status = pthread_spin_init( &spinlock, PTHREAD_PROCESS_SHARED ); rtems_test_assert( status == EINVAL ); /* This successfully creates one */ puts( "pthread_spin_init( &Spinlock, PTHREAD_PROCESS_PRIVATE ) -- OK" ); status = pthread_spin_init( &Spinlock, PTHREAD_PROCESS_PRIVATE ); rtems_test_assert( status == 0 ); puts( "pthread_spin_init( &spinlock, PTHREAD_PROCESS_PRIVATE ) -- EAGAIN" ); status = pthread_spin_init( &spinlock, PTHREAD_PROCESS_PRIVATE ); rtems_test_assert( status == EAGAIN ); puts( "pthread_spin_init( &spinlock, PTHREAD_PROCESS_PRIVATE ) -- EAGAIN" ); status = pthread_spin_init( &spinlock, PTHREAD_PROCESS_PRIVATE ); rtems_test_assert( status == EAGAIN ); puts( "pthread_spin_lock( NULL ) -- EINVAL" ); status = pthread_spin_lock( NULL ); rtems_test_assert( status == EINVAL ); puts( "pthread_spin_trylock( NULL ) -- EINVAL" ); status = pthread_spin_trylock( NULL ); rtems_test_assert( status == EINVAL ); puts( "pthread_spin_unlock( NULL ) -- EINVAL" ); status = pthread_spin_unlock( NULL ); rtems_test_assert( status == EINVAL ); puts( "pthread_spin_destroy( NULL ) -- EINVAL" ); status = pthread_spin_destroy( NULL ); rtems_test_assert( status == EINVAL ); spinlock = 0; puts( "pthread_spin_lock( &spinlock ) -- EINVAL" ); status = pthread_spin_lock( &spinlock ); rtems_test_assert( status == EINVAL ); puts( "pthread_spin_trylock( &spinlock ) -- EINVAL" ); status = pthread_spin_trylock( &spinlock ); rtems_test_assert( status == EINVAL ); puts( "pthread_spin_unlock( &spinlock ) -- EINVAL" ); status = pthread_spin_unlock( &spinlock ); rtems_test_assert( status == EINVAL ); puts( "pthread_spin_destroy( &spinlock ) -- EINVAL" ); status = pthread_spin_destroy( &spinlock ); rtems_test_assert( status == EINVAL ); puts( "pthread_spin_unlock( &Spinlock ) -- already unlocked OK" ); status = pthread_spin_unlock( &Spinlock ); rtems_test_assert( status == 0 ); /* Now some basic locking and unlocking with a deadlock verification */ puts( "pthread_spin_lock( &Spinlock ) -- OK" ); status = pthread_spin_lock( &Spinlock ); rtems_test_assert( status == 0 ); puts( "pthread_spin_lock( &Spinlock ) -- EDEADLK" ); status = pthread_spin_lock( &Spinlock ); rtems_test_assert( status == EDEADLK ); puts( "pthread_spin_trylock( &Spinlock ) -- EDEADLK" ); status = pthread_spin_trylock( &Spinlock ); rtems_test_assert( status == EDEADLK ); puts( "pthread_spin_unlock( &Spinlock ) -- OK" ); status = pthread_spin_unlock( &Spinlock ); rtems_test_assert( status == 0 ); /* Try lock/unlock pair */ puts( "pthread_spin_trylock( &Spinlock ) -- OK" ); status = pthread_spin_trylock( &Spinlock ); rtems_test_assert( status == 0 ); puts( "pthread_spin_unlock( &Spinlock ) -- OK" ); status = pthread_spin_unlock( &Spinlock ); rtems_test_assert( status == 0 ); /* Let another thread lock a spinlock and we contend with it */ mainThreadSpinning = 0; /* Create a helper task */ rstatus = rtems_task_create( rtems_build_name( 'S', 'P', 'I', 'N' ), 1, RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES, RTEMS_DEFAULT_ATTRIBUTES, &taskid ); rtems_test_assert( rstatus == RTEMS_SUCCESSFUL ); rstatus = rtems_task_start( taskid, SpinlockThread, 0 ); rtems_test_assert( rstatus == RTEMS_SUCCESSFUL ); /* We should be preempted immediately. The thread is expected to: * + verify we haven't set the main thread spinning flag * + lock the spinlock * + delay */ mainThreadSpinning = 1; puts( "pthread_spin_lock( &Spinlock ) -- OK" ); status = pthread_spin_lock( &Spinlock ); rtems_test_assert( status == 0 ); /* The thread wakes up, unlocks spin lock, and deletes itself. * So when we get back here, about a second has passed and we now * have the spinlock locked. */ /* spin lock should be locked when we return so destroying it gives busy */ puts( "pthread_spin_destroy( &Spinlock ) -- EBUSY" ); status = pthread_spin_destroy( &Spinlock ); rtems_test_assert( status == EBUSY ); /* Unlock it for a normal destroy */ puts( "pthread_spin_unlock( &Spinlock ) -- OK" ); status = pthread_spin_unlock( &Spinlock ); rtems_test_assert( status == 0 ); puts( "pthread_spin_destroy( &Spinlock ) -- OK" ); status = pthread_spin_destroy( &Spinlock ); rtems_test_assert( status == 0 ); /*************** END OF TEST *****************/ TEST_END(); exit(0); }