#pragma once
#if defined(WIN32) || defined(_WIN32)
#include <Windows.h>
#else
#include <pthread.h>
#include <errno.h>
unsigned long long GetTickCount64();
#endif
class CMyEvent
{
public:
CMyEvent(bool autoReset = true);
~CMyEvent();
void set();
void wait();
bool wait(long milliseconds);
void reset();
private:
#if defined(WIN32) || defined(_WIN32)
HANDLE _event;
#else
bool _auto;
volatile bool _state;
pthread_mutex_t _mutex;
pthread_cond_t _cond;
#endif
};
class CMyRWLock
{
public:
CMyRWLock();
~CMyRWLock();
void readLock();
bool tryReadLock();
void writeLock();
bool tryWriteLock();
void unlock();
private:
#if defined(WIN32) || defined(_WIN32)
void addWriter();
void removeWriter();
unsigned long tryReadLockOnce();
HANDLE _mutex;
HANDLE _readEvent;
HANDLE _writeEvent;
unsigned _readers;
unsigned _writersWaiting;
unsigned _writers;
#else
pthread_rwlock_t _rwl;
#endif
};
class CMyWriteLocker
{
public:
CMyWriteLocker(CMyRWLock *pLock):
m_pLock(pLock)
{
if (m_pLock)
{
m_pLock->writeLock();
}
}
~CMyWriteLocker()
{
if (m_pLock)
{
m_pLock->unlock();
}
}
private:
CMyRWLock* m_pLock;
};
class CMyReadLocker
{
public:
CMyReadLocker(CMyRWLock *pLock) :
m_pLock(pLock)
{
if (m_pLock)
{
m_pLock->readLock();
}
}
~CMyReadLocker()
{
if (m_pLock)
{
m_pLock->unlock();
}
}
private:
CMyRWLock* m_pLock;
};
#include "CMyEvent.h"
#include "siplog.h"
#if defined(WIN32) || defined(_WIN32)
CMyEvent::CMyEvent(bool autoReset)
{
_event = CreateEventW(NULL, autoReset ? FALSE : TRUE, FALSE, NULL);
}
CMyEvent::~CMyEvent()
{
CloseHandle(_event);
}
void CMyEvent::set()
{
SetEvent(_event);
}
void CMyEvent::wait()
{
switch (WaitForSingleObject(_event, INFINITE))
{
case WAIT_OBJECT_0:
return;
default:
return;
}
}
bool CMyEvent::wait(long milliseconds)
{
switch (WaitForSingleObject(_event, milliseconds + 1))
{
case WAIT_TIMEOUT:
return false;
case WAIT_OBJECT_0:
return true;
default:
return false;
}
}
void CMyEvent::reset()
{
ResetEvent(_event);
}
#else
#include <time.h>
#include <sys/time.h>
CMyEvent::CMyEvent(bool autoReset) : _auto(autoReset), _state(false)
{
if (pthread_mutex_init(&_mutex, NULL))
ERROR_LOG("cannot create event (mutex)");
if (pthread_cond_init(&_cond, NULL))
{
pthread_mutex_destroy(&_mutex);
ERROR_LOG("cannot create event (condition)");
}
}
CMyEvent::~CMyEvent()
{
pthread_cond_destroy(&_cond);
pthread_mutex_destroy(&_mutex);
}
void CMyEvent::set()
{
if (pthread_mutex_lock(&_mutex))
ERROR_LOG("cannot signal event(lock)");
_state = true;
if (pthread_cond_broadcast(&_cond))
{
pthread_mutex_unlock(&_mutex);
ERROR_LOG("cannot signal event");
}
pthread_mutex_unlock(&_mutex);
}
void CMyEvent::wait()
{
if (pthread_mutex_lock(&_mutex))
ERROR_LOG("wait for event failed (lock)");
while (!_state)
{
if (pthread_cond_wait(&_cond, &_mutex))
{
pthread_mutex_unlock(&_mutex);
ERROR_LOG("wait for event failed");
}
}
if (_auto)
_state = false;
pthread_mutex_unlock(&_mutex);
}
bool CMyEvent::wait(long milliseconds)
{
int rc = 0;
struct timespec abstime;
struct timeval tv;
gettimeofday(&tv, NULL);
abstime.tv_sec = tv.tv_sec + milliseconds / 1000;
abstime.tv_nsec = tv.tv_usec * 1000 + (milliseconds % 1000) * 1000000;
if (abstime.tv_nsec >= 1000000000)
{
abstime.tv_nsec -= 1000000000;
abstime.tv_sec++;
}
if (pthread_mutex_lock(&_mutex) != 0)
ERROR_LOG("wait for event failed (lock)");
while (!_state)
{
if ((rc = pthread_cond_timedwait(&_cond, &_mutex, &abstime)))
{
if (rc == ETIMEDOUT) break;
pthread_mutex_unlock(&_mutex);
ERROR_LOG("cannot wait for event");
}
}
if (rc == 0 && _auto) _state = false;
pthread_mutex_unlock(&_mutex);
return rc == 0;
}
void CMyEvent::reset()
{
if (pthread_mutex_lock(&_mutex))
ERROR_LOG("cannot reset event");
_state = false;
pthread_mutex_unlock(&_mutex);
}
#endif
#if defined(WIN32) || defined(_WIN32)
CMyRWLock::CMyRWLock() : _readers(0), _writersWaiting(0), _writers(0)
{
_mutex = CreateMutexW(NULL, FALSE, NULL);
if (_mutex == NULL)
return;
_readEvent = CreateEventW(NULL, TRUE, TRUE, NULL);
if (_readEvent == NULL)
return;
_writeEvent = CreateEventW(NULL, TRUE, TRUE, NULL);
if (_writeEvent == NULL)
return;
}
CMyRWLock::~CMyRWLock()
{
CloseHandle(_mutex);
CloseHandle(_readEvent);
CloseHandle(_writeEvent);
}
void CMyRWLock::readLock()
{
HANDLE h[2];
h[0] = _mutex;
h[1] = _readEvent;
switch (WaitForMultipleObjects(2, h, TRUE, INFINITE))
{
case WAIT_OBJECT_0:
case WAIT_OBJECT_0 + 1:
++_readers;
ResetEvent(_writeEvent);
ReleaseMutex(_mutex);
break;
default:
break;;
}
}
bool CMyRWLock::tryReadLock()
{
for (;;)
{
if (_writers != 0 || _writersWaiting != 0)
return false;
DWORD result = tryReadLockOnce();
switch (result)
{
case WAIT_OBJECT_0:
case WAIT_OBJECT_0 + 1:
return true;
case WAIT_TIMEOUT:
continue; // try again
default:
return false;
}
}
}
void CMyRWLock::writeLock()
{
addWriter();
HANDLE h[2];
h[0] = _mutex;
h[1] = _writeEvent;
switch (WaitForMultipleObjects(2, h, TRUE, INFINITE))
{
case WAIT_OBJECT_0:
case WAIT_OBJECT_0 + 1:
--_writersWaiting;
++_readers;
++_writers;
ResetEvent(_readEvent);
ResetEvent(_writeEvent);
ReleaseMutex(_mutex);
break;
default:
removeWriter();
break;
}
}
bool CMyRWLock::tryWriteLock()
{
addWriter();
HANDLE h[2];
h[0] = _mutex;
h[1] = _writeEvent;
switch (WaitForMultipleObjects(2, h, TRUE, 1))
{
case WAIT_OBJECT_0:
case WAIT_OBJECT_0 + 1:
--_writersWaiting;
++_readers;
++_writers;
ResetEvent(_readEvent);
ResetEvent(_writeEvent);
ReleaseMutex(_mutex);
return true;
case WAIT_TIMEOUT:
removeWriter();
return false;
default:
removeWriter();
break;
}
return false;
}
void CMyRWLock::unlock()
{
switch (WaitForSingleObject(_mutex, INFINITE))
{
case WAIT_OBJECT_0:
_writers = 0;
if (_writersWaiting == 0) SetEvent(_readEvent);
if (--_readers == 0) SetEvent(_writeEvent);
ReleaseMutex(_mutex);
break;
default:
break;
}
}
void CMyRWLock::addWriter()
{
switch (WaitForSingleObject(_mutex, INFINITE))
{
case WAIT_OBJECT_0:
if (++_writersWaiting == 1) ResetEvent(_readEvent);
ReleaseMutex(_mutex);
break;
default:
break;;
}
}
void CMyRWLock::removeWriter()
{
switch (WaitForSingleObject(_mutex, INFINITE))
{
case WAIT_OBJECT_0:
if (--_writersWaiting == 0 && _writers == 0) SetEvent(_readEvent);
ReleaseMutex(_mutex);
break;
default:
break;
}
}
unsigned long CMyRWLock::tryReadLockOnce()
{
HANDLE h[2];
h[0] = _mutex;
h[1] = _readEvent;
DWORD result = WaitForMultipleObjects(2, h, TRUE, 1);
switch (result)
{
case WAIT_OBJECT_0:
case WAIT_OBJECT_0 + 1:
++_readers;
ResetEvent(_writeEvent);
ReleaseMutex(_mutex);
return result;
case WAIT_TIMEOUT:
return result;
default:
break;;
}
return false;
}
#else
unsigned long long GetTickCount64()
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
}
CMyRWLock::CMyRWLock()
{
if (pthread_rwlock_init(&_rwl, NULL))
ERROR_LOG("cannot create reader/writer lock\n");
}
CMyRWLock::~CMyRWLock()
{
pthread_rwlock_destroy(&_rwl);
}
void CMyRWLock::readLock()
{
if (pthread_rwlock_rdlock(&_rwl))
ERROR_LOG("cannot lock reader/writer lock\n");
}
bool CMyRWLock::tryReadLock()
{
int rc = pthread_rwlock_tryrdlock(&_rwl);
if (rc == 0)
return true;
else if (rc == EBUSY)
return false;
else
ERROR_LOG("cannot lock reader/writer lock\n");
return false;
}
void CMyRWLock::writeLock()
{
if (pthread_rwlock_wrlock(&_rwl))
ERROR_LOG("cannot lock reader/writer lock\n");
}
bool CMyRWLock::tryWriteLock()
{
int rc = pthread_rwlock_trywrlock(&_rwl);
if (rc == 0)
return true;
else if (rc == EBUSY)
return false;
else
ERROR_LOG("cannot lock reader/writer lock\n");
return false;
}
void CMyRWLock::unlock()
{
if (pthread_rwlock_unlock(&_rwl))
ERROR_LOG("cannot unlock mutex\n");
}
#endif