//======================================================================== // GLFW - An OpenGL framework // File: amigaos_thread.c // Platforms: AmigaOS, MorphOS // API version: 2.6 // WWW: http://glfw.sourceforge.net //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Camilla Berglund // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would // be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not // be misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. // //======================================================================== #include "internal.h" //************************************************************************ //**** GLFW internal functions **** //************************************************************************ //======================================================================== // _glfwNewThread() - This is simply a "wrapper" for calling the user // thread function. //======================================================================== int _glfwNewThread( void ) { GLFWthreadfun threadfun; void *arg; _GLFWthread *t, *t_wait; struct Task *amiTask; int waitSig; // Allocate a signal to use for waiting (glfwWaitThread and // glfwWaitCond) waitSig = AllocSignal( -1 ); if( waitSig == -1 ) { // If we could not get a signal (VERY UNLIKELY), exit immediately return 0; } // Get current task amiTask = FindTask( NULL ); // Enter critical section ENTER_THREAD_CRITICAL_SECTION // The task's user data points to the GLFW thread struct t = (_GLFWthread *) amiTask->tc_UserData; // Store wait signal handle t->WaitSig = waitSig; t->WaitFor = NULL; // Get user thread function pointer and argument threadfun = t->Function; arg = t->Arg; // Leave critical section LEAVE_THREAD_CRITICAL_SECTION // Call the user thread function threadfun( arg ); ENTER_THREAD_CRITICAL_SECTION // Remove thread from thread list _glfwRemoveThread( t ); // Signal any waiting threads that we have died for( t_wait = &_glfwThrd.First; t_wait; t_wait = t_wait->Next ) { if( t_wait->WaitFor == (void *) t ) { Signal( t_wait->AmiTask, 1L<WaitSig ); t_wait->WaitFor = NULL; } } LEAVE_THREAD_CRITICAL_SECTION // When the process function returns, the process will die... return 0; } //************************************************************************ //**** Platform implementation functions **** //************************************************************************ //======================================================================== // _glfwPlatformCreateThread() - Create a new thread //======================================================================== GLFWthread _glfwPlatformCreateThread( GLFWthreadfun fun, void *arg ) { GLFWthread ID; _GLFWthread *t; struct TagItem tagList[ 10 ]; int tagNR; // Enter critical section ENTER_THREAD_CRITICAL_SECTION // Create a new thread information memory area t = (_GLFWthread *) malloc( sizeof(_GLFWthread) ); if( t == NULL ) { // Leave critical section LEAVE_THREAD_CRITICAL_SECTION return -1; } // Get a new unique thread id ID = _glfwThrd.NextID ++; // Store thread information in the thread list t->ID = ID; t->Function = fun; t->Arg = arg; #ifdef _GLFW_MORPHOS // For MorphOS, we set up a 68k -> PPC switch trap instruction. // CreateNewProc actually creates a 68k process (emulated), so we make // sure that the first 68k instruction that is executed is a trap // instruction that forces the execution model to change from emulated // 68k to native PPC (and starts execution at _glfwNewThread). t->mosEmulLibEntry.Trap = TRAP_LIB; t->mosEmulLibEntry.Extension = 0; t->mosEmulLibEntry.Func = _glfwNewThread; #endif // Create new process tagNR = 0; tagList[ tagNR ].ti_Tag = NP_Entry; #ifdef _GLFW_MORPHOS tagList[ tagNR++ ].ti_Data = (ULONG) &t->mosEmulLibEntry; #else tagList[ tagNR++ ].ti_Data = (ULONG) _glfwNewThread; #endif tagList[ tagNR ].ti_Tag = NP_StackSize; tagList[ tagNR++ ].ti_Data = _GLFW_TASK_STACK_SIZE; tagList[ tagNR ].ti_Tag = NP_Input; tagList[ tagNR++ ].ti_Data = (ULONG) Input(); tagList[ tagNR ].ti_Tag = NP_Output; tagList[ tagNR++ ].ti_Data = (ULONG) Output(); tagList[ tagNR ].ti_Tag = NP_CloseInput; tagList[ tagNR++ ].ti_Data = FALSE; tagList[ tagNR ].ti_Tag = NP_CloseOutput; tagList[ tagNR++ ].ti_Data = FALSE; tagList[ tagNR ].ti_Tag = TAG_DONE; t->AmiProc = CreateNewProc( tagList ); // Did the process creation fail? if( !t->AmiProc ) { free( (void *) t ); LEAVE_THREAD_CRITICAL_SECTION return -1; } // Get pointer to task structure t->AmiTask = &(t->AmiProc->pr_Task); // Store GLFW thread struct pointer in task user data t->AmiTask->tc_UserData = (APTR) t; // Append thread to thread list _glfwAppendThread( t ); // Leave critical section LEAVE_THREAD_CRITICAL_SECTION // Return the GLFW thread ID return ID; } //======================================================================== // _glfwPlatformDestroyThread() - Kill a thread. NOTE: THIS IS A VERY // DANGEROUS OPERATION, AND SHOULD NOT BE USED EXCEPT IN EXTREME // SITUATIONS! //======================================================================== void _glfwPlatformDestroyThread( GLFWthread ID ) { _GLFWthread *t, *t_wait; // Enter critical section ENTER_THREAD_CRITICAL_SECTION // Get thread information pointer t = _glfwGetThreadPointer( ID ); if( t == NULL ) { LEAVE_THREAD_CRITICAL_SECTION return; } // Simply murder the process, no mercy! // ?? How about Process resources ?? RemTask( t->AmiTask ); // Remove thread from thread list _glfwRemoveThread( t ); // Signal any waiting threads that the thread has died for( t_wait = &_glfwThrd.First; t_wait; t_wait = t_wait->Next ) { if( t_wait->WaitFor == (void *) t ) { Signal( t_wait->AmiTask, 1L<WaitSig ); t_wait->WaitFor = NULL; } } // Leave critical section LEAVE_THREAD_CRITICAL_SECTION } //======================================================================== // _glfwPlatformWaitThread() - Wait for a thread to die //======================================================================== int _glfwPlatformWaitThread( GLFWthread ID, int waitmode ) { struct Task *amiTask; _GLFWthread *t, *t_this; int waitSig; // Enter critical section ENTER_THREAD_CRITICAL_SECTION // Get thread information pointer t = _glfwGetThreadPointer( ID ); // Is the thread already dead? if( t == NULL ) { LEAVE_THREAD_CRITICAL_SECTION return GL_TRUE; } // If got this far, the thread is alive => polling returns FALSE if( waitmode == GLFW_NOWAIT ) { LEAVE_THREAD_CRITICAL_SECTION return GL_FALSE; } // Find pointer to this threads structure amiTask = FindTask( NULL ); t_this = (_GLFWthread *) amiTask->tc_UserData; // Store information in our thread structure that we want to wait for // the specified thread to die t_this->WaitFor = (void *) t; waitSig = t_this->WaitSig; // Leave critical section LEAVE_THREAD_CRITICAL_SECTION // Wait for thread to die Wait( 1L<tc_UserData; // Return the found GLFW thread identifier return t->ID; } //======================================================================== // _glfwPlatformCreateMutex() - Create a mutual exclusion object //======================================================================== GLFWmutex _glfwPlatformCreateMutex( void ) { struct SignalSemaphore *mutex; // Allocate memory for mutex mutex = (struct SignalSemaphore *) malloc( sizeof(struct SignalSemaphore) ); if( !mutex ) { return NULL; } // Initialize mutex object memset( mutex, 0, sizeof(struct SignalSemaphore) ); InitSemaphore( mutex ); // Cast to GLFWmutex and return return (GLFWmutex) mutex; } //======================================================================== // _glfwPlatformDestroyMutex() - Destroy a mutual exclusion object //======================================================================== void _glfwPlatformDestroyMutex( GLFWmutex mutex ) { // Free memory for mutex object free( (void *) mutex ); } //======================================================================== // _glfwPlatformLockMutex() - Request access to a mutex //======================================================================== void _glfwPlatformLockMutex( GLFWmutex mutex ) { // Wait for mutex to be released ObtainSemaphore( (struct SignalSemaphore *) mutex ); } //======================================================================== // _glfwPlatformUnlockMutex() - Release a mutex //======================================================================== void _glfwPlatformUnlockMutex( GLFWmutex mutex ) { // Release mutex ReleaseSemaphore( (struct SignalSemaphore *) mutex ); } //======================================================================== // _glfwPlatformCreateCond() - Create a new condition variable object //======================================================================== GLFWcond _glfwPlatformCreateCond( void ) { unsigned int cond; // Generate a new unique cond ID ENTER_THREAD_CRITICAL_SECTION cond = _glfwThrd.NextCondID --; LEAVE_THREAD_CRITICAL_SECTION // Cast to GLFWcond and return return (GLFWcond) cond; } //======================================================================== // _glfwPlatformDestroyCond() - Destroy a condition variable object //======================================================================== void _glfwPlatformDestroyCond( GLFWcond cond ) { } //======================================================================== // _glfwPlatformWaitCond() - Wait for a condition to be raised //======================================================================== void _glfwPlatformWaitCond( GLFWcond cond, GLFWmutex mutex, double timeout ) { struct Task *amiTask; _GLFWthread *t_this; // Do we need a limited timeout? if( timeout < GLFW_INFINITY ) { // Oooops! Not implemented properly yet! ReleaseSemaphore( (struct SignalSemaphore *) mutex ); Delay( 1 ); ObtainSemaphore( (struct SignalSemaphore *) mutex ); return; } // Find pointer to this threads structure amiTask = FindTask( NULL ); t_this = (_GLFWthread *) amiTask->tc_UserData; // Store information in our thread structure that we want to wait for // the specified condition variable to be signaled ENTER_THREAD_CRITICAL_SECTION t_this->WaitFor = (void *) cond; LEAVE_THREAD_CRITICAL_SECTION // Release the mutex ReleaseSemaphore( (struct SignalSemaphore *) mutex ); // Wait for condition variable Wait( 1L<<(t_this->WaitSig) ); // Reacquire the mutex ObtainSemaphore( (struct SignalSemaphore *) mutex ); } //======================================================================== // _glfwPlatformSignalCond() - Signal a condition to one waiting thread //======================================================================== void _glfwPlatformSignalCond( GLFWcond cond ) { _GLFWthread *t_wait; // Broadcast condition to one waiting thread ENTER_THREAD_CRITICAL_SECTION for( t_wait = &_glfwThrd.First; t_wait; t_wait = t_wait->Next ) { if( t_wait->WaitFor == (void *) cond ) { Signal( t_wait->AmiTask, 1L<WaitSig ); t_wait->WaitFor = NULL; break; } } LEAVE_THREAD_CRITICAL_SECTION } //======================================================================== // _glfwPlatformBroadcastCond() - Broadcast a condition to all waiting // threads //======================================================================== void _glfwPlatformBroadcastCond( GLFWcond cond ) { _GLFWthread *t_wait; // Broadcast condition to any waiting threads ENTER_THREAD_CRITICAL_SECTION for( t_wait = &_glfwThrd.First; t_wait; t_wait = t_wait->Next ) { if( t_wait->WaitFor == (void *) cond ) { Signal( t_wait->AmiTask, 1L<WaitSig ); t_wait->WaitFor = NULL; } } LEAVE_THREAD_CRITICAL_SECTION } //======================================================================== // _glfwPlatformGetNumberOfProcessors() - Return the number of processors // in the system. //======================================================================== int _glfwPlatformGetNumberOfProcessors( void ) { // Return number of processors online (MorphOS has SMP support, so we // should do something useful here...) return 1; }