SHARE
TWEET

Untitled

a guest Jun 24th, 2019 62 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top