#pragma once #include "gp/ipc/bottleneck.hpp" #include "gp/system/system.hpp" namespace gp{ namespace system { class simple_scheduling : public gp::system::scheduling_scheme { struct locked_circular_buffer { gp::array processes; size_t read_idx = 0; size_t write_idx = 0; fast_bottleneck lock; void push(gp::system::task_queue::node_ptr node) { auto guard = lock_guard(lock); gp_config::assertion((write_idx + 1)%processes.size() != read_idx, "bad push to circular buffer"); processes[write_idx] = node; write_idx=(write_idx+1)%processes.size(); } gp::system::task_queue::node_ptr pop() { gp::system::task_queue::node_ptr ret; auto guard = lock_guard(lock); if(read_idx == write_idx) { ret = nullptr; } else { ret = processes[read_idx]; read_idx=(read_idx+1)%processes.size(); } return ret; } }; locked_circular_buffer running; locked_circular_buffer waiting; locked_circular_buffer to_clean; locked_circular_buffer naughty; system* sys = nullptr; public: simple_scheduling() {} virtual void link(system& value) { gp_config::assertion(!(sys), "Double linkage detected"); sys = &value; sys->process_managers.emplace_back(*sys,0); } virtual gp::system::task_queue::node_ptr one(size_t) { auto v = running.pop(); do{ if(v) return v; v = running.pop(); }while(true); } virtual void push(gp::system::task_queue::node_ptr node) { running.push(node); } virtual gp::system::task_queue::node_ptr next(size_t, gp::system::task_queue::node_ptr current) { switch(current->value->state) { case process_status::inactive: case process_status::running: running.push(current); break; case process_status::finished: to_clean.push(current); break; case process_status::zombie: naughty.push(current); break; case process_status::waiting: waiting.push(current); break; } return one(0); } virtual gp::system::scheduler& current_scheduler() { return sys->process_managers[0]; } }; } }