kernel/lock: Fix ABI compatibility between KDEBUG and non-KDEBUG builds.

This breaks kernel ABI on KDEBUG builds (but not non-KDEBUG builds),
but it does so in order to resolve a long-standing incompatibility
between them: until now, any kernel add-ons built against one which
made use of these lock facilities could not be run on the other;
instead you would get hangs and/or crashes.

After this change, kernel add-ons built with a KDEBUG configuration
should work on a non-KDEBUG kernel, while add-ons built with a
non-KDEBUG configuration will fail to load on a KDEBUG kernel
with unresolved symbols, preventing incorrect and broken operation.
This commit is contained in:
Augustin Cavalier
2024-09-09 22:35:05 -04:00
parent cf5249749d
commit f4e0ce8d61
2 changed files with 83 additions and 40 deletions
+12 -15
View File
@@ -164,6 +164,14 @@ extern status_t mutex_switch_lock(mutex* from, mutex* to);
extern status_t mutex_switch_from_read_lock(rw_lock* from, mutex* to); extern status_t mutex_switch_from_read_lock(rw_lock* from, mutex* to);
// Like mutex_switch_lock(), just for switching from a read-locked rw_lock. // Like mutex_switch_lock(), just for switching from a read-locked rw_lock.
#if KDEBUG
extern status_t mutex_lock(mutex* lock);
extern void mutex_unlock(mutex* lock);
extern status_t mutex_trylock(mutex* lock);
extern status_t mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags,
bigtime_t timeout);
#endif
// implementation private: // implementation private:
@@ -173,11 +181,12 @@ extern status_t _rw_lock_read_lock_with_timeout(rw_lock* lock,
extern void _rw_lock_read_unlock(rw_lock* lock); extern void _rw_lock_read_unlock(rw_lock* lock);
extern void _rw_lock_write_unlock(rw_lock* lock); extern void _rw_lock_write_unlock(rw_lock* lock);
#if !KDEBUG
extern status_t _mutex_lock(mutex* lock, void* locker); extern status_t _mutex_lock(mutex* lock, void* locker);
extern void _mutex_unlock(mutex* lock); extern void _mutex_unlock(mutex* lock);
extern status_t _mutex_trylock(mutex* lock);
extern status_t _mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, extern status_t _mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags,
bigtime_t timeout); bigtime_t timeout);
#endif
static inline status_t static inline status_t
@@ -229,53 +238,41 @@ rw_lock_write_unlock(rw_lock* lock)
} }
#if !KDEBUG
static inline status_t static inline status_t
mutex_lock(mutex* lock) mutex_lock(mutex* lock)
{ {
#if KDEBUG
return _mutex_lock(lock, NULL);
#else
if (atomic_add(&lock->count, -1) < 0) if (atomic_add(&lock->count, -1) < 0)
return _mutex_lock(lock, NULL); return _mutex_lock(lock, NULL);
return B_OK; return B_OK;
#endif
} }
static inline status_t static inline status_t
mutex_trylock(mutex* lock) mutex_trylock(mutex* lock)
{ {
#if KDEBUG
return _mutex_trylock(lock);
#else
if (atomic_test_and_set(&lock->count, -1, 0) != 0) if (atomic_test_and_set(&lock->count, -1, 0) != 0)
return B_WOULD_BLOCK; return B_WOULD_BLOCK;
return B_OK; return B_OK;
#endif
} }
static inline status_t static inline status_t
mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, bigtime_t timeout) mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, bigtime_t timeout)
{ {
#if KDEBUG
return _mutex_lock_with_timeout(lock, timeoutFlags, timeout);
#else
if (atomic_add(&lock->count, -1) < 0) if (atomic_add(&lock->count, -1) < 0)
return _mutex_lock_with_timeout(lock, timeoutFlags, timeout); return _mutex_lock_with_timeout(lock, timeoutFlags, timeout);
return B_OK; return B_OK;
#endif
} }
static inline void static inline void
mutex_unlock(mutex* lock) mutex_unlock(mutex* lock)
{ {
#if !KDEBUG
if (atomic_add(&lock->count, 1) < -1) if (atomic_add(&lock->count, 1) < -1)
#endif
_mutex_unlock(lock); _mutex_unlock(lock);
} }
#endif
static inline void static inline void
+71 -25
View File
@@ -8,17 +8,25 @@
*/ */
/*! Mutex and recursive_lock code */ #include <debug.h>
#if KDEBUG
#define KDEBUG_STATIC static
static status_t _mutex_lock(struct mutex* lock, void* locker);
static void _mutex_unlock(struct mutex* lock);
#else
#define KDEBUG_STATIC
#define mutex_lock mutex_lock_inline
#define mutex_unlock mutex_unlock_inline
#define mutex_trylock mutex_trylock_inline
#define mutex_lock_with_timeout mutex_lock_with_timeout_inline
#endif
#include <lock.h> #include <lock.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <OS.h>
#include <debug.h>
#include <int.h> #include <int.h>
#include <kernel.h> #include <kernel.h>
#include <listeners.h> #include <listeners.h>
@@ -954,7 +962,7 @@ mutex_switch_from_read_lock(rw_lock* from, mutex* to)
} }
status_t KDEBUG_STATIC status_t
_mutex_lock(mutex* lock, void* _locker) _mutex_lock(mutex* lock, void* _locker)
{ {
#if KDEBUG #if KDEBUG
@@ -1022,7 +1030,7 @@ _mutex_lock(mutex* lock, void* _locker)
} }
void KDEBUG_STATIC void
_mutex_unlock(mutex* lock) _mutex_unlock(mutex* lock)
{ {
InterruptsSpinLocker locker(lock->lock); InterruptsSpinLocker locker(lock->lock);
@@ -1064,25 +1072,7 @@ _mutex_unlock(mutex* lock)
} }
status_t KDEBUG_STATIC status_t
_mutex_trylock(mutex* lock)
{
#if KDEBUG
InterruptsSpinLocker _(lock->lock);
if (lock->holder < 0) {
lock->holder = thread_get_current_thread_id();
return B_OK;
} else if (lock->holder == 0)
panic("_mutex_trylock(): using uninitialized lock %p", lock);
return B_WOULD_BLOCK;
#else
return mutex_trylock(lock);
#endif
}
status_t
_mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, bigtime_t timeout) _mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, bigtime_t timeout)
{ {
#if KDEBUG #if KDEBUG
@@ -1183,6 +1173,62 @@ _mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, bigtime_t timeout)
} }
#undef mutex_trylock
status_t
mutex_trylock(mutex* lock)
{
#if KDEBUG
InterruptsSpinLocker _(lock->lock);
if (lock->holder < 0) {
lock->holder = thread_get_current_thread_id();
return B_OK;
} else if (lock->holder == 0) {
panic("_mutex_trylock(): using uninitialized lock %p", lock);
}
return B_WOULD_BLOCK;
#else
return mutex_trylock_inline(lock);
#endif
}
#undef mutex_lock
status_t
mutex_lock(mutex* lock)
{
#if KDEBUG
return _mutex_lock(lock, NULL);
#else
return mutex_lock_inline(lock);
#endif
}
#undef mutex_unlock
void
mutex_unlock(mutex* lock)
{
#if KDEBUG
_mutex_unlock(lock);
#else
mutex_unlock_inline(lock);
#endif
}
#undef mutex_lock_with_timeout
status_t
mutex_lock_with_timeout(mutex* lock, uint32 timeoutFlags, bigtime_t timeout)
{
#if KDEBUG
return _mutex_lock_with_timeout(lock, timeoutFlags, timeout);
#else
return mutex_lock_with_timeout_inline(lock, timeoutFlags, timeout);
#endif
}
static int static int
dump_mutex_info(int argc, char** argv) dump_mutex_info(int argc, char** argv)
{ {