// // Created by rick on 27-02-21. // #include "locking.h" #include #include #include #include #include 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); }