diff --git a/common/ipc_mutex.cpp b/common/ipc_mutex.cpp new file mode 100644 index 000000000..2c634c594 --- /dev/null +++ b/common/ipc_mutex.cpp @@ -0,0 +1,102 @@ +#include "ipc_mutex.h" +#ifdef _WINDOWS +#include +#else +#include +#include +#include +#include +#include +#endif +#include "types.h" +#include "eqemu_exception.h" + + +namespace EQEmu { + struct IPCMutex::Implementation { +#ifdef _WINDOWS + HANDLE mut_; +#else + sem_t *sem_; +#endif + }; + + IPCMutex::IPCMutex(std::string name) : locked_(false) { + imp_ = new Implementation; +#ifdef _WINDOWS + std::string final_name = "EQEmuMutex_"; + final_name += name; + + imp_->mut_ = CreateMutex(NULL, + FALSE, + final_name.c_str()); + + if(!imp_->mut_) { + EQ_EXCEPT("IPC Mutex", "Could not create mutex."); + } +#else + std::string final_name = "/EQEmuMutex_"; + final_name += name; + + imp_->sem_ = sem_open(final_name.c_str(), O_CREAT, S_IRUSR | S_IWUSR, 1); + if(imp_->sem_ == SEM_FAILED) { + EQ_EXCEPT("IPC Mutex", "Could not create mutex."); + } +#endif + } + + IPCMutex::~IPCMutex() { +#ifdef _WINDOWS + if(imp_->mut_) { + if(locked_) { + ReleaseMutex(imp_->mut_); + } + CloseHandle(imp_->mut_); + } +#else + if(imp_->sem_) { + if(locked_) { + sem_post(imp_->sem_); + } + sem_close(imp_->sem_); + } +#endif + delete imp_; + } + + bool IPCMutex::Lock() { + if(locked_) { + return false; + } + +#ifdef _WINDOWS + DWORD wait_result = WaitForSingleObject(imp_->mut_, INFINITE); + if(wait_result != WAIT_OBJECT_0) { + return false; + } +#else + if(sem_wait(imp_->sem_) == -1) { + return false; + } +#endif + locked_ = true; + return true; + } + + bool IPCMutex::Unlock() { + if(!locked_) { + return false; + } +#ifdef _WINDOWS + if(!ReleaseMutex(imp_->mut_)) { + return false; + } +#else + if(sem_post(imp_->sem_) == -1) { + return false; + } +#endif + locked_ = false; + return true; + } +} diff --git a/common/ipc_mutex.h b/common/ipc_mutex.h new file mode 100644 index 000000000..e10e6dd5f --- /dev/null +++ b/common/ipc_mutex.h @@ -0,0 +1,47 @@ +#ifndef _MUTEX_H_ +#define _MUTEX_H_ + +#include + +namespace EQEmu { + + //! Interprocess Named Binary Semaphore (Mutex) + /*! + Important to note: while this can be used to synchronize processes, it is not in itself re-entrant or thread-safe + and thus should be used from one thread and non-recursively. It was intended to be a simple synchronization method + for our MemoryMappedFile loading. + */ + class IPCMutex { + struct Implementation; + public: + //! Constructor + /*! + Creates a named binary semaphore, basically a semaphore that is init S <- 1 + \param name The name of this mutex. + */ + IPCMutex(std::string name); + + //! Destructor + ~IPCMutex(); + + //! Lock the mutex + /*! + Same basic function as P(): for(;;) { if(S > 0) { S -= 1; break; } } + */ + bool Lock(); + + //! Unlocks the mutex + /*! + Same basic function as V(): S += 1; + */ + bool Unlock(); + private: + IPCMutex(const IPCMutex&); + const IPCMutex& operator=(const IPCMutex&); + + bool locked_; //!< Whether this mutex is locked or not + Implementation *imp_; + }; +} + +#endif