General Purpose library for Freestanding C++ and POSIX systems
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

105 satır
3.0 KiB

  1. #pragma once
  2. #include "gp/algorithm/foreach.hpp"
  3. #include "gp/algorithm/reference.hpp"
  4. #include "gp/allocator/allocator.hpp"
  5. #include "gp/vector.hpp"
  6. #include "gp/vfs/file_description.hpp"
  7. #include "gp/vfs/filesystem.hpp"
  8. #include "gp/vfs/scheduler.hpp"
  9. namespace gp{
  10. // TODO: thread safety
  11. class system {
  12. gp::reference_wrapper<gp::allocator> system_allocator;
  13. gp::vector<gp::filesystem*> filesystems{system_allocator};
  14. gp::vector<gp::scheduler> process_managers;
  15. gp::indexed_array<gp::process_data*, gp_config::limits::max_processes> processes;
  16. friend class scheduler;
  17. public:
  18. system(allocator& v, size_t scheduler_count)
  19. : system_allocator{v}
  20. , process_managers{system_allocator}
  21. {
  22. gp_config::assertion(scheduler_count >= 1, "no scheduling in the system");
  23. process_managers.reserve(scheduler_count);
  24. gp::repeat(scheduler_count,[&](){
  25. process_managers.emplace_back(*this);
  26. });
  27. }
  28. size_t spawn(gp::function<void()> fn) {
  29. constexpr size_t stack_sz = gp_config::limits::process_stack;
  30. void* stack = system_allocator.get().allocate(stack_sz);
  31. gp_config::assertion(stack != nullptr, "failed to allocate a stack");
  32. process_data* created_process = (process_data*)system_allocator.get().allocate(sizeof(process_data));
  33. gp_config::assertion(stack != nullptr, "failed to allocate a process data");
  34. new(created_process) process_data(fn, stack, stack_sz);
  35. return processes.push(created_process);
  36. }
  37. void run_once() {
  38. (*process_managers.begin()).run_once();
  39. (*process_managers.begin()).cleanup(system_allocator);
  40. }
  41. };
  42. scheduler::scheduler(class system& v)
  43. : sys(v){}
  44. no_inline_decl(
  45. void scheduler::yield_to(size_t target_pid)
  46. ) {
  47. auto& cur = current ? sys.processes[current-1]->specifics : root;
  48. auto& target = target_pid ? sys.processes[target_pid-1]->specifics : root;
  49. current = target_pid;
  50. cur.pull();
  51. if(target_pid)
  52. {
  53. no_inline_decl([&](scheduler* new_p)){
  54. auto& proc = *new_p->sys.processes[new_p->current-1];
  55. if(proc.state == gp::process_status::inactive) {
  56. proc.state = gp::process_status::running;
  57. proc.fn();
  58. proc.state = gp::process_status::finished;
  59. new_p->yield_to(0);
  60. }
  61. }(static_cast<scheduler*>(target.push(this)));
  62. } else {
  63. volatile scheduler* new_p = static_cast<scheduler*>(target.push(this));
  64. }
  65. }
  66. void scheduler::cleanup(allocator& alloc) {
  67. sys.processes.foreach(
  68. [&] (size_t pid, process_data* process) {
  69. if(
  70. process->state == process_status::finished
  71. ) {
  72. process->fds.foreach([](size_t, file_description* fdes){
  73. fdes->close();
  74. });
  75. gp_config::assertion(alloc.deallocate(process->stack), "can't deallocate the stack");
  76. sys.processes.mark_for_removal(pid);
  77. gp_config::assertion(alloc.deallocate(process), "can't deallocate the process data");
  78. }
  79. }
  80. );
  81. sys.processes.sweep_removed();
  82. }
  83. void scheduler::run_once() {
  84. sys.processes.foreach(
  85. [&] (size_t pid, process_data* process) {
  86. if(
  87. process->state == process_status::inactive
  88. || process->state == process_status::running
  89. ) {
  90. yield_to(pid+1);
  91. }
  92. }
  93. );
  94. }
  95. }