cog/Frameworks/OpenMPT.old/OpenMPT/common/mptMutex.h

238 lines
5.5 KiB
C++

/*
* mptMutex.h
* ----------
* Purpose: Partially implement c++ mutexes as far as openmpt needs them. Can eventually go away when we only support c++11 compilers some time.
* Notes : (currently none)
* Authors: OpenMPT Devs
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
*/
#pragma once
#include "BuildSettings.h"
#include <vector> // some C++ header in order to have the C++ standard library version information available
#if !MPT_PLATFORM_MULTITHREADED
#define MPT_MUTEX_STD 0
#define MPT_MUTEX_PTHREAD 0
#define MPT_MUTEX_WIN32 0
#elif MPT_OS_EMSCRIPTEN
#define MPT_MUTEX_STD 0
#define MPT_MUTEX_PTHREAD 0
#define MPT_MUTEX_WIN32 0
#elif MPT_COMPILER_GENERIC
#define MPT_MUTEX_STD 1
#define MPT_MUTEX_PTHREAD 0
#define MPT_MUTEX_WIN32 0
#elif (defined(__MINGW32__) || defined(__MINGW64__)) && !defined(_GLIBCXX_HAS_GTHREADS) && defined(MPT_WITH_MINGWSTDTHREADS)
#define MPT_MUTEX_STD 1
#define MPT_MUTEX_PTHREAD 0
#define MPT_MUTEX_WIN32 0
#elif (defined(__MINGW32__) || defined(__MINGW64__)) && !defined(_GLIBCXX_HAS_GTHREADS)
#define MPT_MUTEX_STD 0
#define MPT_MUTEX_PTHREAD 0
#define MPT_MUTEX_WIN32 1
#elif MPT_COMPILER_MSVC
#define MPT_MUTEX_STD 1
#define MPT_MUTEX_PTHREAD 0
#define MPT_MUTEX_WIN32 0
#elif MPT_COMPILER_GCC
#define MPT_MUTEX_STD 1
#define MPT_MUTEX_PTHREAD 0
#define MPT_MUTEX_WIN32 0
#elif MPT_COMPILER_CLANG
#define MPT_MUTEX_STD 1
#define MPT_MUTEX_PTHREAD 0
#define MPT_MUTEX_WIN32 0
#elif MPT_OS_WINDOWS
#define MPT_MUTEX_STD 0
#define MPT_MUTEX_PTHREAD 0
#define MPT_MUTEX_WIN32 1
#else
#define MPT_MUTEX_STD 0
#define MPT_MUTEX_PTHREAD 1
#define MPT_MUTEX_WIN32 0
#endif
#if !MPT_MUTEX_STD && !MPT_MUTEX_PTHREAD && !MPT_MUTEX_WIN32
#define MPT_MUTEX_NONE 1
#else
#define MPT_MUTEX_NONE 0
#endif
#if defined(MODPLUG_TRACKER) && MPT_MUTEX_NONE
#error "OpenMPT requires mutexes."
#endif
#if MPT_MUTEX_STD
#if (defined(__MINGW32__) || defined(__MINGW64__)) && !defined(_GLIBCXX_HAS_GTHREADS) && defined(MPT_WITH_MINGWSTDTHREADS)
#include <mingw.mutex.h>
#else
#include <mutex>
#endif
#elif MPT_MUTEX_WIN32
#include <windows.h>
#elif MPT_MUTEX_PTHREAD
#include <pthread.h>
#endif // MPT_MUTEX
OPENMPT_NAMESPACE_BEGIN
namespace mpt {
#if MPT_MUTEX_STD
typedef std::mutex mutex;
typedef std::recursive_mutex recursive_mutex;
#elif MPT_MUTEX_WIN32
// compatible with c++11 std::mutex, can eventually be replaced without touching any usage site
class mutex {
private:
CRITICAL_SECTION impl;
public:
mutex() { InitializeCriticalSection(&impl); }
~mutex() { DeleteCriticalSection(&impl); }
void lock() { EnterCriticalSection(&impl); }
bool try_lock() { return TryEnterCriticalSection(&impl) ? true : false; }
void unlock() { LeaveCriticalSection(&impl); }
};
// compatible with c++11 std::recursive_mutex, can eventually be replaced without touching any usage site
class recursive_mutex {
private:
CRITICAL_SECTION impl;
public:
recursive_mutex() { InitializeCriticalSection(&impl); }
~recursive_mutex() { DeleteCriticalSection(&impl); }
void lock() { EnterCriticalSection(&impl); }
bool try_lock() { return TryEnterCriticalSection(&impl) ? true : false; }
void unlock() { LeaveCriticalSection(&impl); }
};
#elif MPT_MUTEX_PTHREAD
class mutex {
private:
pthread_mutex_t hLock;
public:
mutex()
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
pthread_mutex_init(&hLock, &attr);
pthread_mutexattr_destroy(&attr);
}
~mutex() { pthread_mutex_destroy(&hLock); }
void lock() { pthread_mutex_lock(&hLock); }
bool try_lock() { return (pthread_mutex_trylock(&hLock) == 0); }
void unlock() { pthread_mutex_unlock(&hLock); }
};
class recursive_mutex {
private:
pthread_mutex_t hLock;
public:
recursive_mutex()
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&hLock, &attr);
pthread_mutexattr_destroy(&attr);
}
~recursive_mutex() { pthread_mutex_destroy(&hLock); }
void lock() { pthread_mutex_lock(&hLock); }
bool try_lock() { return (pthread_mutex_trylock(&hLock) == 0); }
void unlock() { pthread_mutex_unlock(&hLock); }
};
#else // MPT_MUTEX_NONE
class mutex {
public:
mutex() { }
~mutex() { }
void lock() { }
bool try_lock() { return true; }
void unlock() { }
};
class recursive_mutex {
public:
recursive_mutex() { }
~recursive_mutex() { }
void lock() { }
bool try_lock() { return true; }
void unlock() { }
};
#endif // MPT_MUTEX
#if MPT_MUTEX_STD
template <typename T> using lock_guard = std::lock_guard<T>;
#else // !MPT_MUTEX_STD
// compatible with c++11 std::lock_guard, can eventually be replaced without touching any usage site
template< typename mutex_type >
class lock_guard {
private:
mutex_type & mutex;
public:
lock_guard( mutex_type & m ) : mutex(m) { mutex.lock(); }
~lock_guard() { mutex.unlock(); }
};
#endif // MPT_MUTEX_STD
#ifdef MODPLUG_TRACKER
class recursive_mutex_with_lock_count {
private:
mpt::recursive_mutex mutex;
long lockCount;
public:
recursive_mutex_with_lock_count()
: lockCount(0)
{
return;
}
~recursive_mutex_with_lock_count()
{
return;
}
void lock()
{
mutex.lock();
lockCount++;
}
void unlock()
{
lockCount--;
mutex.unlock();
}
public:
bool IsLockedByCurrentThread() // DEBUGGING only
{
bool islocked = false;
if(mutex.try_lock())
{
islocked = (lockCount > 0);
mutex.unlock();
}
return islocked;
}
};
#endif // MODPLUG_TRACKER
} // namespace mpt
OPENMPT_NAMESPACE_END