A bunch of random code samples
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

204 строки
4.9 KiB

3 лет назад
  1. // Build with: clang++ --std=c++20 -g -O1 schedtest.cpp
  2. #include <array>
  3. #include <span>
  4. #include <memory>
  5. #include <list>
  6. #include <functional>
  7. #include <iostream>
  8. #if defined(__x86_64__)
  9. #if defined(__GNUG__)
  10. constexpr bool is_x86_64_linux = true;
  11. #else
  12. #if defined(__clang__)
  13. constexpr bool is_x86_64_linux = true;
  14. #else
  15. constexpr bool is_x86_64_linux = false;
  16. #endif
  17. #endif
  18. #else
  19. constexpr bool is_x86_64_linux = false;
  20. #endif
  21. static_assert(is_x86_64_linux, "This code probably only works on x86_64 GNU Extensions C++");
  22. struct platform_data {
  23. platform_data() = default;
  24. platform_data(std::span<char> stack_str)
  25. : stack_ptr(&*(stack_str.end()-16))
  26. , base_ptr(stack_ptr)
  27. {}
  28. uint64_t rbx, r12, r13, r14, r15;
  29. void* stack_ptr;
  30. void* base_ptr;
  31. void pull() __attribute__((always_inline))
  32. {
  33. __asm__ __volatile__(
  34. "movq %%rsp, %0\n"
  35. "movq %%rbp, %1\n"
  36. "movq %%rbx, %2\n"
  37. "movq %%r12, %3\n"
  38. "movq %%r13, %4\n"
  39. "movq %%r14, %5\n"
  40. "movq %%r15, %6\n"
  41. : "=m"(stack_ptr)
  42. , "=m"(base_ptr)
  43. , "=m"(rbx)
  44. , "=m"(r12)
  45. , "=m"(r13)
  46. , "=m"(r14)
  47. , "=m"(r15)
  48. );
  49. }
  50. void* push(void* location) __attribute__((always_inline))
  51. {
  52. volatile void* volatile tmp = static_cast<char*>(stack_ptr) - sizeof(void*);
  53. *static_cast<volatile void* volatile * volatile>(tmp) = location;
  54. __asm__ __volatile__(
  55. "movq %1, %%rsp\n"
  56. "movq %2, %%rbp\n"
  57. "movq %3, %%rbx\n"
  58. "movq %4, %%r12\n"
  59. "movq %5, %%r13\n"
  60. "movq %6, %%r14\n"
  61. "movq %7, %%r15\n"
  62. "popq %0\n"
  63. : "+r"(location)
  64. : "m"(tmp)
  65. , "m"(base_ptr)
  66. , "m"(rbx)
  67. , "m"(r12)
  68. , "m"(r13)
  69. , "m"(r14)
  70. , "m"(r15)
  71. : "memory"
  72. );
  73. return location;
  74. }
  75. };
  76. enum class process_status {
  77. inactive = 0,
  78. running = 1,
  79. waiting = 2,
  80. finished = 3,
  81. zombie = 4
  82. };
  83. struct process {
  84. char* stack;
  85. size_t sz;
  86. platform_data scheduling_swapper;
  87. process_status state = process_status::inactive;
  88. std::function<void()> fn;
  89. process(std::function<void()> _fn, size_t _sz = 16384)
  90. : stack(new char[_sz])
  91. , sz(_sz)
  92. , scheduling_swapper(std::span<char>(stack, sz))
  93. , fn(_fn)
  94. {}
  95. process(char* stack_base)
  96. : stack(stack_base)
  97. , sz(0)
  98. {}
  99. process(const process&) = delete;
  100. ~process() {
  101. if(sz) delete[] stack;
  102. }
  103. };
  104. __attribute__((noinline)) struct system* spawner (struct system* sys);
  105. struct system {
  106. static system sys;
  107. std::list<std::unique_ptr<process>>
  108. running,
  109. waiting,
  110. naughty;
  111. std::unique_ptr<process> previous;
  112. std::unique_ptr<process> current;
  113. std::unique_ptr<process> one() {
  114. auto v = std::move(running.back());
  115. running.pop_back();
  116. return v;
  117. }
  118. void rid(std::unique_ptr<process> current) {
  119. switch(current->state) {
  120. case process_status::inactive:
  121. case process_status::running:
  122. running.push_front(std::move(current));
  123. break;
  124. case process_status::finished:
  125. clean(std::move(current));
  126. break;
  127. case process_status::zombie:
  128. naughty.push_front(std::move(current));
  129. break;
  130. case process_status::waiting:
  131. waiting.push_front(std::move(current));
  132. break;
  133. }
  134. }
  135. void clean(std::unique_ptr<process>) {}
  136. void yield_to(std::unique_ptr<process> target) noexcept {
  137. current->scheduling_swapper.pull();
  138. sys.rid(std::move(current));
  139. current = std::move(target);
  140. current->scheduling_swapper.push(this);
  141. spawner(&sys);
  142. }
  143. void yield() noexcept {
  144. current->scheduling_swapper.pull();
  145. sys.rid(std::move(current));
  146. current = one();
  147. current->scheduling_swapper.push(this);
  148. spawner(&sys);
  149. }
  150. };
  151. // Needs to return the system one way or another
  152. __attribute__((noinline)) struct system* spawner (struct system* sys) {
  153. auto& proc = *system::sys.current;
  154. if(proc.state == process_status::inactive) {
  155. proc.state = process_status::running;
  156. proc.fn();
  157. proc.state = process_status::finished;
  158. sys->current->scheduling_swapper.pull();
  159. sys->yield();
  160. }
  161. return sys;
  162. }
  163. struct system system::sys;
  164. int main() {
  165. char c;
  166. system::sys.current = std::make_unique<process>(&c);
  167. std::cout << "1";
  168. system::sys.current->state = process_status::running;
  169. system::sys.yield_to(std::make_unique<process>([](){
  170. std::cout << "2";
  171. }));
  172. std::cout << "3\n";
  173. return 0;
  174. }