45 lines
1.7 KiB
C
45 lines
1.7 KiB
C
#ifndef FROSTBYTE_SPINLOCK_H
|
|
#define FROSTBYTE_SPINLOCK_H
|
|
|
|
#include "types.h"
|
|
|
|
/*
|
|
* SpinLock: an interrupt-safe mutual-exclusion lock for state shared between
|
|
* thread context and interrupt handlers (irq0/irq1 currently run with
|
|
* interrupts re-enabled per pic.c, so a naive "just disable interrupts"
|
|
* critical section is not enough once two handlers can nest).
|
|
*
|
|
* Acquire disables interrupts and spins on an atomic test-and-set before
|
|
* returning; release restores whatever the interrupt flag was at the
|
|
* matching acquire. This is correct and SMP-ready even though frostbyte is
|
|
* currently single-core: on one core, acquiring an already-held lock is a
|
|
* bug (it would spin forever with interrupts off), so spinLockTryAcquire is
|
|
* provided for call sites -- and tests -- that need to observe contention
|
|
* without deadlocking.
|
|
*/
|
|
|
|
typedef struct SpinLock {
|
|
volatile uint32 locked;
|
|
} SpinLock;
|
|
|
|
void spinLockInit(SpinLock* lock);
|
|
|
|
/* Disables interrupts, then spins until the lock is acquired. Returns the
|
|
interrupt flag as it was immediately before this call, to be passed back
|
|
to spinLockRelease unchanged (callers must not interleave two different
|
|
locks' flags). */
|
|
uint64 spinLockAcquire(SpinLock* lock);
|
|
|
|
/* Non-blocking. On success (true), interrupts are disabled and *savedFlags
|
|
holds the pre-call flag word, exactly as spinLockAcquire would leave
|
|
things. On failure (false) nothing is touched -- interrupts are left
|
|
exactly as the caller had them. */
|
|
bool spinLockTryAcquire(SpinLock* lock, uint64* savedFlags);
|
|
|
|
/* flags must be the value spinLockAcquire/spinLockTryAcquire handed back. */
|
|
void spinLockRelease(SpinLock* lock, uint64 flags);
|
|
|
|
bool spinLockIsLocked(const SpinLock* lock);
|
|
|
|
#endif
|