A bunch of random code samples
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

202 lines
4.9 KiB

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