Skip to content

Commit 39706c1

Browse files
committed
RWLock: Add function to update the associated thread to the writing
This is required for: aseprite/aseprite#4991
1 parent de781a5 commit 39706c1

File tree

2 files changed

+44
-37
lines changed

2 files changed

+44
-37
lines changed

base/rw_lock.cpp

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// LAF Base Library
2-
// Copyright (C) 2020-2024 Igara Studio S.A.
2+
// Copyright (C) 2020-2025 Igara Studio S.A.
33
// Copyright (C) 2001-2016 David Capello
44
//
55
// This file is released under the terms of the MIT license.
@@ -11,15 +11,15 @@
1111

1212
#include "base/rw_lock.h"
1313

14-
// Uncomment this line in case that you want TRACE() lock/unlock
15-
// operations.
16-
// #define DEBUG_OBJECT_LOCKS
17-
1814
#include "base/debug.h"
1915
#include "base/thread.h"
2016

2117
#include <algorithm>
2218

19+
// Uncomment this line in case that you want TRACEARGS() lock/unlock
20+
// operations.
21+
#define LCK_TRACE(...) // TRACEARGS(__VA_ARGS__)
22+
2323
namespace base {
2424

2525
RWLock::RWLock()
@@ -51,7 +51,8 @@ bool RWLock::canWriteLockFromRead() const
5151
RWLock::LockResult RWLock::lock(LockType lockType, int timeout)
5252
{
5353
// Check for re-entrant write locks (multiple write-lock in the same
54-
// thread are allowed).
54+
// thread are allowed, even a read lock if we are writing in the
55+
// same thread).
5556
// if (lockType == WriteLock) {
5657
{
5758
const std::lock_guard lock(m_mutex);
@@ -92,9 +93,7 @@ RWLock::LockResult RWLock::lock(LockType lockType, int timeout)
9293
m_write_lock = true;
9394
m_write_thread = std::this_thread::get_id();
9495

95-
#ifdef DEBUG_OBJECT_LOCKS
96-
TRACE("LCK: lock: Locked <%p> to write\n", this);
97-
#endif
96+
LCK_TRACE("LCK: lock: Locked", this, "to write in thread", m_write_thread);
9897
return LockResult::OK;
9998
}
10099
break;
@@ -107,24 +106,22 @@ RWLock::LockResult RWLock::lock(LockType lockType, int timeout)
107106
const int delay = std::min(100, timeout);
108107
timeout -= delay;
109108

110-
#ifdef DEBUG_OBJECT_LOCKS
111-
TRACE("LCK: lock: wait 100 msecs for <%p>\n", this);
112-
#endif
113-
109+
LCK_TRACE("LCK: lock: wait 100 msecs for", this);
114110
base::this_thread::sleep_for(double(delay) / 1000.0);
115111
}
116112
else
117113
break;
118114
}
119115

120-
#ifdef DEBUG_OBJECT_LOCKS
121-
TRACE("LCK: lock: Cannot lock <%p> to %s (has %d read locks and %d write locks)\n",
122-
this,
123-
(lockType == ReadLock ? "read" : "write"),
124-
m_read_locks,
125-
m_write_lock);
126-
#endif
127-
116+
LCK_TRACE("LCK: lock: Cannot lock",
117+
this,
118+
"to",
119+
(lockType == ReadLock ? "read" : "write"),
120+
"(has",
121+
m_read_locks,
122+
"read locks and",
123+
m_write_lock,
124+
"write locks)");
128125
return LockResult::Fail;
129126
}
130127

@@ -222,10 +219,7 @@ RWLock::LockResult RWLock::upgradeToWrite(int timeout)
222219
m_write_lock = true;
223220
m_write_thread = std::this_thread::get_id();
224221

225-
#ifdef DEBUG_OBJECT_LOCKS
226-
TRACE("LCK: upgradeToWrite: Locked <%p> to write\n", this);
227-
#endif
228-
222+
LCK_TRACE("LCK: upgradeToWrite: Locked", this, "to write in thread", m_write_thread);
229223
return LockResult::OK;
230224
}
231225

@@ -236,24 +230,31 @@ RWLock::LockResult RWLock::upgradeToWrite(int timeout)
236230
const int delay = std::min(100, timeout);
237231
timeout -= delay;
238232

239-
#ifdef DEBUG_OBJECT_LOCKS
240-
TRACE("LCK: upgradeToWrite: wait 100 msecs for <%p>\n", this);
241-
#endif
242-
233+
LCK_TRACE("LCK: upgradeToWrite: wait 100 msecs for", this);
243234
base::this_thread::sleep_for(double(delay) / 1000.0);
244235
}
245236
else
246237
break;
247238
}
248239

249-
#ifdef DEBUG_OBJECT_LOCKS
250-
TRACE("LCK: upgradeToWrite: Cannot lock <%p> to write (has %d read locks and %d write locks)\n",
251-
this,
252-
m_read_locks,
253-
m_write_lock);
254-
#endif
255-
240+
LCK_TRACE("LCK: upgradeToWrite: Cannot lock",
241+
this,
242+
"to write (has",
243+
m_read_locks,
244+
"read locks and",
245+
m_write_lock,
246+
"write locks)");
256247
return LockResult::Fail;
257248
}
258249

250+
void RWLock::updateWriterThread()
251+
{
252+
const std::lock_guard lock(m_mutex);
253+
if (m_write_lock) {
254+
m_write_thread = std::this_thread::get_id();
255+
256+
LCK_TRACE("LCK: updateWriterThread: Lock", this, "has new writer thread", m_write_thread);
257+
}
258+
}
259+
259260
} // namespace base

base/rw_lock.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// LAF Base Library
2-
// Copyright (C) 2020-2023 Igara Studio S.A.
2+
// Copyright (C) 2020-2025 Igara Studio S.A.
33
// Copyright (C) 2001-2016 David Capello
44
//
55
// This file is released under the terms of the MIT license.
@@ -55,6 +55,12 @@ class RWLock {
5555
// raise your access level to write it.
5656
LockResult upgradeToWrite(int timeout);
5757

58+
// You can use this function when you've write-locked the RWLock in
59+
// one thread but want to update the writer thread (m_write_thread)
60+
// to the current thread (e.g. a worker thread) that is going to do
61+
// the writing.
62+
void updateWriterThread();
63+
5864
// If we've locked the object to write, using this method we can
5965
// lower our access to read-only.
6066
void downgradeToRead(LockResult lockResult);

0 commit comments

Comments
 (0)