feat: initial locking etc.
This commit is contained in:
@@ -3,3 +3,136 @@
|
||||
//
|
||||
|
||||
#include "locking.h"
|
||||
#include <mem/malloc.h>
|
||||
#include <tasks/task.h>
|
||||
#include <libk/syscall.h>
|
||||
#include <stdbool.h>
|
||||
#include <libc/kprintf.h>
|
||||
|
||||
typedef struct lock_fifo_entry {
|
||||
uint32_t tid;
|
||||
struct lock_fifo_entry *next;
|
||||
} lock_fifo_entry_t;
|
||||
|
||||
struct semaphore {
|
||||
volatile int32_t value;
|
||||
lock_fifo_entry_t *first_wait;
|
||||
lock_fifo_entry_t *last_wait;
|
||||
};
|
||||
|
||||
struct mutex {
|
||||
volatile bool value;
|
||||
lock_fifo_entry_t *first_wait;
|
||||
lock_fifo_entry_t *last_wait;
|
||||
};
|
||||
|
||||
struct spinlock {
|
||||
volatile uint32_t lock;
|
||||
};
|
||||
|
||||
semaphore_t *semaphore_create() {
|
||||
semaphore_t *semaphore = malloc(sizeof(semaphore_t));
|
||||
semaphore->value = 1;
|
||||
return semaphore;
|
||||
}
|
||||
|
||||
void semaphore_wait(semaphore_t *semaphore) {
|
||||
if (__sync_sub_and_fetch(&semaphore->value, 1) == 0) {
|
||||
return; // first to lock
|
||||
}
|
||||
task_lock_acquire();
|
||||
lock_fifo_entry_t *lock = malloc(sizeof(lock_fifo_entry_t));
|
||||
lock->tid = task_get_current_tid();
|
||||
if (semaphore->first_wait == NULL) {
|
||||
semaphore->first_wait = lock;
|
||||
} else {
|
||||
semaphore->last_wait->next = lock;
|
||||
}
|
||||
semaphore->last_wait = lock;
|
||||
task_lock_free();
|
||||
syscall_job_suspend();
|
||||
}
|
||||
|
||||
void semaphore_signal(semaphore_t *semaphore) {
|
||||
if (__sync_add_and_fetch(&semaphore->value, 1) == 1) {
|
||||
return; // last in queue
|
||||
}
|
||||
task_lock_acquire();
|
||||
task_signal(semaphore->first_wait->tid);
|
||||
lock_fifo_entry_t *first_entry = semaphore->first_wait;
|
||||
semaphore->first_wait = first_entry->next;
|
||||
free(first_entry);
|
||||
task_lock_free();
|
||||
}
|
||||
|
||||
void semaphore_free(semaphore_t *semaphore) {
|
||||
if (semaphore->value < 1) {
|
||||
printf("WARN: freeing semaphore which still has a task waiting\n");
|
||||
}
|
||||
free(semaphore);
|
||||
}
|
||||
|
||||
mutex_t *mutex_create() {
|
||||
mutex_t *mutex = malloc(sizeof(mutex_t));
|
||||
mutex->value = 1;
|
||||
return mutex;
|
||||
}
|
||||
|
||||
void mutex_acquire(mutex_t *mutex) {
|
||||
if (__sync_bool_compare_and_swap(&mutex->value, true, false) == true) {
|
||||
return; // first one to lock
|
||||
}
|
||||
task_lock_acquire();
|
||||
lock_fifo_entry_t *lock = malloc(sizeof(lock_fifo_entry_t));
|
||||
lock->tid = task_get_current_tid();
|
||||
if (mutex->first_wait == NULL) {
|
||||
mutex->first_wait = lock;
|
||||
} else {
|
||||
mutex->last_wait->next = lock;
|
||||
}
|
||||
mutex->last_wait = lock;
|
||||
task_lock_free();
|
||||
syscall_job_suspend();
|
||||
}
|
||||
|
||||
void mutex_release(mutex_t *mutex) {
|
||||
task_lock_acquire();
|
||||
if (mutex->first_wait == NULL) {
|
||||
mutex->value = true;
|
||||
task_lock_free();
|
||||
return; // no one left
|
||||
}
|
||||
lock_fifo_entry_t *entry = mutex->first_wait;
|
||||
task_signal(entry->tid);
|
||||
mutex->first_wait = entry->next;
|
||||
free(entry);
|
||||
task_lock_free();
|
||||
}
|
||||
|
||||
void mutex_free(mutex_t *mutex) {
|
||||
if (mutex->value != true) {
|
||||
printf("WARN: freeing mutex which still has a task waiting\n");
|
||||
}
|
||||
free(mutex);
|
||||
}
|
||||
|
||||
spinlock_t *spinlock_create() {
|
||||
return malloc(sizeof(spinlock_t));
|
||||
}
|
||||
|
||||
void spinlock_acquire(spinlock_t *spinlock) {
|
||||
while (!__sync_bool_compare_and_swap(&spinlock->lock, false, true));
|
||||
__sync_synchronize();
|
||||
}
|
||||
|
||||
void spinlock_release(spinlock_t *spinlock) {
|
||||
__sync_synchronize();
|
||||
spinlock->lock = false;
|
||||
}
|
||||
|
||||
void spinlock_free(spinlock_t *spinlock) {
|
||||
if (spinlock->lock != false) {
|
||||
printf("WARN: freeing spinlock which is still spinning\n");
|
||||
}
|
||||
free(spinlock);
|
||||
}
|
||||
|
||||
@@ -5,4 +5,36 @@
|
||||
#ifndef NEW_KERNEL_LOCKING_H
|
||||
#define NEW_KERNEL_LOCKING_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
typedef struct semaphore semaphore_t;
|
||||
|
||||
typedef struct mutex mutex_t;
|
||||
|
||||
typedef struct spinlock spinlock_t;
|
||||
|
||||
semaphore_t *semaphore_create();
|
||||
|
||||
void semaphore_wait(semaphore_t *semaphore);
|
||||
|
||||
void semaphore_signal(semaphore_t *semaphore);
|
||||
|
||||
void semaphore_free(semaphore_t *semaphore);
|
||||
|
||||
mutex_t *mutex_create();
|
||||
|
||||
void mutex_acquire(mutex_t *mutex);
|
||||
|
||||
void mutex_release(mutex_t *mutex);
|
||||
|
||||
void mutex_free(mutex_t *mutex);
|
||||
|
||||
spinlock_t *spinlock_create();
|
||||
|
||||
void spinlock_acquire(spinlock_t *spinlock);
|
||||
|
||||
void spinlock_release(spinlock_t *spinlock);
|
||||
|
||||
void spinlock_free(spinlock_t *spinlock);
|
||||
|
||||
#endif //NEW_KERNEL_LOCKING_H
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <mem/pmm.h>
|
||||
|
||||
#include <attributes.h>
|
||||
#include <libk/libk.h>
|
||||
|
||||
#define stack_end(task) ((task)->stack + ((task)->stack_page_count * PAGE_SIZE))
|
||||
|
||||
@@ -17,7 +18,9 @@
|
||||
#define TASK_STATE_RUNNABLE (1 << 0)
|
||||
#define TASK_STATE_RUNNING (1 << 1)
|
||||
#define TASK_STATE_WAIT_IRQ (1 << 2)
|
||||
#define TASK_STATE_WAIT_SIGNAL (1 << 3)
|
||||
|
||||
#define TASK_STATE_STOPPED (1 << 6)
|
||||
#define TASK_STATE_ERROR (1 << 7)
|
||||
|
||||
|
||||
@@ -44,7 +47,7 @@ typedef struct {
|
||||
char alignment[4];
|
||||
} packed task_stack_start;
|
||||
|
||||
bool task_locked = false;
|
||||
volatile uint32_t task_locked = 0;
|
||||
|
||||
task_t *idle_task = NULL;
|
||||
task_t *first_task = NULL;
|
||||
@@ -67,12 +70,45 @@ void cdecl noreturn task_entry_point(task_entrypoint entrypoint, void *entry_dat
|
||||
while (true); // halt
|
||||
}
|
||||
|
||||
void task_ensure_enabled() {
|
||||
if (current_task == NULL) {
|
||||
k_panics("Tasking should be enabled\n");
|
||||
}
|
||||
}
|
||||
|
||||
void task_lock_acquire() {
|
||||
task_locked = true;
|
||||
if (__sync_add_and_fetch(&task_locked, 1) == UINT32_MAX) {
|
||||
k_panics("To many task locks");
|
||||
};
|
||||
}
|
||||
|
||||
void task_lock_free() {
|
||||
task_locked = false;
|
||||
if (__sync_sub_and_fetch(&task_locked, 1) == UINT32_MAX) {
|
||||
k_panics("To many task free's");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t task_get_current_tid() {
|
||||
return current_task->tid;
|
||||
}
|
||||
|
||||
void task_signal(uint32_t tid) {
|
||||
task_t *t = first_task;
|
||||
while (t != NULL) {
|
||||
if (t->tid == tid) {
|
||||
if (t->state != TASK_STATE_WAIT_SIGNAL) {
|
||||
// todo
|
||||
}
|
||||
t->state = TASK_STATE_RUNNABLE;
|
||||
break;
|
||||
}
|
||||
t = t->next;
|
||||
}
|
||||
}
|
||||
|
||||
void task_suspend() {
|
||||
current_task->state = TASK_STATE_WAIT_SIGNAL;
|
||||
task_switch_next();
|
||||
}
|
||||
|
||||
void noreturn task_idle(void *data) {
|
||||
@@ -98,7 +134,7 @@ void task_wait_irq(uint16_t irq_bits) {
|
||||
}
|
||||
|
||||
void task_switch_next_inner(task_t *next_task) {
|
||||
if (task_locked) {
|
||||
if (task_locked != 0) {
|
||||
return; // don't switch while the task is locked
|
||||
}
|
||||
if (next_task == current_task) {
|
||||
@@ -115,6 +151,9 @@ void task_switch_next_inner(task_t *next_task) {
|
||||
}
|
||||
|
||||
void task_start_first() {
|
||||
if (task_locked > 0) {
|
||||
k_panics("Tasking locked before start\n");
|
||||
}
|
||||
task_switch_next_inner(first_task);
|
||||
}
|
||||
|
||||
@@ -203,5 +242,13 @@ uint32_t task_spawn(task_entrypoint entrypoint, void *entry_data) {
|
||||
return new_task->tid;
|
||||
}
|
||||
|
||||
void task_end(uint32_t pid) {
|
||||
void task_end(uint32_t tid) {
|
||||
task_t *t = first_task;
|
||||
while (t != NULL) {
|
||||
if (t->tid == tid) {
|
||||
t->state = TASK_STATE_STOPPED;
|
||||
break;
|
||||
}
|
||||
t = t->next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,18 @@ void task_switch_next();
|
||||
|
||||
uint32_t task_spawn(task_entrypoint, void *entry_data);
|
||||
|
||||
void task_end(uint32_t pid);
|
||||
void task_end(uint32_t tid);
|
||||
|
||||
void task_suspend();
|
||||
|
||||
uint32_t task_get_current_tid();
|
||||
|
||||
void task_signal(uint32_t tid);
|
||||
|
||||
void task_lock_acquire();
|
||||
|
||||
void task_ensure_enabled();
|
||||
|
||||
void task_lock_free();
|
||||
|
||||
#endif //NEW_KERNEL_TASK_H
|
||||
|
||||
Reference in New Issue
Block a user