-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #263 from spacetelescope/refactor/synchronization
Refactor synchronization structure
- Loading branch information
Showing
11 changed files
with
411 additions
and
319 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#ifndef EVENT_H | ||
#define EVENT_H | ||
|
||
#include "EventBase.h" | ||
|
||
template <typename Event> | ||
class EventLockGuard | ||
{ | ||
public: | ||
inline EventLockGuard(Event &event) | ||
: m_Event(event) | ||
{ | ||
m_Event->Lock(); | ||
} | ||
|
||
inline ~EventLockGuard() | ||
{ | ||
m_Event->Unlock(); | ||
} | ||
|
||
private: | ||
Event &m_Event; | ||
}; | ||
|
||
// Select which implementation to use based on the platform. | ||
#ifdef _WIN32 | ||
using Event = EventImpl<EventImplementationType::ET_SEMAPHORE>; | ||
#elif defined(__linux__) or defined(__APPLE__) | ||
using Event = EventImpl<EventImplementationType::ET_CONDITION_VARIABLE>; | ||
#endif | ||
|
||
#endif // EVENT_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
#ifndef EVENT_BASE_H | ||
#define EVENT_BASE_H | ||
|
||
#include <functional> | ||
#include <stdexcept> | ||
|
||
enum EventImplementationType | ||
{ | ||
ET_CONDITION_VARIABLE, | ||
ET_FUTEX, | ||
ET_SEMAPHORE, | ||
ET_SPIN_LOCK | ||
}; | ||
|
||
template<EventImplementationType Type> | ||
struct EventSharedState | ||
{ | ||
}; | ||
|
||
template<EventImplementationType Type> | ||
struct EventLocalState | ||
{ | ||
}; | ||
|
||
template<EventImplementationType Type> | ||
class EventImpl | ||
{ | ||
public: | ||
using SharedState = EventSharedState<Type>; | ||
using LocalState = EventLocalState<Type>; | ||
|
||
protected: | ||
EventImpl(); | ||
|
||
public: | ||
~EventImpl(); | ||
|
||
// Note: do not implement these functions for specific implementations. | ||
static std::unique_ptr<EventImpl<Type>> Create(const std::string &id, SharedState *shared_state); | ||
static std::unique_ptr<EventImpl<Type>> Open(const std::string &id, SharedState *shared_state); | ||
|
||
// Note: implement the following functions for specific implementations. | ||
inline void Wait(long timeout_in_ms, std::function<bool()> condition, void (*error_check)()); | ||
inline void Signal(); | ||
|
||
inline void Lock(); | ||
inline void Unlock(); | ||
|
||
protected: | ||
inline void CreateImpl(const std::string &id, SharedState *shared_state); | ||
inline void OpenImpl(const std::string &id, SharedState *shared_state); | ||
|
||
bool m_IsOwner; | ||
|
||
SharedState *m_SharedState; | ||
LocalState m_LocalState; | ||
}; | ||
|
||
template<enum EventImplementationType Type> | ||
EventImpl<Type>::EventImpl() | ||
: m_IsOwner(false), m_SharedState(nullptr) | ||
{ | ||
} | ||
|
||
template<enum EventImplementationType Type> | ||
EventImpl<Type>::~EventImpl() | ||
{ | ||
} | ||
|
||
template<enum EventImplementationType Type> | ||
void EventImpl<Type>::Wait(long timeout_in_ms, std::function<bool()> condition, void (*error_check)()) | ||
{ | ||
throw std::runtime_error("This type of event implementation wasn't implemented."); | ||
} | ||
|
||
template<enum EventImplementationType Type> | ||
void EventImpl<Type>::Signal() | ||
{ | ||
} | ||
|
||
template<enum EventImplementationType Type> | ||
void EventImpl<Type>::Lock() | ||
{ | ||
} | ||
|
||
template<enum EventImplementationType Type> | ||
void EventImpl<Type>::Unlock() | ||
{ | ||
} | ||
|
||
template<enum EventImplementationType Type> | ||
std::unique_ptr<EventImpl<Type>> EventImpl<Type>::Create(const std::string &id, EventImpl<Type>::SharedState *shared_state) | ||
{ | ||
if (!shared_state) | ||
throw std::runtime_error("The passed shared data was a nullptr."); | ||
|
||
auto obj = std::unique_ptr<EventImpl<Type>>(new EventImpl<Type>()); | ||
|
||
obj->CreateImpl(id, shared_state); | ||
|
||
obj->m_IsOwner = true; | ||
obj->m_SharedState = shared_state; | ||
|
||
return obj; | ||
} | ||
|
||
template<enum EventImplementationType Type> | ||
std::unique_ptr<EventImpl<Type>> EventImpl<Type>::Open(const std::string &id, EventImpl<Type>::SharedState *shared_state) | ||
{ | ||
if (!shared_state) | ||
throw std::runtime_error("The passed shared data was a nullptr."); | ||
|
||
auto obj = std::unique_ptr<EventImpl<Type>>(new EventImpl<Type>()); | ||
|
||
obj->OpenImpl(id, shared_state); | ||
|
||
obj->m_IsOwner = false; | ||
obj->m_SharedState = shared_state; | ||
|
||
return obj; | ||
} | ||
|
||
#include "EventConditionVariable.inl" | ||
#include "EventFutex.inl" | ||
#include "EventSemaphore.inl" | ||
#include "EventSpinLock.inl" | ||
|
||
#endif // EVENT_BASE_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
#include "EventBase.h" | ||
|
||
#include "Timing.h" | ||
|
||
#if defined(__linux__) || defined(__APPLE__) | ||
#include <pthread.h> | ||
#endif | ||
|
||
using EventConditionVariable = EventImpl<EventImplementationType::ET_CONDITION_VARIABLE>; | ||
|
||
#if defined(__linux__) || defined(__APPLE__) | ||
|
||
template<> | ||
struct EventSharedState<EventImplementationType::ET_CONDITION_VARIABLE> | ||
{ | ||
pthread_mutex_t m_Mutex; | ||
pthread_cond_t m_Condition; | ||
}; | ||
|
||
template<> | ||
inline void EventConditionVariable::Wait(long timeout_in_ms, std::function<bool()> condition, void (*error_check)()) | ||
{ | ||
Timer timer; | ||
|
||
while (!condition()) | ||
{ | ||
// Wait for a maximum of 20ms to perform periodic error checking. | ||
long timeout_wait = std::min(20L, timeout_in_ms); | ||
|
||
#ifdef __APPLE__ | ||
// Relative timespec. | ||
timespec timeout; | ||
timeout.tv_sec = timeout_wait / 1000; | ||
timeout.tv_nsec = 1000000 * (timeout_wait % 1000); | ||
|
||
int res = pthread_cond_timedwait_relative_np(&(m_SharedState->m_Condition), &(m_SharedState->m_Mutex), &timeout); | ||
#else | ||
// Absolute timespec. | ||
timespec timeout; | ||
clock_gettime(CLOCK_MONOTONIC, &timeout); | ||
timeout.tv_sec += timeout_wait / 1000; | ||
timeout.tv_nsec += 1000000 * (timeout_wait % 1000); | ||
|
||
int res = pthread_cond_timedwait(&(m_SharedState->m_Condition), &(m_SharedState->m_Mutex), &timeout); | ||
#endif // __APPLE__ | ||
if (res == ETIMEDOUT && timer.GetTime() > (timeout_in_ms * 0.001)) | ||
{ | ||
throw std::runtime_error("Waiting time has expired."); | ||
} | ||
|
||
if (error_check != nullptr) | ||
error_check(); | ||
} | ||
} | ||
|
||
template<> | ||
inline void EventConditionVariable::Signal() | ||
{ | ||
pthread_cond_broadcast(&(m_SharedState->m_Condition)); | ||
} | ||
|
||
template<> | ||
inline void EventConditionVariable::Lock() | ||
{ | ||
pthread_mutex_lock(&(m_SharedState->m_Mutex)); | ||
} | ||
|
||
template<> | ||
inline void EventConditionVariable::Unlock() | ||
{ | ||
pthread_mutex_unlock(&(m_SharedState->m_Mutex)); | ||
} | ||
|
||
template<> | ||
inline void EventConditionVariable::CreateImpl(const std::string &id, EventConditionVariable::SharedState *shared_state) | ||
{ | ||
pthread_mutexattr_t mutex_attr; | ||
pthread_mutexattr_init(&mutex_attr); | ||
pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED); | ||
pthread_mutex_init(&(shared_state->m_Mutex), &mutex_attr); | ||
pthread_mutexattr_destroy(&mutex_attr); | ||
|
||
pthread_condattr_t cond_attr; | ||
pthread_condattr_init(&cond_attr); | ||
pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED); | ||
#ifndef __APPLE__ | ||
pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC); | ||
#endif // __APPLE__ | ||
pthread_cond_init(&(shared_state->m_Condition), &cond_attr); | ||
pthread_condattr_destroy(&cond_attr); | ||
} | ||
|
||
template<> | ||
inline void EventConditionVariable::OpenImpl(const std::string &id, EventConditionVariable::SharedState *shared_state) | ||
{ | ||
// Nothing to do. | ||
} | ||
|
||
#endif |
Empty file.
Oops, something went wrong.