diff --git a/renderdoc/os/os_specific.h b/renderdoc/os/os_specific.h index 88100ca17..471223cbf 100644 --- a/renderdoc/os/os_specific.h +++ b/renderdoc/os/os_specific.h @@ -146,6 +146,17 @@ uint64_t AllocateTLSSlot(); void *GetTLSValue(uint64_t slot); void SetTLSValue(uint64_t slot, void *value); +struct Semaphore +{ + static Semaphore *Create(); + void Destroy(); + void Wake(uint32_t numToWake); + void WaitForWake(); +protected: + Semaphore(); + ~Semaphore(); +}; + // must typedef CriticalSectionTemplate CriticalSection void SetCurrentThreadName(const rdcstr &name); diff --git a/renderdoc/os/posix/android/android_threading.cpp b/renderdoc/os/posix/android/android_threading.cpp index 58474fcbd..73700aa0b 100644 --- a/renderdoc/os/posix/android/android_threading.cpp +++ b/renderdoc/os/posix/android/android_threading.cpp @@ -24,6 +24,10 @@ #include "os/os_specific.h" +#include "common/common.h" + +#include +#include #include #include @@ -42,3 +46,67 @@ uint64_t Timing::GetTick() void Threading::SetCurrentThreadName(const rdcstr &name) { } + +namespace Threading +{ + +// works for all posix except apple, hence being here +struct PosixSemaphore : public Semaphore +{ + ~PosixSemaphore() {} + + sem_t h; +}; + +Semaphore *Semaphore::Create() +{ + PosixSemaphore *sem = new PosixSemaphore(); + int err = sem_init(&sem->h, 0, 0); + // only documented errors are too large initial value (impossible for 0) or for shared semaphores + // going wrong (we're not shared) + RDCASSERT(err == 0, errno); + return sem; +} + +void Semaphore::Destroy() +{ + PosixSemaphore *sem = (PosixSemaphore *)this; + sem_destroy(&sem->h); + delete sem; +} + +void Semaphore::Wake(uint32_t numToWake) +{ + PosixSemaphore *sem = (PosixSemaphore *)this; + for(uint32_t i = 0; i < numToWake; i++) + sem_post(&sem->h); +} + +void Semaphore::WaitForWake() +{ + PosixSemaphore *sem = (PosixSemaphore *)this; + + // handle extremely moronic stupid signal interruptions + do + { + int ret = sem_wait(&sem->h); + + if(ret == -1) + { + if(errno == EINTR) + continue; + + RDCWARN("Semaphore wait failed: %d", errno); + } + } while(false); +} + +Semaphore::Semaphore() +{ +} + +Semaphore::~Semaphore() +{ +} + +}; diff --git a/renderdoc/os/posix/apple/apple_threading.cpp b/renderdoc/os/posix/apple/apple_threading.cpp index 3c88b26c5..068a31232 100644 --- a/renderdoc/os/posix/apple/apple_threading.cpp +++ b/renderdoc/os/posix/apple/apple_threading.cpp @@ -24,6 +24,7 @@ #include "os/os_specific.h" +#include #include double Timing::GetTickFrequency() @@ -44,3 +45,51 @@ uint64_t Timing::GetTick() void Threading::SetCurrentThreadName(const rdcstr &name) { } + +namespace Threading +{ + +struct AppleSemaphore : public Semaphore +{ + ~AppleSemaphore() {} + + dispatch_semaphore_t h; +}; + +Semaphore *Semaphore::Create() +{ + AppleSemaphore *sem = new AppleSemaphore(); + sem->h = dispatch_semaphore_create(0); + return sem; +} + +void Semaphore::Destroy() +{ + AppleSemaphore *sem = (AppleSemaphore *)this; + dispatch_release(sem->h); + delete sem; +} + +void Semaphore::Wake(uint32_t numToWake) +{ + AppleSemaphore *sem = (AppleSemaphore *)this; + for(uint32_t i = 0; i < numToWake; i++) + dispatch_semaphore_signal(sem->h); +} + +void Semaphore::WaitForWake() +{ + AppleSemaphore *sem = (AppleSemaphore *)this; + // no timeout, so no point checking return value as that's the only failure case + dispatch_semaphore_wait(sem->h, DISPATCH_TIME_FOREVER); +} + +Semaphore::Semaphore() +{ +} + +Semaphore::~Semaphore() +{ +} + +}; diff --git a/renderdoc/os/posix/linux/linux_threading.cpp b/renderdoc/os/posix/linux/linux_threading.cpp index 3f3c280fd..ce6b7f806 100644 --- a/renderdoc/os/posix/linux/linux_threading.cpp +++ b/renderdoc/os/posix/linux/linux_threading.cpp @@ -24,6 +24,10 @@ #include "os/os_specific.h" +#include "common/common.h" + +#include +#include #include #include #include @@ -44,3 +48,67 @@ void Threading::SetCurrentThreadName(const rdcstr &name) { prctl(PR_SET_NAME, (unsigned long)name.c_str(), 0, 0, 0); } + +namespace Threading +{ + +// works for all posix except apple, hence being here +struct PosixSemaphore : public Semaphore +{ + ~PosixSemaphore() {} + + sem_t h; +}; + +Semaphore *Semaphore::Create() +{ + PosixSemaphore *sem = new PosixSemaphore(); + int err = sem_init(&sem->h, 0, 0); + // only documented errors are too large initial value (impossible for 0) or for shared semaphores + // going wrong (we're not shared) + RDCASSERT(err == 0, errno); + return sem; +} + +void Semaphore::Destroy() +{ + PosixSemaphore *sem = (PosixSemaphore *)this; + sem_destroy(&sem->h); + delete sem; +} + +void Semaphore::Wake(uint32_t numToWake) +{ + PosixSemaphore *sem = (PosixSemaphore *)this; + for(uint32_t i = 0; i < numToWake; i++) + sem_post(&sem->h); +} + +void Semaphore::WaitForWake() +{ + PosixSemaphore *sem = (PosixSemaphore *)this; + + // handle extremely moronic stupid signal interruptions + do + { + int ret = sem_wait(&sem->h); + + if(ret == -1) + { + if(errno == EINTR) + continue; + + RDCWARN("Semaphore wait failed: %d", errno); + } + } while(false); +} + +Semaphore::Semaphore() +{ +} + +Semaphore::~Semaphore() +{ +} + +}; diff --git a/renderdoc/os/win32/win32_threading.cpp b/renderdoc/os/win32/win32_threading.cpp index b99f0346d..a8b15d317 100644 --- a/renderdoc/os/win32/win32_threading.cpp +++ b/renderdoc/os/win32/win32_threading.cpp @@ -368,4 +368,48 @@ void Sleep(uint32_t milliseconds) { ::Sleep((DWORD)milliseconds); } + +struct Win32Semaphore : public Semaphore +{ + ~Win32Semaphore() {} + + HANDLE h; +}; + +Semaphore *Semaphore::Create() +{ + Win32Semaphore *sem = new Win32Semaphore(); + sem->h = CreateSemaphore(NULL, 0, 0xffff, NULL); + return sem; +} + +void Semaphore::Destroy() +{ + Win32Semaphore *sem = (Win32Semaphore *)this; + CloseHandle(sem->h); + delete sem; +} + +void Semaphore::Wake(uint32_t numToWake) +{ + Win32Semaphore *sem = (Win32Semaphore *)this; + ReleaseSemaphore(sem->h, numToWake, NULL); +} + +void Semaphore::WaitForWake() +{ + Win32Semaphore *sem = (Win32Semaphore *)this; + DWORD err = WaitForSingleObject(sem->h, INFINITE); + if(err == WAIT_FAILED) + RDCWARN("Semaphore failed to sleep: %d", GetLastError()); +} + +Semaphore::Semaphore() +{ +} + +Semaphore::~Semaphore() +{ +} + };