bluecore/glfw/lib/win32/win32_thread.c

514 lines
14 KiB
C

//========================================================================
// GLFW - An OpenGL framework
// File: win32_thread.c
// Platform: Windows
// 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.
//
//------------------------------------------------------------------------
// $Id: win32_thread.c,v 1.6 2007/03/15 03:20:21 elmindreda Exp $
//========================================================================
#include "internal.h"
//************************************************************************
// This is an implementation of POSIX "compatible" condition variables for
// Win32, as described by Douglas C. Schmidt and Irfan Pyarali:
// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
//************************************************************************
enum {
_GLFW_COND_SIGNAL = 0,
_GLFW_COND_BROADCAST = 1
};
typedef struct {
// Signal and broadcast event HANDLEs
HANDLE events[ 2 ];
// Count of the number of waiters
unsigned int waiters_count;
// Serialize access to <waiters_count>
CRITICAL_SECTION waiters_count_lock;
} _GLFWcond;
//************************************************************************
//**** GLFW internal functions ****
//************************************************************************
//========================================================================
// _glfwNewThread() - This is simply a "wrapper" for calling the user
// thread function.
//========================================================================
DWORD WINAPI _glfwNewThread( LPVOID lpParam )
{
GLFWthreadfun threadfun;
_GLFWthread *t;
// Get pointer to thread information for current thread
t = _glfwGetThreadPointer( _glfwPlatformGetThreadID() );
if( t == NULL )
{
return 0;
}
// Get user thread function pointer
threadfun = t->Function;
// Call the user thread function
threadfun( (void *) lpParam );
// Remove thread from thread list
ENTER_THREAD_CRITICAL_SECTION
_glfwRemoveThread( t );
LEAVE_THREAD_CRITICAL_SECTION
// When the thread function returns, the thread will die...
return 0;
}
//************************************************************************
//**** GLFW user functions ****
//************************************************************************
//========================================================================
// _glfwPlatformCreateThread() - Create a new thread
//========================================================================
GLFWthread _glfwPlatformCreateThread( GLFWthreadfun fun, void *arg )
{
GLFWthread ID;
_GLFWthread *t, *t_tmp;
HANDLE hThread;
DWORD dwThreadId;
// 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->Function = fun;
t->ID = ID;
// Create thread
hThread = CreateThread(
NULL, // Default security attributes
0, // Default stack size (1 MB)
_glfwNewThread, // Thread function (a wrapper function)
(LPVOID)arg, // Argument to thread is the user argument
0, // Default creation flags
&dwThreadId // Returned thread identifier
);
// Did the thread creation fail?
if( hThread == NULL )
{
free( (void *) t );
LEAVE_THREAD_CRITICAL_SECTION
return -1;
}
// Store more thread information in the thread list
t->Handle = hThread;
t->WinID = dwThreadId;
// Append thread to thread list
t_tmp = &_glfwThrd.First;
while( t_tmp->Next != NULL )
{
t_tmp = t_tmp->Next;
}
t_tmp->Next = t;
t->Previous = t_tmp;
t->Next = NULL;
// 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;
// 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!
if( TerminateThread( t->Handle, 0 ) )
{
// Close thread handle
CloseHandle( t->Handle );
// Remove thread from thread list
_glfwRemoveThread( t );
}
// Leave critical section
LEAVE_THREAD_CRITICAL_SECTION
}
//========================================================================
// _glfwPlatformWaitThread() - Wait for a thread to die
//========================================================================
int _glfwPlatformWaitThread( GLFWthread ID, int waitmode )
{
DWORD result;
HANDLE hThread;
_GLFWthread *t;
// 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;
}
// Get thread handle
hThread = t->Handle;
// Leave critical section
LEAVE_THREAD_CRITICAL_SECTION
// Wait for thread to die
if( waitmode == GLFW_WAIT )
{
result = WaitForSingleObject( hThread, INFINITE );
}
else if( waitmode == GLFW_NOWAIT )
{
result = WaitForSingleObject( hThread, 0 );
}
else
{
return GL_FALSE;
}
// Did we have a time-out?
if( result == WAIT_TIMEOUT )
{
return GL_FALSE;
}
return GL_TRUE;
}
//========================================================================
// _glfwPlatformGetThreadID() - Return the thread ID for the current
// thread
//========================================================================
GLFWthread _glfwPlatformGetThreadID( void )
{
_GLFWthread *t;
GLFWthread ID = -1;
DWORD WinID;
// Get Windows thread ID
WinID = GetCurrentThreadId();
// Enter critical section (to avoid an inconsistent thread list)
ENTER_THREAD_CRITICAL_SECTION
// Loop through entire list of threads to find the matching Windows
// thread ID
for( t = &_glfwThrd.First; t != NULL; t = t->Next )
{
if( t->WinID == WinID )
{
ID = t->ID;
break;
}
}
// Leave critical section
LEAVE_THREAD_CRITICAL_SECTION
// Return the found GLFW thread identifier
return ID;
}
//========================================================================
// _glfwPlatformCreateMutex() - Create a mutual exclusion object
//========================================================================
GLFWmutex _glfwPlatformCreateMutex( void )
{
CRITICAL_SECTION *mutex;
// Allocate memory for mutex
mutex = (CRITICAL_SECTION *) malloc( sizeof(CRITICAL_SECTION) );
if( !mutex )
{
return NULL;
}
// Initialize mutex
InitializeCriticalSection( mutex );
// Cast to GLFWmutex and return
return (GLFWmutex) mutex;
}
//========================================================================
// glfwDestroyMutex() - Destroy a mutual exclusion object
//========================================================================
void _glfwPlatformDestroyMutex( GLFWmutex mutex )
{
// Destroy mutex
DeleteCriticalSection( (CRITICAL_SECTION *) mutex );
free( mutex );
}
//========================================================================
// _glfwPlatformLockMutex() - Request access to a mutex
//========================================================================
void _glfwPlatformLockMutex( GLFWmutex mutex )
{
// Wait for mutex to be released
EnterCriticalSection( (CRITICAL_SECTION *) mutex );
}
//========================================================================
// _glfwPlatformUnlockMutex() - Release a mutex
//========================================================================
void _glfwPlatformUnlockMutex( GLFWmutex mutex )
{
// Release mutex
LeaveCriticalSection( (CRITICAL_SECTION *) mutex );
}
//========================================================================
// _glfwPlatformCreateCond() - Create a new condition variable object
//========================================================================
GLFWcond _glfwPlatformCreateCond( void )
{
_GLFWcond *cond;
// Allocate memory for condition variable
cond = (_GLFWcond *) malloc( sizeof(_GLFWcond) );
if( !cond )
{
return NULL;
}
// Initialize condition variable
cond->waiters_count = 0;
cond->events[ _GLFW_COND_SIGNAL ] = CreateEvent( NULL, FALSE,
FALSE, NULL );
cond->events[ _GLFW_COND_BROADCAST ] = CreateEvent( NULL, TRUE,
FALSE, NULL );
InitializeCriticalSection( &cond->waiters_count_lock );
// Cast to GLFWcond and return
return (GLFWcond) cond;
}
//========================================================================
// _glfwPlatformDestroyCond() - Destroy a condition variable object
//========================================================================
void _glfwPlatformDestroyCond( GLFWcond cond )
{
// Close the condition variable handles
CloseHandle( ((_GLFWcond *)cond)->events[ _GLFW_COND_SIGNAL ] );
CloseHandle( ((_GLFWcond *)cond)->events[ _GLFW_COND_BROADCAST ] );
// Delete critical section
DeleteCriticalSection( &((_GLFWcond *)cond)->waiters_count_lock );
// Free memory for condition variable
free( (void *) cond );
}
//========================================================================
// _glfwPlatformWaitCond() - Wait for a condition to be raised
//========================================================================
void _glfwPlatformWaitCond( GLFWcond cond, GLFWmutex mutex,
double timeout )
{
_GLFWcond *cv = (_GLFWcond *) cond;
int result, last_waiter;
DWORD timeout_ms;
// Avoid race conditions
EnterCriticalSection( &cv->waiters_count_lock );
cv->waiters_count ++;
LeaveCriticalSection( &cv->waiters_count_lock );
// It's ok to release the mutex here since Win32 manual-reset events
// maintain state when used with SetEvent()
LeaveCriticalSection( (CRITICAL_SECTION *) mutex );
// Translate timeout into milliseconds
if( timeout >= GLFW_INFINITY )
{
timeout_ms = INFINITE;
}
else
{
timeout_ms = (DWORD) (1000.0 * timeout + 0.5);
if( timeout_ms <= 0 )
{
timeout_ms = 1;
}
}
// Wait for either event to become signaled due to glfwSignalCond or
// glfwBroadcastCond being called
result = WaitForMultipleObjects( 2, cv->events, FALSE, timeout_ms );
// Check if we are the last waiter
EnterCriticalSection( &cv->waiters_count_lock );
cv->waiters_count --;
last_waiter = (result == WAIT_OBJECT_0 + _GLFW_COND_BROADCAST) &&
(cv->waiters_count == 0);
LeaveCriticalSection( &cv->waiters_count_lock );
// Some thread called glfwBroadcastCond
if( last_waiter )
{
// We're the last waiter to be notified or to stop waiting, so
// reset the manual event
ResetEvent( cv->events[ _GLFW_COND_BROADCAST ] );
}
// Reacquire the mutex
EnterCriticalSection( (CRITICAL_SECTION *) mutex );
}
//========================================================================
// _glfwPlatformSignalCond() - Signal a condition to one waiting thread
//========================================================================
void _glfwPlatformSignalCond( GLFWcond cond )
{
_GLFWcond *cv = (_GLFWcond *) cond;
int have_waiters;
// Avoid race conditions
EnterCriticalSection( &cv->waiters_count_lock );
have_waiters = cv->waiters_count > 0;
LeaveCriticalSection( &cv->waiters_count_lock );
if( have_waiters )
{
SetEvent( cv->events[ _GLFW_COND_SIGNAL ] );
}
}
//========================================================================
// _glfwPlatformBroadcastCond() - Broadcast a condition to all waiting
// threads
//========================================================================
void _glfwPlatformBroadcastCond( GLFWcond cond )
{
_GLFWcond *cv = (_GLFWcond *) cond;
int have_waiters;
// Avoid race conditions
EnterCriticalSection( &cv->waiters_count_lock );
have_waiters = cv->waiters_count > 0;
LeaveCriticalSection( &cv->waiters_count_lock );
if( have_waiters )
{
SetEvent( cv->events[ _GLFW_COND_BROADCAST ] );
}
}
//========================================================================
// _glfwPlatformGetNumberOfProcessors() - Return the number of processors
// in the system.
//========================================================================
int _glfwPlatformGetNumberOfProcessors( void )
{
SYSTEM_INFO si;
// Get hardware system information
GetSystemInfo( &si );
return (int) si.dwNumberOfProcessors;
}