General Purpose library for Freestanding C++ and POSIX systems
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 

102 行
2.8 KiB

#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/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<gp::allocator> system_allocator;
gp::vector<gp::filesystem*> filesystems{system_allocator};
gp::vector<gp::scheduler> process_managers;
scheduling_scheme& scheme;
friend class scheduler;
public:
system(allocator& v, scheduling_scheme& scheme_)
: system_allocator{v}
, process_managers{system_allocator}
, scheme{scheme_}
{}
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);
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, size_t token)
: id(token)
, sys(v)
{}
void scheduler::yield_to(topic_list::node_ptr target)
{
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<scheduler*>(target->value->specifics.push(this)));
}
void scheduler::yield(){
current = sys.scheme.next(id, current);
yield_to(current);
}
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<scheduler*>(target->value->specifics.push(this)));
}
}