508 lines
13 KiB
C
508 lines
13 KiB
C
|
//========================================================================
|
||
|
// GLFW - An OpenGL framework
|
||
|
// File: x11_thread.c
|
||
|
// Platform: X11 (Unix)
|
||
|
// 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 ****
|
||
|
//************************************************************************
|
||
|
|
||
|
#ifdef _GLFW_HAS_PTHREAD
|
||
|
|
||
|
//========================================================================
|
||
|
// _glfwNewThread() - This is simply a "wrapper" for calling the user
|
||
|
// thread function.
|
||
|
//========================================================================
|
||
|
|
||
|
void * _glfwNewThread( void * arg )
|
||
|
{
|
||
|
GLFWthreadfun threadfun;
|
||
|
_GLFWthread *t;
|
||
|
pthread_t posixID;
|
||
|
|
||
|
// Get current thread ID
|
||
|
posixID = pthread_self();
|
||
|
|
||
|
// Enter critical section
|
||
|
ENTER_THREAD_CRITICAL_SECTION
|
||
|
|
||
|
// Loop through entire list of threads to find the matching POSIX
|
||
|
// thread ID
|
||
|
for( t = &_glfwThrd.First; t != NULL; t = t->Next )
|
||
|
{
|
||
|
if( t->PosixID == posixID )
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if( t == NULL )
|
||
|
{
|
||
|
LEAVE_THREAD_CRITICAL_SECTION
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// Get user thread function pointer
|
||
|
threadfun = t->Function;
|
||
|
|
||
|
// Leave critical section
|
||
|
LEAVE_THREAD_CRITICAL_SECTION
|
||
|
|
||
|
// Call the user thread function
|
||
|
threadfun( arg );
|
||
|
|
||
|
// 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 NULL;
|
||
|
}
|
||
|
|
||
|
#endif // _GLFW_HAS_PTHREAD
|
||
|
|
||
|
|
||
|
|
||
|
//************************************************************************
|
||
|
//**** Platform implementation functions ****
|
||
|
//************************************************************************
|
||
|
|
||
|
//========================================================================
|
||
|
// _glfwPlatformCreateThread() - Create a new thread
|
||
|
//========================================================================
|
||
|
|
||
|
GLFWthread _glfwPlatformCreateThread( GLFWthreadfun fun, void *arg )
|
||
|
{
|
||
|
#ifdef _GLFW_HAS_PTHREAD
|
||
|
|
||
|
GLFWthread ID;
|
||
|
_GLFWthread *t;
|
||
|
int result;
|
||
|
|
||
|
// 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
|
||
|
result = pthread_create(
|
||
|
&t->PosixID, // Thread handle
|
||
|
NULL, // Default thread attributes
|
||
|
_glfwNewThread, // Thread function (a wrapper function)
|
||
|
(void *)arg // Argument to thread is user argument
|
||
|
);
|
||
|
|
||
|
// Did the thread creation fail?
|
||
|
if( result != 0 )
|
||
|
{
|
||
|
free( (void *) t );
|
||
|
LEAVE_THREAD_CRITICAL_SECTION
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// Append thread to thread list
|
||
|
_glfwAppendThread( t );
|
||
|
|
||
|
// Leave critical section
|
||
|
LEAVE_THREAD_CRITICAL_SECTION
|
||
|
|
||
|
// Return the GLFW thread ID
|
||
|
return ID;
|
||
|
|
||
|
#else
|
||
|
|
||
|
return -1;
|
||
|
|
||
|
#endif // _GLFW_HAS_PTHREAD
|
||
|
}
|
||
|
|
||
|
|
||
|
//========================================================================
|
||
|
// _glfwPlatformDestroyThread() - Kill a thread. NOTE: THIS IS A VERY
|
||
|
// DANGEROUS OPERATION, AND SHOULD NOT BE USED EXCEPT IN EXTREME
|
||
|
// SITUATIONS!
|
||
|
//========================================================================
|
||
|
|
||
|
void _glfwPlatformDestroyThread( GLFWthread ID )
|
||
|
{
|
||
|
#ifdef _GLFW_HAS_PTHREAD
|
||
|
|
||
|
_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!
|
||
|
pthread_kill( t->PosixID, SIGKILL );
|
||
|
|
||
|
// Remove thread from thread list
|
||
|
_glfwRemoveThread( t );
|
||
|
|
||
|
// Leave critical section
|
||
|
LEAVE_THREAD_CRITICAL_SECTION
|
||
|
|
||
|
#endif // _GLFW_HAS_PTHREAD
|
||
|
}
|
||
|
|
||
|
|
||
|
//========================================================================
|
||
|
// _glfwPlatformWaitThread() - Wait for a thread to die
|
||
|
//========================================================================
|
||
|
|
||
|
int _glfwPlatformWaitThread( GLFWthread ID, int waitmode )
|
||
|
{
|
||
|
#ifdef _GLFW_HAS_PTHREAD
|
||
|
|
||
|
pthread_t thread;
|
||
|
_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;
|
||
|
}
|
||
|
|
||
|
// If got this far, the thread is alive => polling returns FALSE
|
||
|
if( waitmode == GLFW_NOWAIT )
|
||
|
{
|
||
|
LEAVE_THREAD_CRITICAL_SECTION
|
||
|
return GL_FALSE;
|
||
|
}
|
||
|
|
||
|
// Get thread handle
|
||
|
thread = t->PosixID;
|
||
|
|
||
|
// Leave critical section
|
||
|
LEAVE_THREAD_CRITICAL_SECTION
|
||
|
|
||
|
// Wait for thread to die
|
||
|
(void) pthread_join( thread, NULL );
|
||
|
|
||
|
return GL_TRUE;
|
||
|
|
||
|
#else
|
||
|
|
||
|
return GL_TRUE;
|
||
|
|
||
|
#endif // _GLFW_HAS_PTHREAD
|
||
|
}
|
||
|
|
||
|
|
||
|
//========================================================================
|
||
|
// _glfwPlatformGetThreadID() - Return the thread ID for the current
|
||
|
// thread
|
||
|
//========================================================================
|
||
|
|
||
|
GLFWthread _glfwPlatformGetThreadID( void )
|
||
|
{
|
||
|
#ifdef _GLFW_HAS_PTHREAD
|
||
|
|
||
|
_GLFWthread *t;
|
||
|
GLFWthread ID = -1;
|
||
|
pthread_t posixID;
|
||
|
|
||
|
// Get current thread ID
|
||
|
posixID = pthread_self();
|
||
|
|
||
|
// Enter critical section
|
||
|
ENTER_THREAD_CRITICAL_SECTION
|
||
|
|
||
|
// Loop through entire list of threads to find the matching POSIX
|
||
|
// thread ID
|
||
|
for( t = &_glfwThrd.First; t != NULL; t = t->Next )
|
||
|
{
|
||
|
if( t->PosixID == posixID )
|
||
|
{
|
||
|
ID = t->ID;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Leave critical section
|
||
|
LEAVE_THREAD_CRITICAL_SECTION
|
||
|
|
||
|
// Return the found GLFW thread identifier
|
||
|
return ID;
|
||
|
|
||
|
#else
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
#endif // _GLFW_HAS_PTHREAD
|
||
|
}
|
||
|
|
||
|
|
||
|
//========================================================================
|
||
|
// _glfwPlatformCreateMutex() - Create a mutual exclusion object
|
||
|
//========================================================================
|
||
|
|
||
|
GLFWmutex _glfwPlatformCreateMutex( void )
|
||
|
{
|
||
|
#ifdef _GLFW_HAS_PTHREAD
|
||
|
|
||
|
pthread_mutex_t *mutex;
|
||
|
|
||
|
// Allocate memory for mutex
|
||
|
mutex = (pthread_mutex_t *) malloc( sizeof( pthread_mutex_t ) );
|
||
|
if( !mutex )
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// Initialise a mutex object
|
||
|
(void) pthread_mutex_init( mutex, NULL );
|
||
|
|
||
|
// Cast to GLFWmutex and return
|
||
|
return (GLFWmutex) mutex;
|
||
|
|
||
|
#else
|
||
|
|
||
|
return (GLFWmutex) 0;
|
||
|
|
||
|
#endif // _GLFW_HAS_PTHREAD
|
||
|
}
|
||
|
|
||
|
|
||
|
//========================================================================
|
||
|
// _glfwPlatformDestroyMutex() - Destroy a mutual exclusion object
|
||
|
//========================================================================
|
||
|
|
||
|
void _glfwPlatformDestroyMutex( GLFWmutex mutex )
|
||
|
{
|
||
|
#ifdef _GLFW_HAS_PTHREAD
|
||
|
|
||
|
// Destroy the mutex object
|
||
|
pthread_mutex_destroy( (pthread_mutex_t *) mutex );
|
||
|
|
||
|
// Free memory for mutex object
|
||
|
free( (void *) mutex );
|
||
|
|
||
|
#endif // _GLFW_HAS_PTHREAD
|
||
|
}
|
||
|
|
||
|
|
||
|
//========================================================================
|
||
|
// _glfwPlatformLockMutex() - Request access to a mutex
|
||
|
//========================================================================
|
||
|
|
||
|
void _glfwPlatformLockMutex( GLFWmutex mutex )
|
||
|
{
|
||
|
#ifdef _GLFW_HAS_PTHREAD
|
||
|
|
||
|
// Wait for mutex to be released
|
||
|
(void) pthread_mutex_lock( (pthread_mutex_t *) mutex );
|
||
|
|
||
|
#endif // _GLFW_HAS_PTHREAD
|
||
|
}
|
||
|
|
||
|
|
||
|
//========================================================================
|
||
|
// _glfwPlatformUnlockMutex() - Release a mutex
|
||
|
//========================================================================
|
||
|
|
||
|
void _glfwPlatformUnlockMutex( GLFWmutex mutex )
|
||
|
{
|
||
|
#ifdef _GLFW_HAS_PTHREAD
|
||
|
|
||
|
// Release mutex
|
||
|
pthread_mutex_unlock( (pthread_mutex_t *) mutex );
|
||
|
|
||
|
#endif // _GLFW_HAS_PTHREAD
|
||
|
}
|
||
|
|
||
|
|
||
|
//========================================================================
|
||
|
// _glfwPlatformCreateCond() - Create a new condition variable object
|
||
|
//========================================================================
|
||
|
|
||
|
GLFWcond _glfwPlatformCreateCond( void )
|
||
|
{
|
||
|
#ifdef _GLFW_HAS_PTHREAD
|
||
|
|
||
|
pthread_cond_t *cond;
|
||
|
|
||
|
// Allocate memory for condition variable
|
||
|
cond = (pthread_cond_t *) malloc( sizeof(pthread_cond_t) );
|
||
|
if( !cond )
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// Initialise condition variable
|
||
|
(void) pthread_cond_init( cond, NULL );
|
||
|
|
||
|
// Cast to GLFWcond and return
|
||
|
return (GLFWcond) cond;
|
||
|
|
||
|
#else
|
||
|
|
||
|
return (GLFWcond) 0;
|
||
|
|
||
|
#endif // _GLFW_HAS_PTHREAD
|
||
|
}
|
||
|
|
||
|
|
||
|
//========================================================================
|
||
|
// _glfwPlatformDestroyCond() - Destroy a condition variable object
|
||
|
//========================================================================
|
||
|
|
||
|
void _glfwPlatformDestroyCond( GLFWcond cond )
|
||
|
{
|
||
|
#ifdef _GLFW_HAS_PTHREAD
|
||
|
|
||
|
// Destroy the condition variable object
|
||
|
(void) pthread_cond_destroy( (pthread_cond_t *) cond );
|
||
|
|
||
|
// Free memory for condition variable object
|
||
|
free( (void *) cond );
|
||
|
|
||
|
#endif // _GLFW_HAS_PTHREAD
|
||
|
}
|
||
|
|
||
|
|
||
|
//========================================================================
|
||
|
// _glfwPlatformWaitCond() - Wait for a condition to be raised
|
||
|
//========================================================================
|
||
|
|
||
|
void _glfwPlatformWaitCond( GLFWcond cond, GLFWmutex mutex,
|
||
|
double timeout )
|
||
|
{
|
||
|
#ifdef _GLFW_HAS_PTHREAD
|
||
|
|
||
|
struct timeval currenttime;
|
||
|
struct timespec wait;
|
||
|
long dt_sec, dt_usec;
|
||
|
|
||
|
// Select infinite or timed wait
|
||
|
if( timeout >= GLFW_INFINITY )
|
||
|
{
|
||
|
// Wait for condition (infinite wait)
|
||
|
(void) pthread_cond_wait( (pthread_cond_t *) cond,
|
||
|
(pthread_mutex_t *) mutex );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Set timeout time, relatvie to current time
|
||
|
gettimeofday( ¤ttime, NULL );
|
||
|
dt_sec = (long) timeout;
|
||
|
dt_usec = (long) ((timeout - (double)dt_sec) * 1000000.0);
|
||
|
wait.tv_nsec = (currenttime.tv_usec + dt_usec) * 1000L;
|
||
|
if( wait.tv_nsec > 1000000000L )
|
||
|
{
|
||
|
wait.tv_nsec -= 1000000000L;
|
||
|
dt_sec ++;
|
||
|
}
|
||
|
wait.tv_sec = currenttime.tv_sec + dt_sec;
|
||
|
|
||
|
// Wait for condition (timed wait)
|
||
|
(void) pthread_cond_timedwait( (pthread_cond_t *) cond,
|
||
|
(pthread_mutex_t *) mutex, &wait );
|
||
|
}
|
||
|
|
||
|
#endif // _GLFW_HAS_PTHREAD
|
||
|
}
|
||
|
|
||
|
|
||
|
//========================================================================
|
||
|
// _glfwPlatformSignalCond() - Signal a condition to one waiting thread
|
||
|
//========================================================================
|
||
|
|
||
|
void _glfwPlatformSignalCond( GLFWcond cond )
|
||
|
{
|
||
|
#ifdef _GLFW_HAS_PTHREAD
|
||
|
|
||
|
// Signal condition
|
||
|
(void) pthread_cond_signal( (pthread_cond_t *) cond );
|
||
|
|
||
|
#endif // _GLFW_HAS_PTHREAD
|
||
|
}
|
||
|
|
||
|
|
||
|
//========================================================================
|
||
|
// _glfwPlatformBroadcastCond() - Broadcast a condition to all waiting
|
||
|
// threads
|
||
|
//========================================================================
|
||
|
|
||
|
void _glfwPlatformBroadcastCond( GLFWcond cond )
|
||
|
{
|
||
|
#ifdef _GLFW_HAS_PTHREAD
|
||
|
|
||
|
// Broadcast condition
|
||
|
(void) pthread_cond_broadcast( (pthread_cond_t *) cond );
|
||
|
|
||
|
#endif // _GLFW_HAS_PTHREAD
|
||
|
}
|
||
|
|
||
|
|
||
|
//========================================================================
|
||
|
// _glfwPlatformGetNumberOfProcessors() - Return the number of processors
|
||
|
// in the system.
|
||
|
//========================================================================
|
||
|
|
||
|
int _glfwPlatformGetNumberOfProcessors( void )
|
||
|
{
|
||
|
int n;
|
||
|
|
||
|
// Get number of processors online
|
||
|
_glfw_numprocessors( n );
|
||
|
return n;
|
||
|
}
|