kernel: Rewrite KDEBUG_RW_LOCK_DEBUG.

Previously this just turned the rw_lock into the equivalent of a
recursive_lock, which meant that reader vs. writer assertions
were of no use.

Now, we have a per-thread static array which stores the held read
locks, allowing ASSERT_READ_LOCKED_RW_LOCK to work properly,
and allowing multiple readers to be active at a time.

This probably should still remain disabled even on nightly builds,
but at least it's much more useful as a debugging tool than it was
beforehand.

Change-Id: I386b2bc2ada8df42f4ab11a05563ef22af58e77f
This commit is contained in:
Augustin Cavalier
2023-06-29 21:04:40 -04:00
parent 50330091b0
commit 30fda09a95
3 changed files with 112 additions and 9 deletions
+9 -5
View File
@@ -72,23 +72,27 @@ typedef struct rw_lock {
#if KDEBUG
# define KDEBUG_RW_LOCK_DEBUG 0
// Define to 1 if you want to use ASSERT_READ_LOCKED_RW_LOCK().
// The rw_lock will just behave like a recursive locker then.
# define ASSERT_LOCKED_RECURSIVE(r) \
{ ASSERT(find_thread(NULL) == (r)->lock.holder); }
# define ASSERT_LOCKED_MUTEX(m) { ASSERT(find_thread(NULL) == (m)->holder); }
# define ASSERT_WRITE_LOCKED_RW_LOCK(l) \
{ ASSERT(find_thread(NULL) == (l)->holder); }
# if KDEBUG_RW_LOCK_DEBUG
extern bool _rw_lock_is_read_locked(rw_lock* lock);
# define ASSERT_READ_LOCKED_RW_LOCK(l) \
{ ASSERT(find_thread(NULL) == (l)->holder); }
{ ASSERT_PRINT(_rw_lock_is_read_locked(l), "rwlock %p", l); }
# define ASSERT_UNLOCKED_RW_LOCK(l) \
{ ASSERT_PRINT(!_rw_lock_is_read_locked(l), "rwlock %p", l); }
# else
# define ASSERT_READ_LOCKED_RW_LOCK(l) do {} while (false)
# define ASSERT_UNLOCKED_RW_LOCK(l) do {} while (false)
# endif
#else
# define ASSERT_LOCKED_RECURSIVE(r) do {} while (false)
# define ASSERT_LOCKED_MUTEX(m) do {} while (false)
# define ASSERT_WRITE_LOCKED_RW_LOCK(m) do {} while (false)
# define ASSERT_READ_LOCKED_RW_LOCK(l) do {} while (false)
# define ASSERT_UNLOCKED_RW_LOCK(l) do {} while (false)
#endif
@@ -180,7 +184,7 @@ static inline status_t
rw_lock_read_lock(rw_lock* lock)
{
#if KDEBUG_RW_LOCK_DEBUG
return rw_lock_write_lock(lock);
return _rw_lock_read_lock(lock);
#else
int32 oldCount = atomic_add(&lock->count, 1);
if (oldCount >= RW_LOCK_WRITER_COUNT_BASE)
@@ -195,7 +199,7 @@ rw_lock_read_lock_with_timeout(rw_lock* lock, uint32 timeoutFlags,
bigtime_t timeout)
{
#if KDEBUG_RW_LOCK_DEBUG
return mutex_lock_with_timeout(lock, timeoutFlags, timeout);
return _rw_lock_read_lock_with_timeout(lock, timeoutFlags, timeout);
#else
int32 oldCount = atomic_add(&lock->count, 1);
if (oldCount >= RW_LOCK_WRITER_COUNT_BASE)
@@ -209,7 +213,7 @@ static inline void
rw_lock_read_unlock(rw_lock* lock)
{
#if KDEBUG_RW_LOCK_DEBUG
rw_lock_write_unlock(lock);
_rw_lock_read_unlock(lock);
#else
int32 oldCount = atomic_add(&lock->count, -1);
if (oldCount >= RW_LOCK_WRITER_COUNT_BASE)
+4
View File
@@ -547,6 +547,10 @@ struct Thread : TeamThreadIteratorEntry<thread_id>, KernelReferenceable {
void (*post_interrupt_callback)(void*);
void* post_interrupt_data;
#if KDEBUG_RW_LOCK_DEBUG
rw_lock* held_read_locks[64] = {}; // only modified by this thread
#endif
// architecture dependent section
struct arch_thread arch_info;