Advertisement
Guest User

Untitled

a guest
Jun 24th, 2019
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.42 KB | None | 0 0
  1. #include <algorithm>
  2. #include <array>
  3. #include <stddef.h>
  4. #include <stdint.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7.  
  8. static const size_t STACK_SIZE = 16777216;
  9. static const size_t DEFAULT_THREADS = 4;
  10. struct Runtime;
  11. static Runtime* runtime;
  12.  
  13. enum class ThreadState {
  14. Available,
  15. Ready,
  16. Running,
  17. };
  18.  
  19. struct ThreadContext {
  20. uint64_t rsp, r15, r14, r13, r12, rbx, rbp;
  21. ThreadContext() : rsp(), r15(), r14(), r13(), r12(), rbx(), rbp() {}
  22. static __attribute__((noinline)) __attribute__((naked)) void
  23. switch_to(ThreadContext&, ThreadContext&) {
  24. __asm__ volatile(
  25. "movq %rsp, (%rdi)\n\t"
  26. "movq %r15, 0x8(%rdi)\n\t"
  27. "movq %r14, 0x10(%rdi)\n\t"
  28. "movq %r13, 0x18(%rdi)\n\t"
  29. "movq %r12, 0x20(%rdi)\n\t"
  30. "movq %rbx, 0x28(%rdi)\n\t"
  31. "movq %rbp, 0x30(%rdi)\n\t"
  32.  
  33. "movq (%rsi), %rsp\n\t"
  34. "movq 0x8(%rsi), %r15\n\t"
  35. "movq 0x10(%rsi), %r14\n\t"
  36. "movq 0x18(%rsi), %r13\n\t"
  37. "movq 0x20(%rsi), %r12\n\t"
  38. "movq 0x28(%rsi), %rbx\n\t"
  39. "movq 0x30(%rsi), %rbp\n\t"
  40.  
  41. "ret");
  42. }
  43. };
  44. static_assert(offsetof(ThreadContext, rsp) == 0, "unexpected offset");
  45. static_assert(offsetof(ThreadContext, r15) == 010, "unexpected offset");
  46. static_assert(offsetof(ThreadContext, r14) == 020, "unexpected offset");
  47. static_assert(offsetof(ThreadContext, r13) == 030, "unexpected offset");
  48. static_assert(offsetof(ThreadContext, r12) == 040, "unexpected offset");
  49. static_assert(offsetof(ThreadContext, rbx) == 050, "unexpected offset");
  50. static_assert(offsetof(ThreadContext, rbp) == 060, "unexpected offset");
  51.  
  52. struct Thread {
  53. size_t id;
  54. void* stack;
  55. ThreadContext ctx;
  56. ThreadState state;
  57. Thread() : id(0), stack(), state(ThreadState::Available) {
  58. stack = malloc(STACK_SIZE);
  59. if (!stack) {
  60. fputs("Could not allocate memory for new thread.\n", stderr);
  61. exit(1);
  62. }
  63. }
  64. };
  65.  
  66. struct Runtime {
  67. std::array<Thread, 1 + DEFAULT_THREADS> threads;
  68. size_t current;
  69. Runtime() : threads(), current(0) {
  70. threads.front().state = ThreadState::Running;
  71. for (size_t i = 1; i <= DEFAULT_THREADS; ++i) { threads[i].id = i; }
  72. }
  73. void init() { runtime = this; }
  74. void run() {
  75. while (yield())
  76. ;
  77. exit(0);
  78. }
  79. void ret() {
  80. if (current) {
  81. threads[current].state = ThreadState::Available;
  82. yield();
  83. }
  84. }
  85. bool yield() {
  86. auto next_ready = std::find_if(
  87. threads.begin() + current, threads.end(),
  88. [](Thread const& th) { return th.state == ThreadState::Ready; });
  89. if (next_ready == threads.end()) {
  90. next_ready = std::find_if(
  91. threads.begin(), threads.begin() + current,
  92. [](Thread const& th) { return th.state == ThreadState::Ready; });
  93. }
  94. if (next_ready == threads.begin() + current) { return false; }
  95.  
  96. if (threads[current].state != ThreadState::Available)
  97. threads[current].state = ThreadState::Ready;
  98.  
  99. next_ready->state = ThreadState::Running;
  100. size_t old = current;
  101. current = next_ready - threads.begin();
  102.  
  103. ThreadContext::switch_to(threads[old].ctx, next_ready->ctx);
  104. return true;
  105. }
  106. static void finish() { runtime->ret(); }
  107. void spawn(void (*func)()) {
  108. auto avail =
  109. std::find_if(threads.begin(), threads.end(), [](Thread const& th) {
  110. return th.state == ThreadState::Available;
  111. });
  112. if (avail == threads.end()) {
  113. fputs("Cannot spawn task. No available threads.\n", stderr);
  114. exit(2);
  115. }
  116. void (*guard)() = Runtime::finish;
  117. memcpy((unsigned char*) avail->stack + STACK_SIZE - 8, &guard, 8);
  118. memcpy((unsigned char*) avail->stack + STACK_SIZE - 16, &func, 8);
  119. avail->ctx.rsp =
  120. (uint64_t)((unsigned char*) avail->stack + STACK_SIZE - 16);
  121. avail->state = ThreadState::Ready;
  122. }
  123. };
  124.  
  125. static void thread1() {
  126. puts("thread 1 started");
  127. for (int i = 0; i < 10; ++i) {
  128. printf("thread 1 counting %d\n", i);
  129. runtime->yield();
  130. }
  131. }
  132.  
  133. static void thread2() {
  134. puts("thread 2 started");
  135. for (int i = 0; i < 10; ++i) {
  136. printf("thread 2 counting %d\n", i);
  137. runtime->yield();
  138. }
  139. }
  140.  
  141. int main() {
  142. Runtime().init();
  143. runtime->spawn(thread1);
  144. runtime->spawn(thread2);
  145. runtime->run();
  146. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement