brand new mutex

This commit is contained in:
2023-10-23 21:01:40 +02:00
parent c61d7f586e
commit c8dc675734
11 changed files with 134 additions and 218 deletions

View File

@@ -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)();

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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)

View File

@@ -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;
};
};

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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