|
|
- #pragma once
-
- #include "gp/algorithm/foreach.hpp"
- #include "gp/algorithm/reference.hpp"
- #include "gp/allocator/allocator.hpp"
- #include "gp/vector.hpp"
- #include "gp/vfs/file_description.hpp"
- #include "gp/vfs/filesystem.hpp"
- #include "gp/vfs/scheduler.hpp"
-
- namespace gp{
- // TODO: thread safety
- class system {
- gp::reference_wrapper<gp::allocator> system_allocator;
- gp::vector<gp::filesystem*> filesystems{system_allocator};
- gp::vector<gp::scheduler> process_managers;
- gp::indexed_array<gp::process_data*, gp_config::limits::max_processes> processes;
-
- friend class scheduler;
- public:
- system(allocator& v, size_t scheduler_count)
- : 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);
- });
- }
-
- size_t spawn(gp::function<void()> fn) {
- constexpr size_t stack_sz = gp_config::limits::process_stack;
- void* stack = system_allocator.get().allocate(stack_sz);
- gp_config::assertion(stack != nullptr, "failed to allocate a stack");
- 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);
- }
- };
-
- scheduler::scheduler(class system& v)
- : sys(v){}
-
- void scheduler::yield_to(size_t target_pid)
- {
- 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<scheduler*>(target.push(this)));
- } else {
- [[maybe_unused]] volatile scheduler* new_p = static_cast<scheduler*>(target.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::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);
- }
- }
- );
- }
-
- }
|