2017-01-21 17:09:38 -06:00
/* Copyright (C) 2010-2017 The RetroArch team
2011-10-06 20:31:39 +02:00
*
2014-10-21 03:25:59 +02:00
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* The following license statement only applies to this file ( rthreads . c ) .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2011-10-06 20:31:39 +02:00
*
2014-10-21 03:25:59 +02:00
* Permission is hereby granted , free of charge ,
* to any person obtaining a copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation the rights to
* use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies of the Software ,
* and to permit persons to whom the Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR IMPLIED ,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT .
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY ,
* WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
2011-10-06 20:31:39 +02:00
*/
2016-04-05 17:52:23 +02:00
# ifdef __unix__
# define _POSIX_C_SOURCE 199309
# endif
2011-10-06 20:31:39 +02:00
# include <stdlib.h>
2015-12-04 10:33:06 +01:00
# include <boolean.h>
2015-09-05 21:13:58 +02:00
# include <rthreads/rthreads.h>
2016-03-21 05:44:45 +01:00
/* with RETRO_WIN32_USE_PTHREADS, pthreads can be used even on win32. Maybe only supported in MSVC>=2005 */
# if defined(_WIN32) && !defined(RETRO_WIN32_USE_PTHREADS)
# define USE_WIN32_THREADS
2013-04-11 22:35:15 +02:00
# ifdef _XBOX
# include <xtl.h>
# else
2011-10-06 20:31:39 +02:00
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
2013-04-11 22:35:15 +02:00
# endif
2012-08-11 13:33:32 +02:00
# elif defined(GEKKO)
2014-10-21 03:25:59 +02:00
# include "gx_pthread.h"
2016-09-08 16:11:16 +02:00
# elif defined(PSP)
2014-10-21 03:25:59 +02:00
# include "psp_pthread.h"
2016-05-21 13:38:07 +02:00
# elif defined(__CELLOS_LV2__)
# include <pthread.h>
# include <sys/sys_time.h>
2011-10-06 20:31:39 +02:00
# else
# include <pthread.h>
# include <time.h>
# endif
2016-08-19 02:59:25 +02:00
# if defined(VITA)
# include <sys/time.h>
# endif
2016-05-21 13:38:07 +02:00
2011-10-06 20:49:00 +02:00
# ifdef __MACH__
# include <mach/clock.h>
# include <mach/mach.h>
# endif
2011-10-06 22:19:56 +02:00
struct thread_data
{
void ( * func ) ( void * ) ;
void * userdata ;
} ;
struct sthread
{
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2011-10-06 22:19:56 +02:00
HANDLE thread ;
2015-01-08 20:33:20 +01:00
# else
pthread_t id ;
# endif
2011-10-06 22:19:56 +02:00
} ;
2015-01-08 20:33:20 +01:00
struct slock
{
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2017-01-21 17:09:38 -06:00
CRITICAL_SECTION lock ;
2015-01-08 20:33:20 +01:00
# else
pthread_mutex_t lock ;
# endif
} ;
struct scond
{
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2017-01-09 16:46:35 -06:00
/* The syntax we'll use is mind-bending unless we use a struct. Plus, we might want to store more info later */
/* This will be used as a linked list immplementing a queue of waiting threads */
struct QueueEntry
{
2017-01-21 16:49:10 -06:00
struct QueueEntry * next ;
2017-01-09 16:46:35 -06:00
} ;
/* With this implementation of scond, we don't have any way of waking (or even identifying) specific threads */
/* But we need to wake them in the order indicated by the queue. */
/* This potato token will get get passed around every waiter. The bearer can test whether he's next, and hold onto the potato if he is. */
/* When he's done he can then put it back into play to progress the queue further */
HANDLE hot_potato ;
/* The primary signalled event. Hot potatoes are passed until this is set. */
2017-01-21 16:49:10 -06:00
HANDLE event ;
2017-01-09 16:46:35 -06:00
/* the head of the queue; NULL if queue is empty */
2017-01-21 16:49:10 -06:00
struct QueueEntry * head ;
2017-01-09 16:46:35 -06:00
/* equivalent to the queue length */
2017-01-21 16:49:10 -06:00
int waiters ;
2017-01-09 16:46:35 -06:00
/* how many waiters in the queue have been conceptually wakened by signals (even if we haven't managed to actually wake them yet */
2017-01-21 16:49:10 -06:00
int wakens ;
2017-01-09 16:46:35 -06:00
2017-01-21 22:44:31 -06:00
/* used to control access to this scond, in case the user fails */
CRITICAL_SECTION cs ;
2015-01-08 20:33:20 +01:00
# else
pthread_cond_t cond ;
# endif
} ;
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2011-10-06 22:19:56 +02:00
static DWORD CALLBACK thread_wrap ( void * data_ )
2015-01-08 20:33:20 +01:00
# else
static void * thread_wrap ( void * data_ )
# endif
2011-10-06 22:19:56 +02:00
{
2011-12-24 13:46:12 +01:00
struct thread_data * data = ( struct thread_data * ) data_ ;
2016-07-04 11:39:20 +02:00
if ( ! data )
2015-04-26 05:35:41 +02:00
return 0 ;
2016-07-06 13:21:08 +02:00
data - > func ( data - > userdata ) ;
2011-10-06 22:19:56 +02:00
free ( data ) ;
return 0 ;
}
2015-01-08 21:23:34 +01:00
/**
* sthread_create :
* @ start_routine : thread entry callback function
* @ userdata : pointer to userdata that will be made
* available in thread entry callback function
*
* Create a new thread .
*
* Returns : pointer to new thread if successful , otherwise NULL .
*/
2011-10-06 22:19:56 +02:00
sthread_t * sthread_create ( void ( * thread_func ) ( void * ) , void * userdata )
{
2015-12-04 10:33:06 +01:00
bool thread_created = false ;
struct thread_data * data = NULL ;
sthread_t * thread = ( sthread_t * ) calloc ( 1 , sizeof ( * thread ) ) ;
2011-10-06 22:19:56 +02:00
if ( ! thread )
return NULL ;
2015-12-04 10:33:06 +01:00
data = ( struct thread_data * ) calloc ( 1 , sizeof ( * data ) ) ;
2011-10-06 22:19:56 +02:00
if ( ! data )
2015-12-04 10:33:06 +01:00
goto error ;
2011-10-06 22:19:56 +02:00
data - > func = thread_func ;
data - > userdata = userdata ;
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2011-10-06 22:19:56 +02:00
thread - > thread = CreateThread ( NULL , 0 , thread_wrap , data , 0 , NULL ) ;
2016-03-21 05:44:45 +01:00
thread_created = ! ! thread - > thread ;
2016-10-02 15:58:44 +02:00
# else
# if defined(VITA)
pthread_attr_t thread_attr ;
pthread_attr_init ( & thread_attr ) ;
pthread_attr_setstacksize ( & thread_attr , 0x10000 ) ;
thread_created = pthread_create ( & thread - > id , & thread_attr , thread_wrap , data ) = = 0 ;
2015-01-08 20:33:20 +01:00
# else
2015-12-04 10:33:06 +01:00
thread_created = pthread_create ( & thread - > id , NULL , thread_wrap , data ) = = 0 ;
2016-10-02 15:58:44 +02:00
# endif
2015-01-08 20:33:20 +01:00
# endif
2015-12-04 10:33:06 +01:00
if ( ! thread_created )
goto error ;
2011-10-06 22:19:56 +02:00
return thread ;
2015-12-04 10:33:06 +01:00
error :
if ( data )
free ( data ) ;
free ( thread ) ;
return NULL ;
2011-10-06 22:19:56 +02:00
}
2015-01-08 21:23:34 +01:00
/**
* sthread_detach :
2016-09-08 16:11:16 +02:00
* @ thread : pointer to thread object
2015-01-08 21:23:34 +01:00
*
* Detach a thread . When a detached thread terminates , its
2017-01-21 16:49:10 -06:00
* resources are automatically released back to the system
2016-09-08 16:11:16 +02:00
* without the need for another thread to join with the
2015-01-08 21:23:34 +01:00
* terminated thread .
*
* Returns : 0 on success , otherwise it returns a non - zero error number .
*/
2013-11-01 04:49:29 +01:00
int sthread_detach ( sthread_t * thread )
{
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2013-11-01 04:49:29 +01:00
CloseHandle ( thread - > thread ) ;
2013-11-01 09:12:36 +01:00
free ( thread ) ;
2013-11-01 04:49:29 +01:00
return 0 ;
2015-01-08 20:33:20 +01:00
# else
return pthread_detach ( thread - > id ) ;
# endif
2013-11-01 04:49:29 +01:00
}
2015-01-08 21:23:34 +01:00
/**
* sthread_join :
2016-09-08 16:11:16 +02:00
* @ thread : pointer to thread object
2015-01-08 21:23:34 +01:00
*
* Join with a terminated thread . Waits for the thread specified by
* @ thread to terminate . If that thread has already terminated , then
* it will return immediately . The thread specified by @ thread must
* be joinable .
2016-09-08 16:11:16 +02:00
*
2015-01-08 21:23:34 +01:00
* Returns : 0 on success , otherwise it returns a non - zero error number .
*/
2011-10-06 22:19:56 +02:00
void sthread_join ( sthread_t * thread )
{
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2011-10-06 22:19:56 +02:00
WaitForSingleObject ( thread - > thread , INFINITE ) ;
CloseHandle ( thread - > thread ) ;
2015-01-08 20:33:20 +01:00
# else
pthread_join ( thread - > id , NULL ) ;
# endif
2011-10-06 22:19:56 +02:00
free ( thread ) ;
}
2016-03-21 05:44:45 +01:00
/**
* sthread_isself :
2016-09-08 16:11:16 +02:00
* @ thread : pointer to thread object
2016-03-21 05:44:45 +01:00
*
* Returns : true ( 1 ) if calling thread is the specified thread
*/
bool sthread_isself ( sthread_t * thread )
{
2017-01-09 16:46:35 -06:00
/* This thread can't possibly be a null thread */
if ( ! thread ) return false ;
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
return GetCurrentThread ( ) = = thread - > thread ;
# else
return pthread_equal ( pthread_self ( ) , thread - > id ) ;
# endif
}
2015-01-08 21:23:34 +01:00
/**
* slock_new :
*
* Create and initialize a new mutex . Must be manually
* freed .
*
* Returns : pointer to a new mutex if successful , otherwise NULL .
* */
2011-10-06 20:31:39 +02:00
slock_t * slock_new ( void )
{
2017-01-09 16:46:35 -06:00
bool mutex_created = false ;
2015-12-04 10:33:06 +01:00
slock_t * lock = ( slock_t * ) calloc ( 1 , sizeof ( * lock ) ) ;
2011-10-06 20:31:39 +02:00
if ( ! lock )
return NULL ;
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2017-01-21 17:09:38 -06:00
InitializeCriticalSection ( & lock - > lock ) ;
mutex_created = true ;
2015-01-08 20:33:20 +01:00
# else
2017-01-21 17:09:38 -06:00
mutex_created = ( pthread_mutex_init ( & lock - > lock , NULL ) = = 0 ) ;
2016-05-06 06:25:06 +02:00
# endif
2015-01-08 20:33:20 +01:00
2017-01-09 16:46:35 -06:00
if ( ! mutex_created )
goto error ;
2011-10-06 22:19:56 +02:00
return lock ;
2015-12-04 10:33:06 +01:00
error :
2017-01-09 16:46:35 -06:00
free ( lock ) ;
2015-12-04 10:33:06 +01:00
return NULL ;
2011-10-06 20:31:39 +02:00
}
2015-01-08 21:23:34 +01:00
/**
* slock_free :
2016-09-08 16:11:16 +02:00
* @ lock : pointer to mutex object
2015-01-08 21:23:34 +01:00
*
* Frees a mutex .
* */
2011-10-06 22:19:56 +02:00
void slock_free ( slock_t * lock )
{
2014-09-15 08:17:16 -04:00
if ( ! lock )
return ;
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2017-01-21 17:09:38 -06:00
DeleteCriticalSection ( & lock - > lock ) ;
2015-01-08 20:33:20 +01:00
# else
pthread_mutex_destroy ( & lock - > lock ) ;
# endif
2011-10-06 22:19:56 +02:00
free ( lock ) ;
}
2011-10-06 20:31:39 +02:00
2015-01-08 21:23:34 +01:00
/**
* slock_lock :
2016-09-08 16:11:16 +02:00
* @ lock : pointer to mutex object
2015-01-08 21:23:34 +01:00
*
* Locks a mutex . If a mutex is already locked by
* another thread , the calling thread shall block until
* the mutex becomes available .
* */
2011-10-06 22:19:56 +02:00
void slock_lock ( slock_t * lock )
{
2017-01-05 21:20:37 -05:00
if ( ! lock )
return ;
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2017-01-21 17:09:38 -06:00
EnterCriticalSection ( & lock - > lock ) ;
2015-01-08 20:33:20 +01:00
# else
pthread_mutex_lock ( & lock - > lock ) ;
# endif
2011-10-06 22:19:56 +02:00
}
2011-10-06 20:31:39 +02:00
2015-01-08 21:23:34 +01:00
/**
* slock_unlock :
2016-09-08 16:11:16 +02:00
* @ lock : pointer to mutex object
2015-01-08 21:23:34 +01:00
*
* Unlocks a mutex .
* */
2011-10-06 22:19:56 +02:00
void slock_unlock ( slock_t * lock )
2011-10-06 20:31:39 +02:00
{
2017-01-05 21:20:37 -05:00
if ( ! lock )
return ;
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2017-01-21 17:09:38 -06:00
LeaveCriticalSection ( & lock - > lock ) ;
2015-01-08 20:33:20 +01:00
# else
pthread_mutex_unlock ( & lock - > lock ) ;
# endif
2011-10-06 22:19:56 +02:00
}
2015-01-08 21:23:34 +01:00
/**
* scond_new :
*
* Creates and initializes a condition variable . Must
* be manually freed .
*
* Returns : pointer to new condition variable on success ,
* otherwise NULL .
* */
2011-10-06 22:19:56 +02:00
scond_t * scond_new ( void )
{
2015-12-04 10:33:06 +01:00
scond_t * cond = ( scond_t * ) calloc ( 1 , sizeof ( * cond ) ) ;
2011-10-06 22:19:56 +02:00
if ( ! cond )
return NULL ;
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2017-01-21 22:44:31 -06:00
2017-01-09 16:46:35 -06:00
/* This is very complex because recreating condition variable semantics with win32 parts is not easy */
2017-01-21 16:49:10 -06:00
/* The main problem is that a condition variable can't be used to "pre-wake" a thread (it will get wakened only after it's waited) */
/* whereas a win32 event can pre-wake a thread (the event will be set in advance, so a 'waiter' won't even have to wait on it) */
/* Keep in mind a condition variable can apparently pre-wake a thread, insofar as spurious wakeups are always possible, */
/* but nobody will be expecting this and it does not need to be simulated. */
2017-01-21 22:44:31 -06:00
/* Moreover, we won't be doing this, because it counts as a spurious wakeup -- someone else with a genuine claim must get wakened, in any case.
/* Therefore we choose to wake only one of the correct waiting threads. */
2017-01-09 16:46:35 -06:00
/* So at the very least, we need to do something clever. But there's bigger problems. */
/* We don't even have a straightforward way in win32 to satisfy pthread_cond_wait's atomicity requirement. The bulk of this algorithm is solving that. */
/* Note: We might could simplify this using vista+ condition variables, but we wanted an XP compatible solution. */
cond - > event = CreateEvent ( NULL , FALSE , FALSE , NULL ) ;
2017-01-21 16:49:10 -06:00
if ( ! cond - > event ) goto error ;
2017-01-09 16:46:35 -06:00
cond - > hot_potato = CreateEvent ( NULL , FALSE , FALSE , NULL ) ;
2017-01-21 16:49:10 -06:00
if ( ! cond - > hot_potato )
2017-01-09 16:46:35 -06:00
{
CloseHandle ( cond - > event ) ;
goto error ;
}
2017-01-21 22:44:31 -06:00
InitializeCriticalSection ( & cond - > cs ) ;
2017-01-09 16:46:35 -06:00
cond - > waiters = cond - > wakens = 0 ;
cond - > head = NULL ;
2015-12-04 10:33:06 +01:00
2017-01-09 16:46:35 -06:00
# else
if ( pthread_cond_init ( & cond - > cond , NULL ) ! = 0 )
2015-12-04 10:33:06 +01:00
goto error ;
2017-01-09 16:46:35 -06:00
# endif
2011-10-06 22:19:56 +02:00
return cond ;
2015-12-04 10:33:06 +01:00
error :
free ( cond ) ;
return NULL ;
2011-10-06 22:19:56 +02:00
}
2015-01-08 21:23:34 +01:00
/**
* scond_free :
2016-09-08 16:11:16 +02:00
* @ cond : pointer to condition variable object
2015-01-08 21:23:34 +01:00
*
* Frees a condition variable .
* */
2015-01-08 20:33:20 +01:00
void scond_free ( scond_t * cond )
2011-10-06 22:19:56 +02:00
{
2015-01-08 20:33:20 +01:00
if ( ! cond )
return ;
2011-10-06 22:19:56 +02:00
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2015-01-08 20:33:20 +01:00
CloseHandle ( cond - > event ) ;
2017-01-09 16:46:35 -06:00
CloseHandle ( cond - > hot_potato ) ;
2017-01-21 22:44:31 -06:00
DeleteCriticalSection ( & cond - > cs ) ;
2014-06-25 04:06:42 +02:00
# else
2015-01-08 20:33:20 +01:00
pthread_cond_destroy ( & cond - > cond ) ;
2014-06-25 04:06:42 +02:00
# endif
2015-01-08 20:33:20 +01:00
free ( cond ) ;
2011-10-06 22:19:56 +02:00
}
2015-01-08 21:23:34 +01:00
/**
* scond_wait :
2016-09-08 16:11:16 +02:00
* @ cond : pointer to condition variable object
* @ lock : pointer to mutex object
2015-01-08 21:23:34 +01:00
*
2016-09-08 16:11:16 +02:00
* Block on a condition variable ( i . e . wait on a condition ) .
2015-01-08 21:23:34 +01:00
* */
2015-01-08 20:33:20 +01:00
void scond_wait ( scond_t * cond , slock_t * lock )
2011-10-06 22:19:56 +02:00
{
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2017-01-09 16:46:35 -06:00
2017-01-21 22:44:31 -06:00
struct QueueEntry myentry ;
struct QueueEntry * * ptr ;
/* Reminder: `lock` is held before this is called. */
/* however, someone else may have called scond_signal without the lock. soo... */
EnterCriticalSection ( & cond - > cs ) ;
2017-01-21 16:49:10 -06:00
2017-01-09 16:46:35 -06:00
/* add ourselves to a queue of waiting threads */
2017-01-21 22:44:31 -06:00
ptr = & cond - > head ;
2017-01-09 16:46:35 -06:00
while ( * ptr ) /* walk to the end of the linked list */
ptr = & ( ( * ptr ) - > next ) ;
* ptr = & myentry ;
myentry . next = NULL ;
cond - > waiters + + ;
/* now the conceptual lock release and condition block are supposed to be atomic. */
/* we can't do that in windows, but we can simulate the effects by using the queue, by the following analysis: */
/* What happens if they aren't atomic? */
/* 1. a signaller can rush in and signal, expecting a waiter to get it; but the waiter wouldn't, because he isn't blocked yet */
/* solution: win32 events make this easy. the event will sit there enabled */
/* 2. a signaller can rush in and signal, and then turn right around and wait */
/* solution: the signaller will get queued behind the waiter, who's enqueued before he releases the mutex */
/* It's my turn if I'm the head of the queue. Check to see if it's my turn. */
while ( cond - > head ! = & myentry )
{
2017-01-21 16:49:10 -06:00
/* It isn't my turn: */
2017-01-09 16:46:35 -06:00
/* As long as someone is even going to be able to wake up when they receive the potato, keep it going round */
if ( cond - > wakens > 0 )
SetEvent ( cond - > hot_potato ) ;
2017-01-21 16:49:10 -06:00
/* Let someone else go */
2017-01-21 17:09:38 -06:00
LeaveCriticalSection ( & lock - > lock ) ;
2017-01-21 22:44:31 -06:00
LeaveCriticalSection ( & cond - > cs ) ;
2017-01-21 16:49:10 -06:00
/* Wait a while to catch the hot potato.. someone else should get a chance to go */
2017-01-21 22:44:31 -06:00
/* After all, it isn't my turn (and it must be someone else's) */
2017-01-21 16:49:10 -06:00
Sleep ( 0 ) ;
WaitForSingleObject ( cond - > hot_potato , INFINITE ) ;
/* I should come out of here with the main lock taken */
2017-01-21 17:09:38 -06:00
EnterCriticalSection ( & lock - > lock ) ;
2017-01-21 22:44:31 -06:00
EnterCriticalSection ( & cond - > cs ) ;
2017-01-09 16:46:35 -06:00
}
2017-01-21 16:49:10 -06:00
2017-01-09 16:46:35 -06:00
/* It's my turn now -- I hold the potato */
2017-01-21 16:49:10 -06:00
/* I still have the main lock, in any case */
/* I need to release it so that someone can set the event */
2017-01-21 17:09:38 -06:00
LeaveCriticalSection ( & lock - > lock ) ;
2017-01-21 22:44:31 -06:00
LeaveCriticalSection ( & cond - > cs ) ;
2017-01-21 16:49:10 -06:00
/* Wait for someone to actually signal this condition */
/* We're the only waiter waiting on the event right now -- everyone else is waiting on something different */
WaitForSingleObject ( cond - > event , INFINITE ) ;
/* Take the main lock so we can do work. Nobody else waits on this lock for very long, so even though it's GO TIME we won't have to wait long */
2017-01-21 17:09:38 -06:00
EnterCriticalSection ( & lock - > lock ) ;
2017-01-21 22:44:31 -06:00
EnterCriticalSection ( & cond - > cs ) ;
2017-01-09 16:46:35 -06:00
/* Remove ourselves from the queue */
cond - > head = myentry . next ;
cond - > waiters - - ;
/* If any other wakenings are pending, go ahead and set it up */
/* There may actually be no waiters. That's OK. The first waiter will come in, find it's his turn, and immediately get the signaled event */
cond - > wakens - - ;
2017-01-21 16:49:10 -06:00
if ( cond - > wakens > 0 )
2017-01-09 16:46:35 -06:00
{
SetEvent ( cond - > event ) ;
/* Progress the queue: Put the hot potato back into play. It'll be tossed around until next in line gets it */
SetEvent ( cond - > hot_potato ) ;
}
2017-01-21 22:44:31 -06:00
LeaveCriticalSection ( & cond - > cs ) ;
2015-01-08 20:33:20 +01:00
# else
pthread_cond_wait ( & cond - > cond , & lock - > lock ) ;
# endif
2011-10-06 22:19:56 +02:00
}
2015-01-08 21:23:34 +01:00
/**
* scond_broadcast :
2016-09-08 16:11:16 +02:00
* @ cond : pointer to condition variable object
2015-01-08 21:23:34 +01:00
*
* Broadcast a condition . Unblocks all threads currently blocked
2016-09-08 16:11:16 +02:00
* on the specified condition variable @ cond .
2015-01-08 21:23:34 +01:00
* */
2013-10-31 23:12:40 +01:00
int scond_broadcast ( scond_t * cond )
{
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2017-01-09 16:46:35 -06:00
/* remember: we currently have mutex */
if ( cond - > waiters = = 0 ) return 0 ;
/* awaken everything which is currently queued up */
if ( cond - > wakens = = 0 ) SetEvent ( cond - > event ) ;
cond - > wakens = cond - > waiters ;
/* Since there is now at least one pending waken, the potato must be in play */
SetEvent ( cond - > hot_potato ) ;
2013-10-31 23:12:40 +01:00
return 0 ;
2011-10-06 22:19:56 +02:00
# else
2015-01-08 20:33:20 +01:00
return pthread_cond_broadcast ( & cond - > cond ) ;
# endif
2011-10-06 20:31:39 +02:00
}
2015-01-08 21:23:34 +01:00
/**
* scond_signal :
2016-09-08 16:11:16 +02:00
* @ cond : pointer to condition variable object
2015-01-08 21:23:34 +01:00
*
* Signal a condition . Unblocks at least one of the threads currently blocked
2016-09-08 16:11:16 +02:00
* on the specified condition variable @ cond .
2015-01-08 21:23:34 +01:00
* */
2015-01-08 20:33:20 +01:00
void scond_signal ( scond_t * cond )
2011-10-06 20:31:39 +02:00
{
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2017-01-09 16:46:35 -06:00
2017-01-21 22:44:31 -06:00
/* Unfortunately, pthread_cond_signal does not require that the lock be held in advance */
/* To avoid stomping on the condvar from other threads, we need to control access to it with this */
EnterCriticalSection ( & cond - > cs ) ;
2017-01-09 16:46:35 -06:00
/* remember: we currently have mutex */
2017-01-21 22:44:31 -06:00
if ( cond - > waiters = = 0 )
{
LeaveCriticalSection ( & cond - > cs ) ;
return ;
}
2017-01-09 16:46:35 -06:00
/* wake up the next thing in the queue */
if ( cond - > wakens = = 0 ) SetEvent ( cond - > event ) ;
cond - > wakens + + ;
2017-01-21 22:44:31 -06:00
/* The data structure is done being modified.. I think we can leave the CS now. */
/* This would prevent some other thread from receiving the hot potato and then
/* immediately stalling for the critical section. */
/* But remember, we were trying to replicate a semantic where this entire scond_signal call
/* was controlled (by the user) by a lock. */
/* So in case there's trouble with this, we can move it after SetEvent() */
LeaveCriticalSection ( & cond - > cs ) ;
2017-01-09 16:46:35 -06:00
/* Since there is now at least one pending waken, the potato must be in play */
SetEvent ( cond - > hot_potato ) ;
2015-01-08 20:33:20 +01:00
# else
pthread_cond_signal ( & cond - > cond ) ;
# endif
2011-10-06 20:31:39 +02:00
}
2015-01-08 21:23:34 +01:00
/**
* scond_wait_timeout :
2016-09-08 16:11:16 +02:00
* @ cond : pointer to condition variable object
* @ lock : pointer to mutex object
2015-01-08 21:23:34 +01:00
* @ timeout_us : timeout ( in microseconds )
*
* Try to block on a condition variable ( i . e . wait on a condition ) until
* @ timeout_us elapses .
*
* Returns : false ( 0 ) if timeout elapses before condition variable is
* signaled or broadcast , otherwise true ( 1 ) .
* */
2015-01-08 20:33:20 +01:00
bool scond_wait_timeout ( scond_t * cond , slock_t * lock , int64_t timeout_us )
2011-10-06 20:31:39 +02:00
{
2016-03-21 05:44:45 +01:00
# ifdef USE_WIN32_THREADS
2015-01-08 20:33:20 +01:00
DWORD ret ;
2011-10-06 20:31:39 +02:00
2017-01-21 22:44:31 -06:00
/* TODO: this is woefully inadequate. It needs to be solved with the newer approach used above. */
2015-01-08 20:33:20 +01:00
WaitForSingleObject ( cond - > event , 0 ) ;
2017-01-21 17:09:38 -06:00
LeaveCriticalSection ( & lock - > lock ) ;
ret = WaitForSingleObject ( cond - > event , ( DWORD ) ( timeout_us ) / 1000 ) ;
2013-10-31 23:12:40 +01:00
2017-01-21 17:09:38 -06:00
EnterCriticalSection ( & lock - > lock ) ;
2015-01-08 20:33:20 +01:00
return ret = = WAIT_OBJECT_0 ;
# else
int ret ;
2015-08-27 09:22:03 +02:00
int64_t seconds , remainder ;
2013-11-07 21:01:49 -05:00
struct timespec now = { 0 } ;
2011-10-06 20:49:00 +02:00
2014-09-07 05:47:18 +02:00
# ifdef __MACH__
/* OSX doesn't have clock_gettime. */
2011-10-06 20:49:00 +02:00
clock_serv_t cclock ;
mach_timespec_t mts ;
2015-01-08 20:33:20 +01:00
2011-10-06 20:49:00 +02:00
host_get_clock_service ( mach_host_self ( ) , CALENDAR_CLOCK , & cclock ) ;
clock_get_time ( cclock , & mts ) ;
mach_port_deallocate ( mach_task_self ( ) , cclock ) ;
now . tv_sec = mts . tv_sec ;
now . tv_nsec = mts . tv_nsec ;
2013-11-08 01:54:46 +01:00
# elif defined(__CELLOS_LV2__)
sys_time_sec_t s ;
sys_time_nsec_t n ;
2015-01-08 20:33:20 +01:00
2013-11-08 01:54:46 +01:00
sys_time_get_current_time ( & s , & n ) ;
2013-11-07 21:58:59 -05:00
now . tv_sec = s ;
now . tv_nsec = n ;
2016-08-19 02:59:25 +02:00
# elif defined(__mips__) || defined(VITA)
2014-02-17 19:30:21 +01:00
struct timeval tm ;
2015-01-08 20:33:20 +01:00
2014-02-17 19:30:21 +01:00
gettimeofday ( & tm , NULL ) ;
now . tv_sec = tm . tv_sec ;
now . tv_nsec = tm . tv_usec * 1000 ;
2016-03-21 05:44:45 +01:00
# elif defined(RETRO_WIN32_USE_PTHREADS)
_ftime64_s ( & now ) ;
2014-09-07 05:47:18 +02:00
# elif !defined(GEKKO)
/* timeout on libogc is duration, not end time. */
2011-10-06 20:31:39 +02:00
clock_gettime ( CLOCK_REALTIME , & now ) ;
2011-10-06 20:49:00 +02:00
# endif
2011-10-06 20:31:39 +02:00
2015-08-27 09:22:03 +02:00
seconds = timeout_us / INT64_C ( 1000000 ) ;
remainder = timeout_us % INT64_C ( 1000000 ) ;
2011-10-06 20:31:39 +02:00
2015-08-27 09:22:03 +02:00
now . tv_sec + = seconds ;
now . tv_nsec + = remainder * INT64_C ( 1000 ) ;
2011-10-06 20:31:39 +02:00
2015-01-08 20:33:20 +01:00
ret = pthread_cond_timedwait ( & cond - > cond , & lock - > lock , & now ) ;
return ( ret = = 0 ) ;
2011-10-06 20:31:39 +02:00
# endif
2015-01-08 20:33:20 +01:00
}
2016-10-17 20:49:37 -03:00
2016-10-17 21:21:51 -03:00
# ifdef HAVE_THREAD_STORAGE
2016-10-17 20:49:37 -03:00
bool sthread_tls_create ( sthread_tls_t * tls )
{
# ifdef USE_WIN32_THREADS
return ( * tls = TlsAlloc ( ) ) ! = TLS_OUT_OF_INDEXES ;
# else
2016-10-26 02:46:15 +02:00
return pthread_key_create ( ( pthread_key_t * ) tls , NULL ) = = 0 ;
2016-10-17 20:49:37 -03:00
# endif
}
bool sthread_tls_delete ( sthread_tls_t * tls )
{
# ifdef USE_WIN32_THREADS
return TlsFree ( * tls ) ! = 0 ;
# else
return pthread_key_delete ( * tls ) = = 0 ;
# endif
}
void * sthread_tls_get ( sthread_tls_t * tls )
{
# ifdef USE_WIN32_THREADS
return TlsGetValue ( * tls ) ;
# else
return pthread_getspecific ( * tls ) ;
# endif
}
bool sthread_tls_set ( sthread_tls_t * tls , const void * data )
{
# ifdef USE_WIN32_THREADS
return TlsSetValue ( * tls , ( void * ) data ) ! = 0 ;
# else
return pthread_setspecific ( * tls , data ) = = 0 ;
# endif
}
2016-10-17 21:21:51 -03:00
# endif