diff --git a/common/src/Utilities/Console.cpp b/common/src/Utilities/Console.cpp index 97f1623469..9761b43b7e 100644 --- a/common/src/Utilities/Console.cpp +++ b/common/src/Utilities/Console.cpp @@ -32,7 +32,7 @@ static DeclareTls(ConsoleColors) conlog_Color( DefaultConsoleColor ); static wxString m_buffer; // used by ConsoleBuffer static Mutex m_bufferlock; // used by ConsoleBuffer -#ifdef __linux__ +#ifdef __POSIX__ static FILE *stdout_fp = stdout; void Console_SetStdout(FILE *fp) diff --git a/common/src/Utilities/Linux/LnxHostSys.cpp b/common/src/Utilities/Linux/LnxHostSys.cpp index 2213b23139..d400411e0e 100644 --- a/common/src/Utilities/Linux/LnxHostSys.cpp +++ b/common/src/Utilities/Linux/LnxHostSys.cpp @@ -24,6 +24,12 @@ #include #include +// Apple uses the MAP_ANON define instead of MAP_ANONYMOUS, but they mean +// the same thing. +#if defined(__APPLE__) && !defined(MAP_ANONYMOUS) +# define MAP_ANONYMOUS MAP_ANON +#endif + extern void SignalExit(int sig); static const uptr m_pagemask = getpagesize()-1; diff --git a/common/src/Utilities/Mutex.cpp b/common/src/Utilities/Mutex.cpp index fdcd5b7f19..19d0735c16 100644 --- a/common/src/Utilities/Mutex.cpp +++ b/common/src/Utilities/Mutex.cpp @@ -31,6 +31,57 @@ namespace Threading // Mutex Implementations // -------------------------------------------------------------------------------------- +#if defined(_WIN32) || (defined(_POSIX_TIMEOUTS) && _POSIX_TIMEOUTS >= 200112L) +// good, we have pthread_mutex_timedlock +#define xpthread_mutex_timedlock pthread_mutex_timedlock +#else +// We have to emulate pthread_mutex_timedlock(). This could be a serious +// performance drain if its used a lot. + +#include // gettimeofday() + +// sleep for 10ms at a time +#define TIMEDLOCK_EMU_SLEEP_NS 10000000ULL + +// Original POSIX docs: +// +// The pthread_mutex_timedlock() function shall lock the mutex object +// referenced by mutex. If the mutex is already locked, the calling thread +// shall block until the mutex becomes available as in the +// pthread_mutex_lock() function. If the mutex cannot be locked without +// waiting for another thread to unlock the mutex, this wait shall be +// terminated when the specified timeout expires. +// +// This is an implementation that emulates pthread_mutex_timedlock() via +// pthread_mutex_trylock(). +static int xpthread_mutex_timedlock( + pthread_mutex_t *mutex, + const struct timespec *abs_timeout) +{ + int err = 0; + + while ((err = pthread_mutex_trylock(mutex)) == EBUSY) { + // acquiring lock failed, sleep some + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = TIMEDLOCK_EMU_SLEEP_NS; + int status; + while ((status = nanosleep(&ts, &ts)) == -1); + + // check if the timeout has expired, gettimeofday() is implemented + // efficiently (in userspace) on OSX + struct timeval now; + int res = gettimeofday(&now, NULL); + if (abs_timeout->tv_sec == 0 || now.tv_sec > abs_timeout->tv_sec || + (u64) now.tv_usec * 1000ULL > (u64) abs_timeout->tv_nsec) { + return ETIMEDOUT; + } + } + + return err; +} +#endif + Threading::Mutex::Mutex() { pthread_mutex_init( &m_mutex, NULL ); @@ -125,7 +176,7 @@ bool Threading::Mutex::AcquireWithoutYield( const wxTimeSpan& timeout ) { wxDateTime megafail( wxDateTime::UNow() + timeout ); const timespec fail = { megafail.GetTicks(), megafail.GetMillisecond() * 1000000 }; - return pthread_mutex_timedlock( &m_mutex, &fail ) == 0; + return xpthread_mutex_timedlock( &m_mutex, &fail ) == 0; } void Threading::Mutex::Release()