150 lines
3.6 KiB
C
150 lines
3.6 KiB
C
//
|
|
// Created by rick on 27-02-21.
|
|
//
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
|
|
#include <myke/tasks/locking.h>
|
|
#include <myke/tasks/task.h>
|
|
#include <myke/libk/syscall.h>
|
|
|
|
typedef struct lock_fifo_entry {
|
|
pid_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(int32_t start) {
|
|
semaphore_t *semaphore = malloc(sizeof(semaphore_t));
|
|
memset((uint8_t *) semaphore, 0, sizeof(semaphore_t));
|
|
semaphore->value = start;
|
|
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();
|
|
lock->next = NULL;
|
|
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) {
|
|
semaphore->value++;
|
|
task_lock_acquire();
|
|
if (semaphore->first_wait != NULL) {
|
|
task_signal(semaphore->first_wait->tid);
|
|
lock_fifo_entry_t *first_entry = semaphore->first_wait;
|
|
semaphore->first_wait = first_entry->next;
|
|
if (semaphore->first_wait == NULL) {
|
|
semaphore->last_wait = NULL;
|
|
}
|
|
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));
|
|
memset((uint8_t *) mutex, 0, 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();
|
|
lock->next = NULL;
|
|
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() {
|
|
spinlock_t *lock = malloc(sizeof(spinlock_t));
|
|
lock->lock = false;
|
|
return lock;
|
|
}
|
|
|
|
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);
|
|
}
|