From dae517d2508690cfa5db2db7a3fe92b9fd91c91d Mon Sep 17 00:00:00 2001 From: Steve Checkoway Date: Fri, 27 Jan 2006 07:33:11 +0000 Subject: [PATCH] Make sure that the run loop runs until the input handler terminates by adding a run loop source. --- .../arch/InputHandler/InputHandler_Carbon.cpp | 38 +++++++++++++++---- .../arch/InputHandler/InputHandler_Carbon.h | 1 + 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/stepmania/src/arch/InputHandler/InputHandler_Carbon.cpp b/stepmania/src/arch/InputHandler/InputHandler_Carbon.cpp index 814cdb07de..dc92a6ac0d 100644 --- a/stepmania/src/arch/InputHandler/InputHandler_Carbon.cpp +++ b/stepmania/src/arch/InputHandler/InputHandler_Carbon.cpp @@ -47,12 +47,32 @@ int InputHandler_Carbon::Run( void *data ) This->StartDevices(); SetThreadPrecedence( 1.0f ); - /* The function copies the information out of the structure, so the memory pointed - * to by context does not need to persist beyond the function call. */ - CFRunLoopObserverContext context = { 0, &This->m_Sem, NULL, NULL, NULL }; - CFRunLoopObserverRef o = CFRunLoopObserverCreate( kCFAllocatorDefault, kCFRunLoopEntry, - false, 0, RunLoopStarted, &context); - CFRunLoopAddObserver( This->m_LoopRef, o, kCFRunLoopDefaultMode ); + // Add an observer for the start of the run loop + { + /* The function copies the information out of the structure, so the memory pointed + * to by context does not need to persist beyond the function call. */ + CFRunLoopObserverContext context = { 0, &This->m_Sem, NULL, NULL, NULL }; + CFRunLoopObserverRef o = CFRunLoopObserverCreate( kCFAllocatorDefault, kCFRunLoopEntry, + false, 0, RunLoopStarted, &context); + CFRunLoopAddObserver( This->m_LoopRef, o, kCFRunLoopDefaultMode ); + } + + /* Add a source for ending the run loop. This serves two purposes: + * 1. it provides a way to terminate the run loop when IH_Carbon exists, and + * 2. it ensures that CFRunLoopRun() doesn't return immediately if there are no other sources. */ + { + /* Being a little tricky here, the perform callback takes a void* and returns nothing. + * CFRunLoopStop takes a CFRunLoopRef (a pointer) so cast the function and pass the loop ref. */ + void *info = This->m_LoopRef; + void (*perform)(void *) = (void (*)(void *))CFRunLoopStop; + // { version, info, retain, release, copyDescription, equal, hash, schedule, cancel, perform } + CFRunLoopSourceContext context = { 0, info, NULL, NULL, NULL, NULL, NULL, NULL, NULL, perform }; + + // Pass 1 so that it is called after all inputs have been handled (they will have order = 0) + This->m_SourceRef = CFRunLoopSourceCreate( kCFAllocatorDefault, 1, &context ); + + CFRunLoopAddSource( This->m_LoopRef, This->m_SourceRef, kCFRunLoopDefaultMode ); + } CFRunLoopRun(); LOG->Trace( "Shutting down input handler thread..." ); return 0; @@ -74,9 +94,11 @@ InputHandler_Carbon::~InputHandler_Carbon() delete *i; if( PREFSMAN->m_bThreadedInput ) { - CFRunLoopStop( m_LoopRef ); - CFRelease( m_LoopRef ); + CFRunLoopSourceSignal( m_SourceRef ); + CFRunLoopWakeUp( m_LoopRef ); m_InputThread.Wait(); + CFRelease( m_SourceRef ); + // Don't release the loop ref. LOG->Trace( "Input handler thread shut down." ); } } diff --git a/stepmania/src/arch/InputHandler/InputHandler_Carbon.h b/stepmania/src/arch/InputHandler/InputHandler_Carbon.h index 47cec7d623..b6f2e644b4 100644 --- a/stepmania/src/arch/InputHandler/InputHandler_Carbon.h +++ b/stepmania/src/arch/InputHandler/InputHandler_Carbon.h @@ -15,6 +15,7 @@ private: RageThread m_InputThread; RageSemaphore m_Sem; CFRunLoopRef m_LoopRef; + CFRunLoopSourceRef m_SourceRef; static int Run( void *data ); void StartDevices();