From 8cb671ee3d027504cb788b803aa9fb538373ab07 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Fri, 12 Mar 2004 05:27:27 +0000 Subject: [PATCH] add test_threads --- stepmania/src/tests/test_threads.cpp | 248 +++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 stepmania/src/tests/test_threads.cpp diff --git a/stepmania/src/tests/test_threads.cpp b/stepmania/src/tests/test_threads.cpp new file mode 100644 index 0000000000..549acf1502 --- /dev/null +++ b/stepmania/src/tests/test_threads.cpp @@ -0,0 +1,248 @@ +#include "global.h" +#include "RageLog.h" +#include "RageUtil.h" +#include "RageThreads.h" +#include "archutils/Unix/Backtrace.h" +#include "archutils/Unix/BacktraceNames.h" +#include "test_misc.h" + +#include +#include "archutils/Unix/LinuxThreadHelpers.h" + +/* These are volatile, so writes to them aren't optimized. */ +volatile int g_ThreadId = -1; +volatile int g_Counter = 0; +volatile bool g_Finish = false; + +void TestSuspendIncrLoop() +{ + while( !g_Finish ) + ++g_Counter; +} + +int TestSuspendThread( void *p ) +{ + printf("Test thread started\n"); + + g_ThreadId = GetCurrentThreadId(); + TestSuspendIncrLoop(); + + return 0; +} + +void test_suspend_threadid( int ThreadId ) +{ + /* Wait for g_Counter to increment a bit. */ + usleep( 100000 ); + + /* Stop the thread. */ + SuspendThread( ThreadId ); + + int OldCounter = g_Counter; + + /* Wait a while. g_Counter shouldn't change. */ + usleep( 100000 ); + + ASSERT( g_Counter == OldCounter ); + + /* Start it again, and wait. */ + ResumeThread( ThreadId ); + usleep( 100000 ); + + /* g_Counter should change. */ + ASSERT( g_Counter != OldCounter ); + + /* Stop all other threads. */ + RageThread::HaltAllThreads(); + + OldCounter = g_Counter; + + /* Wait a while. g_Counter shouldn't change. */ + usleep( 100000 ); + ASSERT( g_Counter == OldCounter ); + + /* Start it again, and wait. */ + RageThread::ResumeAllThreads(); + usleep( 100000 ); + + /* g_Counter should change. */ + ASSERT( g_Counter != OldCounter ); +} + +/* Test whether suspending a child thread works. */ +void test_suspend_secondary_thread() +{ + ASSERT( !g_Finish ); + ASSERT( g_ThreadId == -1 ); + + RageThread testing; + testing.SetName( "TestSuspend" ); + testing.Create( TestSuspendThread, NULL ); + + while( g_ThreadId == -1 ) + ; + + test_suspend_threadid( g_ThreadId ); + + g_Finish = true; + testing.Wait(); + g_Finish = false; + g_ThreadId = -1; +} + +int TestSuspendMainThread( void *p ) +{ + ASSERT( !g_Finish ); + + printf("Test thread started\n"); + + ASSERT( g_ThreadId != -1 ); + test_suspend_threadid( g_ThreadId ); + g_Finish = true; + + return 0; +} + +/* Test whether suspending the main thread works. */ +void test_suspend_main_thread() +{ + ASSERT( !g_Finish ); + ASSERT( g_ThreadId == -1 ); + + g_ThreadId = GetCurrentThreadId(); + + RageThread testing; + testing.SetName( "TestSuspend" ); + testing.Create( TestSuspendMainThread, NULL ); + + TestSuspendIncrLoop(); + + testing.Wait(); + g_Finish = false; + g_ThreadId = -1; +} + +/* Run a second function, so we have two symbols to search for. */ +void TestBacktraceThreadLoop() __attribute__ ((noinline)); +void TestBacktraceThreadLoop() +{ + g_ThreadId = GetCurrentThreadId(); + while( !g_Finish ) + ; +} + +int TestBacktraceThread( void *p ) __attribute__ ((noinline)); +int TestBacktraceThread( void *p ) +{ + TestBacktraceThreadLoop(); + return 0; +} + +bool test_thread_backtrace( int ThreadId, const void *expect1, const void *expect2 ) +{ + BacktraceContext ctx; + int ret = GetThreadBacktraceContext( ThreadId, &ctx ); + ASSERT( ret == 0 ); + + const void *BacktracePointers[1024]; + GetBacktrace( BacktracePointers, 1024, &ctx ); + + bool bFound1 = false, bFound2 = false; + for( int i = 0; BacktracePointers[i]; ++i) + { + BacktraceNames bn; + bn.FromAddr( BacktracePointers[i] ); + +// printf("want %p, %p: %p, %p\n", expect1, expect2, bn.Address-bn.Offset, BacktracePointers[i] ); +// printf(" %s\n", bn.Format().c_str() ); + + /* bn.Address is the current address; Offset is the distance to the beginning + * of the symbol, so bn.Address-bn.Offset is the actual symbol. */ + if( bn.Address-bn.Offset == (int) expect1 ) + bFound1 = true; + if( bn.Address-bn.Offset == (int) expect2 ) + bFound2 = true; + } + + return bFound1 && bFound2; +} + +void test_backtracing_secondary_thread() +{ + ASSERT( !g_Finish ); + + RageThread testing; + testing.SetName( "TestBacktrace" ); + testing.Create( TestBacktraceThread, NULL ); + + while( g_ThreadId == -1 ) + ; + + if( !test_thread_backtrace( g_ThreadId, (void *) TestBacktraceThread, (void *) TestBacktraceThreadLoop ) ) + { + printf( "test_backtracing_secondary_thread failed\n" ); + exit( 1 ); + } + + g_Finish = true; + testing.Wait(); + g_Finish = false; + g_ThreadId = -1; +} + +int TestBacktraceMainThread( void *p ) +{ + printf("Test thread started\n"); + + while( g_ThreadId == -1 ) + ; + + if( !test_thread_backtrace( g_ThreadId, (void *) TestBacktraceThread, (void *) TestBacktraceThreadLoop ) ) + { + printf( "test_backtracing_main_thread failed\n" ); + exit( 1 ); + } + + g_Finish = true; + + return 0; +} + +void test_backtracing_main_thread() +{ + ASSERT( !g_Finish ); + ASSERT( g_ThreadId == -1 ); + + RageThread testing; + testing.SetName( "TestBacktrace" ); + testing.Create( TestBacktraceMainThread, NULL ); + + TestBacktraceThread( NULL ); + + testing.Wait(); + g_Finish = false; + g_ThreadId = -1; +} + +int main( int argc, char *argv[] ) +{ + test_handle_args( argc, argv ); + + test_init(); + + InitializeBacktrace(); + printf("'%s'\n", ThreadsVersion().c_str()); + + /* Test the main thread suspending a secondary thread, and vice versa. */ + test_suspend_secondary_thread(); + test_suspend_main_thread(); + + /* Test the main thread backtracing a secondary thread, and vice versa. */ + test_backtracing_secondary_thread(); + test_backtracing_main_thread(); + + test_deinit(); + + exit(0); +} +