From 4824f7630b2ca9c5750f93c4daa837dfcac3059e Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 5 Nov 2013 04:16:13 +0100 Subject: [PATCH] kernel: Add sequential lock implementation --- headers/os/drivers/KernelExport.h | 17 +++++++++ headers/private/kernel/smp.h | 45 ++++++++++++++++++++++++ headers/private/kernel/util/AutoLock.h | 48 ++++++++++++++++++++++++++ src/system/kernel/smp.cpp | 48 ++++++++++++++++++++++++++ 4 files changed, 158 insertions(+) diff --git a/headers/os/drivers/KernelExport.h b/headers/os/drivers/KernelExport.h index 98e59387f1..be17861cb6 100644 --- a/headers/os/drivers/KernelExport.h +++ b/headers/os/drivers/KernelExport.h @@ -40,6 +40,17 @@ typedef ulong cpu_status; # define B_SPINLOCK_IS_LOCKED(lock) (*(lock) > 0) #endif +typedef struct { + spinlock lock; + uint32 count; +} seqlock; + +#define B_SEQLOCK_INITIALIZER { B_SPINLOCK_INITIALIZER, 0 } +#define B_INITIALIZE_SEQLOCK(seqlock) do { \ + B_INITIALIZE_SPINLOCK((seqlock)->lock); \ + (seqlock)->count = 0; \ + } while (false) + /* interrupt handling support for device drivers */ typedef int32 (*interrupt_handler)(void *data); @@ -126,6 +137,12 @@ extern void restore_interrupts(cpu_status status); extern void acquire_spinlock(spinlock *lock); extern void release_spinlock(spinlock *lock); +extern bool try_acquire_write_seqlock(seqlock* lock); +extern void acquire_write_seqlock(seqlock* lock); +extern void release_write_seqlock(seqlock* lock); +extern uint32 acquire_read_seqlock(seqlock* lock); +extern bool release_read_seqlock(seqlock* lock, uint32 count); + extern status_t install_io_interrupt_handler(long interrupt_number, interrupt_handler handler, void *data, ulong flags); extern status_t remove_io_interrupt_handler(long interrupt_number, diff --git a/headers/private/kernel/smp.h b/headers/private/kernel/smp.h index 90427fb825..50bdcbe4c3 100644 --- a/headers/private/kernel/smp.h +++ b/headers/private/kernel/smp.h @@ -103,4 +103,49 @@ release_spinlock_inline(spinlock* lock) #endif // !DEBUG_SPINLOCKS && !B_DEBUG_SPINLOCK_CONTENTION +static inline bool +try_acquire_write_seqlock_inline(seqlock* lock) { + bool succeed = try_acquire_spinlock(&lock->lock); + if (succeed) + atomic_add(&lock->count, 1); + return succeed; +} + + +static inline void +acquire_write_seqlock_inline(seqlock* lock) { + acquire_spinlock(&lock->lock); + atomic_add(&lock->count, 1); +} + + +static inline void +release_write_seqlock_inline(seqlock* lock) { + atomic_add(&lock->count, 1); + release_spinlock(&lock->lock); +} + + +static inline uint32 +acquire_read_seqlock_inline(seqlock* lock) { + return atomic_get(&lock->count); +} + + +static inline bool +release_read_seqlock_inline(seqlock* lock, uint32 count) { + uint32 current = atomic_get(&lock->count); + + return count % 2 == 0 && current == count; +} + + +#define try_acquire_write_seqlock(lock) try_acquire_write_seqlock_inline(lock) +#define acquire_write_seqlock(lock) acquire_write_seqlock_inline(lock) +#define release_write_seqlock(lock) release_write_seqlock_inline(lock) +#define acquire_read_seqlock(lock) acquire_read_seqlock_inline(lock) +#define release_read_seqlock(lock, count) \ + release_read_seqlock_inline(lock, count) + + #endif /* KERNEL_SMP_H */ diff --git a/headers/private/kernel/util/AutoLock.h b/headers/private/kernel/util/AutoLock.h index 12f9b972b4..5a334fbc1a 100644 --- a/headers/private/kernel/util/AutoLock.h +++ b/headers/private/kernel/util/AutoLock.h @@ -160,6 +160,52 @@ private: typedef AutoLocker InterruptsSpinLocker; +class WriteSequentialLocking { +public: + inline bool Lock(seqlock* lockable) + { + acquire_write_seqlock(lockable); + return true; + } + + inline void Unlock(seqlock* lockable) + { + release_write_seqlock(lockable); + } +}; + +typedef AutoLocker WriteSequentialLocker; + + +class InterruptsWriteSequentialLocking { +public: + InterruptsWriteSequentialLocking() + : + fState(0) + { + } + + inline bool Lock(seqlock* lockable) + { + fState = disable_interrupts(); + acquire_write_seqlock(lockable); + return true; + } + + inline void Unlock(seqlock* lockable) + { + release_write_seqlock(lockable); + restore_interrupts(fState); + } + +private: + int fState; +}; + +typedef AutoLocker + InterruptsWriteSequentialLocker; + + class ThreadCPUPinLocking { public: inline bool Lock(Thread* thread) @@ -191,6 +237,8 @@ using BPrivate::WriteLocker; using BPrivate::InterruptsLocker; using BPrivate::SpinLocker; using BPrivate::InterruptsSpinLocker; +using BPrivate::WriteSequentialLocker; +using BPrivate::InterruptsWriteSequentialLocker; using BPrivate::ThreadCPUPinner; using BPrivate::TeamLocker; using BPrivate::ThreadLocker; diff --git a/src/system/kernel/smp.cpp b/src/system/kernel/smp.cpp index e28faf619c..93be92fe2e 100644 --- a/src/system/kernel/smp.cpp +++ b/src/system/kernel/smp.cpp @@ -45,6 +45,12 @@ #undef acquire_spinlock #undef release_spinlock +#undef try_acquire_write_seqlock +#undef acquire_write_seqlock +#undef release_write_seqlock +#undef acquire_read_seqlock +#undef release_read_seqlock + #define MSG_POOL_SIZE (SMP_MAX_CPUS * 4) @@ -512,6 +518,48 @@ release_spinlock(spinlock *lock) } +bool +try_acquire_write_seqlock(seqlock* lock) { + bool succeed = try_acquire_spinlock(&lock->lock); + if (succeed) + atomic_add(&lock->count, 1); + return succeed; +} + + +void +acquire_write_seqlock(seqlock* lock) { + acquire_spinlock(&lock->lock); + atomic_add(&lock->count, 1); +} + + +void +release_write_seqlock(seqlock* lock) { + atomic_add(&lock->count, 1); + release_spinlock(&lock->lock); +} + + +uint32 +acquire_read_seqlock(seqlock* lock) { + return atomic_get(&lock->count); +} + + +bool +release_read_seqlock(seqlock* lock, uint32 count) { + uint32 current = atomic_get(&lock->count); + + if (count % 2 == 1 || current != count) { + PAUSE(); + return false; + } + + return true; +} + + /*! Finds a free message and gets it. NOTE: has side effect of disabling interrupts return value is the former interrupt state