Skip to content

Commit d5f5d04

Browse files
committed
Fix ChunkLock final problem
1 parent fe78b9a commit d5f5d04

1 file changed

Lines changed: 55 additions & 22 deletions

File tree

include/CommonLib/ChunkLock.inl

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,36 @@
66

77
namespace tsom
88
{
9+
namespace Detail
10+
{
11+
template<bool Write, typename T>
12+
void LockChunk(T* chunk)
13+
{
14+
if constexpr (Write)
15+
chunk->LockWrite();
16+
else
17+
chunk->LockRead();
18+
}
19+
20+
template<bool Write, typename T>
21+
bool TryLockChunk(T* chunk)
22+
{
23+
if constexpr (Write)
24+
return chunk->TryLockWrite();
25+
else
26+
return chunk->TryLockRead();
27+
}
28+
29+
template<bool Write, typename T>
30+
void UnlockChunk(T* chunk)
31+
{
32+
if constexpr (Write)
33+
chunk->UnlockWrite();
34+
else
35+
chunk->UnlockRead();
36+
}
37+
}
38+
939
template<bool Write>
1040
ChunkLock<Write>::ChunkLock(ChunkType chunk) :
1141
m_chunk(chunk),
@@ -46,23 +76,17 @@ namespace tsom
4676
void ChunkLock<Write>::Lock()
4777
{
4878
NazaraAssertMsg(!m_isLocked, "ChunkLock is already locked");
49-
if constexpr (Write)
50-
m_chunk->LockWrite();
51-
else
52-
m_chunk->LockRead();
5379

80+
Detail::LockChunk<Write>(m_chunk);
5481
m_isLocked = true;
5582
}
5683

5784
template<bool Write>
5885
void ChunkLock<Write>::Unlock()
5986
{
6087
NazaraAssertMsg(m_isLocked, "ChunkLock isn't locked");
61-
if constexpr (Write)
62-
m_chunk->UnlockWrite();
63-
else
64-
m_chunk->UnlockRead();
6588

89+
Detail::UnlockChunk<Write>(m_chunk);
6690
m_isLocked = false;
6791
}
6892

@@ -91,6 +115,7 @@ namespace tsom
91115
void MultiChunkLock<Write, Max>::AddChunk(ChunkType chunk)
92116
{
93117
NazaraAssertMsg(!m_isLocked, "ChunkLock is already locked");
118+
NazaraAssertMsg(std::find(m_chunks.begin(), m_chunks.end(), chunk) == m_chunks.end(), "Chunk is already in the list");
94119
m_chunks.push_back(chunk);
95120
}
96121

@@ -99,24 +124,32 @@ namespace tsom
99124
{
100125
// Algorithm to lock every chunk without deadlock
101126
std::size_t lastFailureMutex = Nz::MaxValue();
127+
102128
for (;;)
103129
{
104130
bool succeeded = true;
105131
for (std::size_t i = 0; i < m_chunks.size(); ++i)
106132
{
107-
if (i != lastFailureMutex && !m_chunks[i]->TryLockRead())
108-
{
109-
succeeded = false;
110-
111-
// Lock failed, unlock everything and try again
112-
for (std::size_t j = 0; j < i; ++j)
113-
m_chunks[j]->UnlockRead();
114-
115-
// Lock blocked chunk first to pause thread
116-
m_chunks[i]->LockRead();
117-
lastFailureMutex = i;
118-
break;
119-
}
133+
if (i == lastFailureMutex)
134+
continue;
135+
136+
if (Detail::TryLockChunk<Write>(m_chunks[i]))
137+
continue;
138+
139+
// Lock failed, unlock everything and try again
140+
succeeded = false;
141+
142+
for (std::size_t j = 0; j < i; ++j)
143+
Detail::UnlockChunk<Write>(m_chunks[j]);
144+
145+
if (lastFailureMutex > i && lastFailureMutex < m_chunks.size())
146+
Detail::UnlockChunk<Write>(m_chunks[lastFailureMutex]);
147+
148+
// Lock blocked chunk first to pause thread
149+
Detail::LockChunk<Write>(m_chunks[i]);
150+
151+
lastFailureMutex = i;
152+
break;
120153
}
121154

122155
if (succeeded)
@@ -131,7 +164,7 @@ namespace tsom
131164
{
132165
NazaraAssertMsg(m_isLocked, "ChunkLock isn't locked");
133166
for (const Chunk* chunk : m_chunks)
134-
chunk->UnlockRead();
167+
Detail::UnlockChunk<Write>(chunk);
135168

136169
m_isLocked = false;
137170
}

0 commit comments

Comments
 (0)