kernel: Add sequential lock implementation
This commit is contained in:
parent
958f6d00aa
commit
4824f7630b
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -160,6 +160,52 @@ private:
|
||||
typedef AutoLocker<spinlock, InterruptsSpinLocking> 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<seqlock, WriteSequentialLocking> 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<seqlock, InterruptsWriteSequentialLocking>
|
||||
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;
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user