blob: 609b2f5ce7f6ca1a1c2865e6753c28fd414f2879 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
#include "semaphore.h"
#include "exceptionex.h"
RecursiveBenaphore::RecursiveBenaphore() : m_Counter(0), m_OwnerId(0UL), m_Recursion(0)
{
m_Semaphore = ::CreateSemaphore(nullptr, 1, 1, nullptr);
}
RecursiveBenaphore::~RecursiveBenaphore()
{
::CloseHandle(m_Semaphore);
}
void RecursiveBenaphore::wait(DWORD timeout)
{
DWORD tid = ::GetCurrentThreadId();
if (::_InterlockedIncrement(&m_Counter) > 1) {
if (tid != m_OwnerId) {
int tries = 3;
while (::WaitForSingleObject(m_Semaphore, timeout) != WAIT_OBJECT_0) {
HANDLE owner = ::OpenThread(SYNCHRONIZE, FALSE, m_OwnerId);
ON_BLOCK_EXIT([owner]() {
::CloseHandle(owner);
});
if ((tries <= 0) || (::WaitForSingleObject(owner, 0) == WAIT_OBJECT_0)) {
// owner has quit without releasing the semaphore!
m_Recursion = 0;
spdlog::get("usvfs")->error("thread {} never released the mutex", m_OwnerId);
break;
} else {
--tries;
}
}
}
}
m_OwnerId = tid;
++m_Recursion;
}
void RecursiveBenaphore::signal()
{
if (m_Recursion == 0) {
return;
}
// no validation the signaling thread is the one owning the lock
DWORD recursion = --m_Recursion;
if (recursion == 0) {
m_OwnerId = 0;
}
DWORD result = ::_InterlockedDecrement(&m_Counter);
if (result > 0) {
if (recursion == 0) {
::ReleaseSemaphore(m_Semaphore, 1, nullptr);
}
}
}
|