mirror of
https://github.com/usatiuk/ficus.git
synced 2025-10-29 00:27:52 +01:00
brand new mutex
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
//
|
||||
#include <cstddef>
|
||||
|
||||
#include "LockGuard.hpp"
|
||||
#include "TestTemplates.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "kmem.hpp"
|
||||
@@ -79,31 +80,34 @@ void freeprinter() {
|
||||
}
|
||||
}
|
||||
|
||||
static struct Mutex testmutex;
|
||||
static Mutex testmutex;
|
||||
|
||||
void mtest1() {
|
||||
m_lock(&testmutex);
|
||||
all_tty_putstr("Locked1\n");
|
||||
sleep_self(100000);
|
||||
m_unlock(&testmutex);
|
||||
{
|
||||
LockGuard l(testmutex);
|
||||
all_tty_putstr("Locked1\n");
|
||||
sleep_self(100000);
|
||||
}
|
||||
all_tty_putstr("Unlocked1\n");
|
||||
remove_self();
|
||||
}
|
||||
|
||||
void mtest2() {
|
||||
m_lock(&testmutex);
|
||||
all_tty_putstr("Locked2\n");
|
||||
sleep_self(100000);
|
||||
m_unlock(&testmutex);
|
||||
{
|
||||
LockGuard l(testmutex);
|
||||
all_tty_putstr("Locked2\n");
|
||||
sleep_self(100000);
|
||||
}
|
||||
all_tty_putstr("Unlocked2\n");
|
||||
remove_self();
|
||||
}
|
||||
|
||||
void mtest3() {
|
||||
m_lock(&testmutex);
|
||||
all_tty_putstr("Locked3\n");
|
||||
sleep_self(100000);
|
||||
m_unlock(&testmutex);
|
||||
{
|
||||
LockGuard l(testmutex);
|
||||
all_tty_putstr("Locked3\n");
|
||||
sleep_self(100000);
|
||||
}
|
||||
all_tty_putstr("Unlocked3\n");
|
||||
remove_self();
|
||||
}
|
||||
@@ -142,6 +146,9 @@ void stress_tester() {
|
||||
}
|
||||
|
||||
void ktask_main() {
|
||||
struct tty_funcs serial_tty = {.putchar = write_serial};
|
||||
add_tty(serial_tty);
|
||||
|
||||
new_ktask(ktask, "one");
|
||||
new_ktask(freeprinter, "freeprinter");
|
||||
new_ktask(mtest1, "mtest1");
|
||||
@@ -164,9 +171,6 @@ extern void (*ctors_begin[])();
|
||||
extern void (*ctors_end[])();
|
||||
|
||||
void kmain() {
|
||||
struct tty_funcs serial_tty = {.putchar = write_serial};
|
||||
add_tty(serial_tty);
|
||||
|
||||
for (void (**ctor)() = ctors_begin; ctor < ctors_end; ctor++)
|
||||
(*ctor)();
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "task.hpp"
|
||||
#include "LockGuard.hpp"
|
||||
#include "Spinlock.hpp"
|
||||
#include "cv.hpp"
|
||||
#include "gdt.hpp"
|
||||
#include "kmem.hpp"
|
||||
#include "misc.hpp"
|
||||
@@ -330,64 +329,24 @@ extern "C" void switch_task(struct task_frame *cur_frame) {
|
||||
sanity_check_frame(cur_frame);
|
||||
}
|
||||
|
||||
void wait_m_on_self(struct Mutex *m) {
|
||||
if (!m->waiters) {
|
||||
m->waiters = static_cast<TaskList *>(kmalloc(sizeof(struct TaskList)));
|
||||
m->waiters->cur = NULL;
|
||||
m->waiters->last = NULL;
|
||||
}
|
||||
// TODO: lock-free?
|
||||
NO_INT(append_task_node(m->waiters, RunningTask);
|
||||
void self_block() {
|
||||
RunningTask->task->state = TS_BLOCKED;
|
||||
yield_self();
|
||||
}
|
||||
|
||||
void self_block(Spinlock &to_unlock) {
|
||||
NO_INT(to_unlock.unlock();
|
||||
RunningTask->task->state = TS_BLOCKED;)
|
||||
yield_self();
|
||||
}
|
||||
|
||||
void m_unlock_sched_hook(struct Mutex *m) {
|
||||
struct TaskListNode *newt = NULL;
|
||||
|
||||
NO_INT(if (m->waiters) {
|
||||
newt = pop_front_node(m->waiters);
|
||||
})
|
||||
|
||||
if (newt) {
|
||||
newt->task->state = TS_RUNNING;
|
||||
{
|
||||
LockGuard l(UnblockedTasks_lock);
|
||||
append_task_node(&UnblockedTasks, newt);
|
||||
}
|
||||
void unblock(Task *what) {
|
||||
what->state = TS_RUNNING;
|
||||
{
|
||||
LockGuard l(UnblockedTasks_lock);
|
||||
append_task(&UnblockedTasks, what);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void wait_cv_on_self(struct CV *cv) {
|
||||
if (!cv->waiters) {
|
||||
cv->waiters = static_cast<TaskList *>(kmalloc(sizeof(struct TaskList)));
|
||||
cv->waiters->cur = NULL;
|
||||
cv->waiters->last = NULL;
|
||||
}
|
||||
// TODO: lock-free?
|
||||
NO_INT(append_task_node(cv->waiters, RunningTask);
|
||||
RunningTask->task->state = TS_BLOCKED;)
|
||||
yield_self();
|
||||
}
|
||||
|
||||
void cv_unlock_sched_hook(struct CV *cv, int who) {
|
||||
struct TaskListNode *newt = NULL;
|
||||
do {
|
||||
NO_INT(if (cv->waiters) {
|
||||
newt = pop_front_node(cv->waiters);
|
||||
})
|
||||
|
||||
if (newt) {
|
||||
newt->task->state = TS_RUNNING;
|
||||
{
|
||||
LockGuard l(UnblockedTasks_lock);
|
||||
append_task_node(&UnblockedTasks, newt);
|
||||
}
|
||||
}
|
||||
} while (newt && (who == CV_NOTIFY_ALL));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct Task *cur_task() {
|
||||
if (!RunningTask) return NULL;
|
||||
|
||||
@@ -5,14 +5,11 @@
|
||||
#ifndef OS1_TASK_H
|
||||
#define OS1_TASK_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "idt.hpp"
|
||||
|
||||
#define TASK_SS 16384
|
||||
|
||||
struct Mutex;
|
||||
struct CV;
|
||||
class Mutex;
|
||||
|
||||
enum TaskMode {
|
||||
TASKMODE_KERN,
|
||||
@@ -43,13 +40,18 @@ void init_tasks();
|
||||
struct Task *new_ktask(void (*fn)(), const char *name);
|
||||
void remove_self();
|
||||
void sleep_self(uint64_t diff);
|
||||
|
||||
|
||||
void self_block();
|
||||
|
||||
class Spinlock;
|
||||
void self_block(Spinlock &to_unlock);
|
||||
void unblock(Task *what);
|
||||
|
||||
extern "C" void switch_task(struct task_frame *cur_frame);
|
||||
void wait_m_on_self(struct Mutex *m);
|
||||
void m_unlock_sched_hook(struct Mutex *m);
|
||||
void wait_cv_on_self(struct CV *cv);
|
||||
void stop_waiting_on(struct Mutex *m);
|
||||
|
||||
void yield_self();
|
||||
|
||||
extern "C" void _yield_self_kern();// Expects the caller to save interrupt state
|
||||
void cv_unlock_sched_hook(struct CV *cv, int who);
|
||||
|
||||
#endif//OS1_TASK_H
|
||||
|
||||
@@ -4,69 +4,46 @@
|
||||
|
||||
#include "tty.hpp"
|
||||
|
||||
#include "LockGuard.hpp"
|
||||
#include "Vector.hpp"
|
||||
#include "kmem.hpp"
|
||||
#include "mutex.hpp"
|
||||
#include "serial.hpp"
|
||||
|
||||
static unsigned ttyNum = 0;
|
||||
static struct Mutex ttysMutex;
|
||||
static Mutex ttysMutex;
|
||||
|
||||
struct ttys {
|
||||
unsigned num;
|
||||
struct tty *ttys;
|
||||
};
|
||||
Vector<tty> ttys;
|
||||
|
||||
struct ttys ttys = {.num = 0};
|
||||
void add_tty(tty_funcs funcs) {
|
||||
LockGuard l(ttysMutex);
|
||||
|
||||
void add_tty(struct tty_funcs funcs) {
|
||||
m_lock(&ttysMutex);
|
||||
|
||||
if (ttyNum >= ttys.num) {
|
||||
if (ttys.num == 0) {
|
||||
ttys.ttys = static_cast<tty *>(kmalloc(sizeof(struct ttys) + sizeof(struct tty)));
|
||||
ttys.num = 1;
|
||||
} else {
|
||||
ttys.num *= 2;
|
||||
ttys.ttys = static_cast<tty *>(krealloc(ttys.ttys, sizeof(struct ttys) + sizeof(struct tty) * ttys.num));
|
||||
}
|
||||
assert2(ttys.ttys != NULL, "Couldn't allocate memory for ttys!");
|
||||
}
|
||||
|
||||
m_init(&ttys.ttys[ttyNum].lock);
|
||||
ttys.ttys[ttyNum].id = ttyNum;
|
||||
ttys.ttys[ttyNum].funcs = funcs;
|
||||
|
||||
ttyNum++;
|
||||
|
||||
m_unlock(&ttysMutex);
|
||||
ttys.emplace_back(ttys.size(), funcs);
|
||||
}
|
||||
|
||||
void tty_putchar(struct tty *tty, char c) {
|
||||
m_lock(&tty->lock);
|
||||
LockGuard l(tty->lock);
|
||||
tty->funcs.putchar(c);
|
||||
m_unlock(&tty->lock);
|
||||
}
|
||||
|
||||
void tty_putstr(struct tty *tty, const char *str) {
|
||||
m_lock(&tty->lock);
|
||||
LockGuard l(tty->lock);
|
||||
while (*str != '\0') tty->funcs.putchar(*str++);
|
||||
m_unlock(&tty->lock);
|
||||
}
|
||||
|
||||
void all_tty_putchar(char c) {
|
||||
for (unsigned i = 0; i < ttyNum; i++) { tty_putchar(get_tty(i), c); }
|
||||
for (unsigned i = 0; i < get_num_ttys(); i++) { tty_putchar(get_tty(i), c); }
|
||||
}
|
||||
|
||||
void all_tty_putstr(const char *str) {
|
||||
for (unsigned i = 0; i < ttyNum; i++) { tty_putstr(get_tty(i), str); }
|
||||
for (unsigned i = 0; i < get_num_ttys(); i++) { tty_putstr(get_tty(i), str); }
|
||||
}
|
||||
|
||||
unsigned get_num_ttys() {
|
||||
return ttyNum;
|
||||
return ttys.size();
|
||||
}
|
||||
|
||||
struct tty *get_tty(unsigned n) {
|
||||
if (n < get_num_ttys()) return &ttys.ttys[n];
|
||||
if (n < get_num_ttys()) return &ttys[n];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
@@ -6,16 +6,17 @@
|
||||
#define OS1_TTY_H
|
||||
|
||||
#include "mutex.hpp"
|
||||
#include <stdint.h>
|
||||
|
||||
struct tty_funcs {
|
||||
void (*putchar)(char);
|
||||
};
|
||||
|
||||
struct tty {
|
||||
Mutex lock;
|
||||
unsigned id;
|
||||
struct Mutex lock;
|
||||
struct tty_funcs funcs;
|
||||
tty_funcs funcs;
|
||||
|
||||
tty(unsigned id, tty_funcs funcs) : id(id), funcs(funcs) {}
|
||||
};
|
||||
|
||||
void add_tty(struct tty_funcs);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
target_include_directories(kernel.elf PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
target_sources(kernel.elf PRIVATE mutex.cpp cv.cpp cppsupport.cpp Spinlock.cpp LockGuard.cpp rand.cpp)
|
||||
target_sources(kernel.elf PRIVATE mutex.cpp cppsupport.cpp Spinlock.cpp LockGuard.cpp rand.cpp)
|
||||
|
||||
add_subdirectory(templates)
|
||||
@@ -71,4 +71,15 @@ void operator delete(void *p, size_t n) {
|
||||
|
||||
void operator delete[](void *p, size_t n) {
|
||||
kfree(p);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
void *__dso_handle = nullptr;
|
||||
|
||||
// Do we really care about destructors at kernel exit?
|
||||
int __cxa_atexit(void (*f)(void *), void *objptr, void *dso) {
|
||||
writestr("Something registered\n");
|
||||
return 0;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 20.08.2023.
|
||||
//
|
||||
|
||||
#include "cv.hpp"
|
||||
|
||||
#include "mutex.hpp"
|
||||
#include "serial.hpp"
|
||||
#include "task.hpp"
|
||||
|
||||
void cv_wait(struct Mutex *m, struct CV *cv) {
|
||||
m_unlock(m);
|
||||
wait_cv_on_self(cv);
|
||||
m_lock(m);
|
||||
}
|
||||
|
||||
void cv_notify_one(struct CV *cv) {
|
||||
cv_unlock_sched_hook(cv, CV_NOTIFY_ONE);
|
||||
}
|
||||
|
||||
void cv_notify_all(struct CV *cv) {
|
||||
cv_unlock_sched_hook(cv, CV_NOTIFY_ALL);
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 20.08.2023.
|
||||
//
|
||||
|
||||
#ifndef OS1_CV_H
|
||||
#define OS1_CV_H
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
|
||||
#if !(ATOMIC_INT_LOCK_FREE == 2)
|
||||
#error Atomic int isnt lock free!
|
||||
#endif
|
||||
|
||||
struct Mutex;
|
||||
|
||||
enum CV_NOTIFY {
|
||||
CV_NOTIFY_NONE = 0,
|
||||
CV_NOTIFY_ONE = 1,
|
||||
CV_NOTIFY_ALL = 2,
|
||||
};
|
||||
|
||||
struct CV {
|
||||
std::atomic<int> notified;
|
||||
struct TaskList *waiters;
|
||||
};
|
||||
|
||||
void cv_wait(struct Mutex *m, struct CV *cv);
|
||||
void cv_notify_one(struct CV *cv);
|
||||
void cv_notify_all(struct CV *cv);
|
||||
|
||||
#endif//OS1_CV_H
|
||||
@@ -3,73 +3,78 @@
|
||||
//
|
||||
|
||||
#include "mutex.hpp"
|
||||
#include "LockGuard.hpp"
|
||||
#include "serial.hpp"
|
||||
#include "task.hpp"
|
||||
#include "timer.hpp"
|
||||
|
||||
void m_init(struct Mutex *m) {
|
||||
atomic_init(&m->locked, false);
|
||||
m->waiters = NULL;
|
||||
m->spin_success = 127;
|
||||
m->owner = NULL;
|
||||
}
|
||||
|
||||
bool m_try_lock(struct Mutex *m) {
|
||||
bool Mutex::try_lock() {
|
||||
bool expected = false;
|
||||
if (!m->locked.compare_exchange_strong(expected, true)) {
|
||||
if (!locked.compare_exchange_strong(expected, true)) {
|
||||
return false;
|
||||
}
|
||||
m->owner = cur_task();
|
||||
owner = cur_task();
|
||||
return true;
|
||||
}
|
||||
|
||||
void m_spin_lock(struct Mutex *m) {
|
||||
while (!m_try_lock(m)) { __builtin_ia32_pause(); }
|
||||
void Mutex::spin_lock() {
|
||||
while (!Mutex::try_lock()) { yield_self(); }
|
||||
}
|
||||
|
||||
void m_lock(struct Mutex *m) {
|
||||
bool spin_success = false;
|
||||
void Mutex::lock() {
|
||||
bool spinned = false;
|
||||
|
||||
if (m_try_lock(m)) {
|
||||
if (m->spin_success < 255)
|
||||
m->spin_success++;
|
||||
if (Mutex::try_lock()) {
|
||||
if (spin_success < 255)
|
||||
spin_success++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m->spin_success >= 127) {
|
||||
if (spin_success >= 127) {
|
||||
uint64_t startMicros = micros;
|
||||
while (micros - startMicros < 10) {
|
||||
|
||||
if (m_try_lock(m)) {
|
||||
spin_success = true;
|
||||
if (Mutex::try_lock()) {
|
||||
spinned = true;
|
||||
break;
|
||||
}
|
||||
|
||||
__builtin_ia32_pause();
|
||||
yield_self();
|
||||
}
|
||||
}
|
||||
|
||||
if (spin_success) {
|
||||
if (m->spin_success < 255)
|
||||
m->spin_success++;
|
||||
if (spinned) {
|
||||
if (spin_success < 255)
|
||||
spin_success++;
|
||||
return;
|
||||
} else {
|
||||
if (m->spin_success > 0)
|
||||
m->spin_success--;
|
||||
if (spin_success > 0)
|
||||
spin_success--;
|
||||
|
||||
while (!m_try_lock(m)) {
|
||||
wait_m_on_self(m);
|
||||
while (!Mutex::try_lock()) {
|
||||
waiters_lock.lock();
|
||||
waiters.emplace_front(cur_task());
|
||||
self_block(waiters_lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void m_unlock(struct Mutex *m) {
|
||||
void Mutex::unlock() {
|
||||
bool expected = true;
|
||||
if (!m->locked.compare_exchange_strong(expected, false))
|
||||
if (!locked.compare_exchange_strong(expected, false))
|
||||
writestr("Unlocking an unlocked mutex!\n");
|
||||
m_unlock_sched_hook(m);
|
||||
Task *t = nullptr;
|
||||
{
|
||||
LockGuard l(waiters_lock);
|
||||
if (!waiters.empty()) {
|
||||
t = waiters.back();
|
||||
waiters.pop_back();
|
||||
}
|
||||
}
|
||||
if (t) unblock(t);
|
||||
}
|
||||
|
||||
bool m_test(struct Mutex *m) {
|
||||
return atomic_load(&m->locked);
|
||||
bool Mutex::test() {
|
||||
return atomic_load(&locked);
|
||||
}
|
||||
@@ -9,19 +9,31 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "List.hpp"
|
||||
#include "Spinlock.hpp"
|
||||
|
||||
struct Mutex {
|
||||
std::atomic<bool> locked;
|
||||
struct TaskList *waiters;
|
||||
struct Task *owner;
|
||||
uint8_t spin_success;
|
||||
struct Task;
|
||||
struct TaskListNode;
|
||||
|
||||
class Mutex {
|
||||
public:
|
||||
Mutex() = default;
|
||||
|
||||
void lock();
|
||||
void spin_lock();
|
||||
bool try_lock();
|
||||
void unlock();
|
||||
bool test();
|
||||
|
||||
private:
|
||||
std::atomic<bool> locked = false;
|
||||
|
||||
List<Task *> waiters;
|
||||
Spinlock waiters_lock;
|
||||
|
||||
Task *owner = nullptr;
|
||||
uint8_t spin_success = 127;
|
||||
};
|
||||
|
||||
void m_init(struct Mutex *m);
|
||||
void m_lock(struct Mutex *m);
|
||||
void m_spin_lock(struct Mutex *m);
|
||||
bool m_try_lock(struct Mutex *m);
|
||||
void m_unlock(struct Mutex *m);
|
||||
bool m_test(struct Mutex *m);
|
||||
|
||||
#endif//OS1_MUTEX_H
|
||||
|
||||
Reference in New Issue
Block a user