From a295f8642c7ce387ce252b16570d461ad37e8746 Mon Sep 17 00:00:00 2001 From: Ludovic 'Archivist' Lagouardette Date: Thu, 29 Oct 2020 02:33:38 +0100 Subject: [PATCH] advanced scheduling introduced --- include/gp/vfs/process_data.hpp | 3 + include/gp/vfs/runqueue.hpp | 44 +++---- include/gp/vfs/scheduler.hpp | 30 ++--- .../scheduling/simple_lockfree_scheduling.hpp | 44 +++++++ include/gp/vfs/system.hpp | 119 +++++++++--------- 5 files changed, 133 insertions(+), 107 deletions(-) create mode 100644 include/gp/vfs/scheduling/simple_lockfree_scheduling.hpp diff --git a/include/gp/vfs/process_data.hpp b/include/gp/vfs/process_data.hpp index de92254..d388757 100644 --- a/include/gp/vfs/process_data.hpp +++ b/include/gp/vfs/process_data.hpp @@ -19,7 +19,10 @@ namespace gp { zombie = 4 }; + using pid_t = size_t; + struct process_data{ + pid_t pid; gp::function fn; void* stack; size_t stack_sz; diff --git a/include/gp/vfs/runqueue.hpp b/include/gp/vfs/runqueue.hpp index 5dbabf8..e113ea8 100644 --- a/include/gp/vfs/runqueue.hpp +++ b/include/gp/vfs/runqueue.hpp @@ -4,27 +4,26 @@ #include -class runqueue{ - - struct node{ - std::atomic_bool is_locked; - gp::process_data* value; - std::atomic next; +namespace gp { + struct topic_list{ + struct node{ + std::atomic_bool is_locked; + gp::process_data* value; + std::atomic next; - bool try_acquire() noexcept { - bool expected = false; - return !(is_locked.compare_exchange_strong(expected, true)); - } + bool try_acquire() noexcept { + bool expected = false; + return !(is_locked.compare_exchange_strong(expected, true)); + } - void release() noexcept { - is_locked.store(false); - } - }; + void release() noexcept { + is_locked.store(false); + } + }; - using node_ptr = struct node*; - using node_ptr_rep = std::atomic; + using node_ptr = struct node*; + using node_ptr_rep = std::atomic; - struct topic_list{ node_ptr_rep start; node_ptr_rep end; @@ -49,7 +48,8 @@ class runqueue{ } } - // ONLY PUSH ACQUIRED NODES + // ONLY PUSH ACQUIRED NODES, + // RELEASE WHEN NO LONGER IN USE bool try_push(node_ptr node) { auto ed = end.load(); if(ed) { @@ -57,18 +57,15 @@ class runqueue{ node->next.store(ed); if(end.compare_exchange_strong(ed, node)) { ed->release(); - node->release(); return true; } else { ed->release(); - node->release(); return false; } } else return false; } else { if(end.compare_exchange_strong(ed, node)) { start.store(node); - node->release(); return true; } else { return false; @@ -76,7 +73,4 @@ class runqueue{ } } }; - - topic_list running; - topic_list waiting; -}; \ No newline at end of file +} \ No newline at end of file diff --git a/include/gp/vfs/scheduler.hpp b/include/gp/vfs/scheduler.hpp index 154fb6f..8b2f2bc 100644 --- a/include/gp/vfs/scheduler.hpp +++ b/include/gp/vfs/scheduler.hpp @@ -2,39 +2,27 @@ #include "gp/indexed_array.hpp" #include "gp/vfs/process_data.hpp" +#include "gp/vfs/runqueue.hpp" namespace gp{ class system; -class scheduler { - gp::specifics::platform_data root; - size_t current = 0; +struct scheduler { + topic_list::node_ptr previous; + topic_list::node_ptr current; + size_t id; system& sys; no_inline_decl( - void yield_to(size_t target_pid) + void yield_to(topic_list::node_ptr target) ); + scheduler(class system&, size_t token); - -public: - scheduler(class system&); - - [[noreturn]] void run(allocator& alloc) { - again: - run_once(); - cleanup(alloc); - goto again; - } - - void cleanup(allocator& alloc); - - void run_once(); + [[noreturn]] void startup(); - void yield(){ - yield_to(0); - } + void yield(); }; } \ No newline at end of file diff --git a/include/gp/vfs/scheduling/simple_lockfree_scheduling.hpp b/include/gp/vfs/scheduling/simple_lockfree_scheduling.hpp new file mode 100644 index 0000000..841aa80 --- /dev/null +++ b/include/gp/vfs/scheduling/simple_lockfree_scheduling.hpp @@ -0,0 +1,44 @@ +#pragma once +#include "gp/vfs/system.hpp" + +namespace gp{ + + class simple_lockfree_scheduling : gp::scheduling_scheme { + gp::topic_list running; + gp::topic_list waiting; + gp::topic_list to_clean; + gp::topic_list naughty; + scheduler me; + + public: + virtual gp::topic_list::node_ptr one(size_t) { + auto v = running.try_pop(); + do{ + if(v) return v; + v = running.try_pop(); + }while(true); + } + virtual gp::topic_list::node_ptr next(size_t, gp::topic_list::node_ptr current) { + switch(current->value->state) { + case process_status::inactive: + case process_status::running: + do{}while(!running.try_push(current)); + break; + case process_status::finished: + do{}while(!to_clean.try_push(current)); + break; + case process_status::zombie: + do{}while(!naughty.try_push(current)); + break; + case process_status::waiting: + do{}while(!waiting.try_push(current)); + break; + } + return one(0); + } + + virtual gp::scheduler& current_scheduler() { + return me; + } + }; +} \ No newline at end of file diff --git a/include/gp/vfs/system.hpp b/include/gp/vfs/system.hpp index bf85cd1..3522c1f 100644 --- a/include/gp/vfs/system.hpp +++ b/include/gp/vfs/system.hpp @@ -6,28 +6,34 @@ #include "gp/vector.hpp" #include "gp/vfs/file_description.hpp" #include "gp/vfs/filesystem.hpp" +#include "gp/vfs/runqueue.hpp" #include "gp/vfs/scheduler.hpp" + namespace gp{ // TODO: thread safety + +class scheduling_scheme { +public: + virtual topic_list::node_ptr one(size_t token) = 0; + virtual topic_list::node_ptr next(size_t token, topic_list::node_ptr current) = 0; + virtual scheduler& current_scheduler() = 0; +}; + class system { gp::reference_wrapper system_allocator; gp::vector filesystems{system_allocator}; gp::vector process_managers; - gp::indexed_array processes; + scheduling_scheme& scheme; + friend class scheduler; public: - system(allocator& v, size_t scheduler_count) + system(allocator& v, scheduling_scheme& scheme_) : system_allocator{v} , process_managers{system_allocator} - { - gp_config::assertion(scheduler_count >= 1, "no scheduling in the system"); - process_managers.reserve(scheduler_count); - gp::repeat(scheduler_count,[&](){ - process_managers.emplace_back(*this); - }); - } + , scheme{scheme_} + {} size_t spawn(gp::function fn) { constexpr size_t stack_sz = gp_config::limits::process_stack; @@ -36,70 +42,61 @@ public: process_data* created_process = (process_data*)system_allocator.get().allocate(sizeof(process_data)); gp_config::assertion(stack != nullptr, "failed to allocate a process data"); new(created_process) process_data(fn, stack, stack_sz); - return processes.push(created_process); - } - void run_once() { - (*process_managers.begin()).run_once(); - (*process_managers.begin()).cleanup(system_allocator); + topic_list::node_ptr pp = (topic_list::node_ptr)system_allocator.get().allocate( + sizeof(topic_list::node) + ); + new(pp) topic_list::node(); + pp->value = created_process; + + auto& sched = scheme.current_scheduler(); + sched.yield_to(scheme.next(sched.id, pp)); + return pp->value->pid; } }; -scheduler::scheduler(class system& v) -: sys(v){} +scheduler::scheduler(class system& v, size_t token) +: id(token) +, sys(v) +{} -void scheduler::yield_to(size_t target_pid) +void scheduler::yield_to(topic_list::node_ptr target) { - auto& cur = current ? sys.processes[current-1]->specifics : root; - auto& target = target_pid ? sys.processes[target_pid-1]->specifics : root; - current = target_pid; - cur.pull(); - if(target_pid) - { - no_inline_decl([&](scheduler* new_p)){ - auto& proc = *new_p->sys.processes[new_p->current-1]; - if(proc.state == gp::process_status::inactive) { - proc.state = gp::process_status::running; - proc.fn(); - proc.state = gp::process_status::finished; - new_p->yield_to(0); - } - }(static_cast(target.push(this))); - } else { - [[maybe_unused]] volatile scheduler* new_p = static_cast(target.push(this)); - } + previous = current; + current->value->specifics.pull(); + current = target; + no_inline_decl([&](scheduler* new_p)){ + *new_p->previous->release(); + auto& proc = *new_p->current->value; + if(proc.state == gp::process_status::inactive) { + proc.state = gp::process_status::running; + proc.fn(); + proc.state = gp::process_status::finished; + new_p->yield_to(new_p->sys.scheme.next(new_p->id, new_p->current)); + } + }(static_cast(target->value->specifics.push(this))); } -void scheduler::cleanup(allocator& alloc) { - sys.processes.foreach( - [&] (size_t pid, process_data* process) { - if( - process->state == process_status::finished - ) { - process->fds.foreach([](size_t, file_description* fdes){ - fdes->close(); - }); - gp_config::assertion(alloc.deallocate(process->stack), "can't deallocate the stack"); - sys.processes.mark_for_removal(pid); - gp_config::assertion(alloc.deallocate(process), "can't deallocate the process data"); - } - } - ); - sys.processes.sweep_removed(); +void scheduler::yield(){ + current = sys.scheme.next(id, current); + yield_to(current); } -void scheduler::run_once() { - sys.processes.foreach( - [&] (size_t pid, process_data* process) { - if( - process->state == process_status::inactive - || process->state == process_status::running - ) { - yield_to(pid+1); - } + +void scheduler::startup() +{ + current = sys.scheme.one(id); + no_inline_decl([&](scheduler* new_p)){ + auto& proc = *new_p->current->value; + if(proc.state == gp::process_status::inactive) { + proc.state = gp::process_status::running; + proc.fn(); + proc.state = gp::process_status::finished; + new_p->yield_to(new_p->sys.scheme.next(new_p->id, new_p->current)); } - ); + }(static_cast(target->value->specifics.push(this))); } + } \ No newline at end of file