-
Notifications
You must be signed in to change notification settings - Fork 6
Add basic kernel locks #33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Changes from all commits
561d0db
ff679bb
af1527e
cf883d9
59760f2
bcd151a
388969a
056f909
8495a98
86ad43a
7fb6a97
a243334
4490986
2dcc861
c0ddb82
da861e8
bf3c47d
b1b74df
f5a780b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| #include <hart_locals.h> | ||
| #include <hartlock.h> | ||
| #include <irq.h> | ||
| #include <panic.h> | ||
| #include <types.h> | ||
|
|
||
| void hartlock_acquire(void) { | ||
| bool prev_interrupt_enabled = are_interrupts_enabled(); | ||
| disable_interrupts(); | ||
| struct hart_locals *hart = get_hart_locals(); | ||
| if (hart->interrupt_disabled_depth == 0) { | ||
| hart->prev_interrupt_enabled = prev_interrupt_enabled; | ||
| } | ||
| hart->interrupt_disabled_depth += 1; | ||
| } | ||
|
|
||
| void hartlock_release(void) { | ||
| if (are_interrupts_enabled()) { | ||
| panic("hartlock_release: interrupts are enabled when they should be disabled"); | ||
| } | ||
| struct hart_locals *hart = get_hart_locals(); | ||
| if (hart->interrupt_disabled_depth < 1) { | ||
| panic("hartlock_release: called without matching hartlock_acquire"); | ||
| } | ||
| hart->interrupt_disabled_depth -= 1; | ||
| if (hart->interrupt_disabled_depth == 0 && hart->prev_interrupt_state) { | ||
| enable_interrupts(); | ||
| } | ||
| } | ||
|
|
||
| bool is_hart_locked(void) { | ||
| // Currently, a hartlock is just enabling/disabling interrupts | ||
| return !are_interrupts_enabled(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| #ifndef UKO_OS_KERNEL__IRQ_H | ||
| #define UKO_OS_KERNEL__IRQ_H 1 | ||
|
|
||
| #include <insns.h> | ||
| #include <types.h> | ||
|
|
||
| constexpr u64 RISCV64_SSTATUS_SIE = (1UL << 1); | ||
|
|
||
| /** | ||
| * enable_interrupts - Enables interrupt requests. | ||
| * | ||
| * Sets the SIE (supervisor interrupt enable) flag in the SSTATUS CSR. | ||
| */ | ||
| static inline void enable_interrupts(void) { | ||
| csrs(RISCV64_CSR_SSTATUS, RISCV64_SSTATUS_SIE); | ||
| } | ||
|
|
||
| /** | ||
| * disable_interrupts - Disables interrupt requests. | ||
| * | ||
| * Clears the SIE (supervisor interrupt enable) flag in the SSTATUS CSR. | ||
| */ | ||
| static inline void disable_interrupts(void) { | ||
| csrc(RISCV64_CSR_SSTATUS, RISCV64_SSTATUS_SIE); | ||
| } | ||
|
|
||
| /** | ||
| * are_interrupts_enabled - Checks if interrupt requests are enabled. | ||
| * | ||
| * Return: true if interrupt requests are enabled, false otherwise. | ||
| */ | ||
| static inline bool are_interrupts_enabled(void) { | ||
| u64 sstatus = csrr(RISCV64_CSR_SSTATUS); | ||
| return (sstatus & RISCV64_SSTATUS_SIE) != 0; | ||
| } | ||
|
|
||
| #endif // UKO_OS_KERNEL__IRQ_H | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| #ifndef UKO_OS_KERNEL__HARTLOCK_H | ||
| #define UKO_OS_KERNEL__HARTLOCK_H 1 | ||
|
|
||
| /** | ||
| * hartlock_acquire - Locks the executing thread to the current hart. | ||
| * | ||
| * Disables interrupts to prevent the current thread from being moved | ||
| * to another hart. This does not provide mutual exclusion, nor does it | ||
| * prevent the thread from blocking. It only ensures that the | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Shouldn't it? Blocking operations should allow context-switching. |
||
| * thread continues to execute on the same hart by preventing | ||
| * preemption via interrupts. | ||
| */ | ||
| void hartlock_acquire(void); | ||
|
|
||
| /** | ||
| * hartlock_release - Unlocks the executing thread from the current hart. | ||
| * | ||
| * Re-enables interrupts if they were enabled at the time hartlock_acquire() | ||
| * was called. If interrupts were already disabled, they remain disabled. | ||
| */ | ||
| void hartlock_release(void); | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| /** | ||
| * is_hart_locked - Checks if the executing thread has a hartlock. | ||
| * | ||
| * Return: true if the thread has a hartlock, false otherwise. | ||
| */ | ||
| bool is_hart_locked(void); | ||
|
|
||
| #endif // UKO_OS_KERNEL__HARTLOCK_H | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| #ifndef UKO_OS_KERNEL__SPINLOCK_H | ||
| #define UKO_OS_KERNEL__SPINLOCK_H 1 | ||
|
|
||
| #include <hart_locals.h> | ||
| #include <stdatomic.h> | ||
| #include <types.h> | ||
|
|
||
| /** | ||
| * struct spinlock - Basic spinlock structure. | ||
| * @lock: Atomic lock flag (true if acquired, false otherwise). | ||
| * @hart: Pointer to the hart holding the lock. | ||
| * @name: Name of the lock (for debugging). | ||
| */ | ||
| struct spinlock { | ||
| volatile atomic_flag lock; | ||
| struct hart_locals *hart; | ||
| const char *name; | ||
| }; | ||
|
|
||
| /** | ||
| * spinlock_init - Initializes a spinlock. | ||
| * @sp: Pointer to the spinlock structure. | ||
| * @name: Name of the lock. | ||
| * | ||
| * Initializes a spinlock that disables interrupts. | ||
| */ | ||
| void spinlock_init(struct spinlock *sp, const char *name); | ||
|
|
||
| /** | ||
| * spinlock_acquire - Acquire a spinlock. | ||
| * @sp: Pointer to the spinlock structure. | ||
| * | ||
| * Acquires the specified spinlock. If the lock is already held, | ||
| * the caller will spin until the lock becomes available. | ||
| */ | ||
| void spinlock_acquire(struct spinlock *sp); | ||
|
|
||
| /** | ||
| * spinlock_release - Release a spinlock. | ||
| * @sp: Pointer to the spinlock structure. | ||
| * | ||
| * Releases the previously acquired spinlock. The lock must have | ||
| * been acquired by the same context. | ||
| */ | ||
| void spinlock_release(struct spinlock *sp); | ||
|
|
||
| #endif // UKO_OS_KERNEL__SPINLOCK_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| #include <hartlock.h> | ||
| #include <panic.h> | ||
| #include <spinlock.h> | ||
|
|
||
| /* Returns true if thread is holding the specified spinlock, false otherwise. */ | ||
| static bool holding(struct spinlock *sp) { | ||
| struct hart_locals *hart = get_hart_locals(); | ||
| return atomic_load(&sp->lock) && (sp->hart == hart); | ||
| } | ||
|
|
||
| void spinlock_init(struct spinlock *sp, const char *name) { | ||
| sp->lock = ATOMIC_FLAG_INIT; | ||
| sp->hart = nullptr; | ||
| sp->name = name; | ||
| } | ||
|
|
||
| void spinlock_acquire(struct spinlock *sp) { | ||
| hartlock_acquire(); // Lock execution to current hart | ||
| if (holding(sp)) { | ||
| panic("spinlock_acquire: {cstr} already held by current thread", sp->name); | ||
| } | ||
| while (atomic_flag_test_and_set(&sp->lock, memory_order_acquire)) {} | ||
| sp->hart = get_hart_locals(); | ||
| } | ||
|
|
||
| void spinlock_release(struct spinlock *sp) { | ||
| if (!holding(sp)) { | ||
| panic("spinlock_release: {cstr} not held by current thread", sp->name); | ||
| } | ||
| sp->hart = nullptr; | ||
| atomic_flag_clear_explicit(&sp->lock, memory_order_release); | ||
| hartlock_release(); // Unlock execution if necessary | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, didn't realize this was going to so closely correspond to what's in hartlock.c -- one thing you can do is to have an arch-independent
foo.h, but put the.cunder arch/