Advertisement
Guest User

Untitled

a guest
Feb 4th, 2013
56
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.21 KB | None | 0 0
  1. #include <Windows.h>
  2. #include <assert.h>
  3. #include <stdio.h>
  4.  
  5. // Since we're not really switching contexts, we only actually need to save
  6. // the call saved registers!
  7. struct SavedContextFrame
  8. {
  9.   void *r15;
  10.   void *r14;
  11.   void *r13;
  12.   void *r12;
  13.   void *rdi;
  14.   void *rsi;
  15.   void *rbp;
  16.   void *rbx;
  17.   void (*rip)();
  18. };
  19.  
  20. // This has a few extra entries at the bottom of
  21. // the stack to handle a thread returning
  22. struct NewFrame
  23. {
  24.   SavedContextFrame context;
  25.  
  26.   void *threadexit;
  27.   void *zero;
  28. };
  29.  
  30. struct Task
  31. {
  32.   // rsp at beginning of structure for convenience from asm
  33.   SavedContextFrame *rsp;
  34.  
  35.   enum State
  36.   {
  37.     INVALID,
  38.     ROOT,
  39.     CREATED,
  40.     EXITED,
  41.   };
  42.   State state;
  43.  
  44.   void *stack;
  45.   size_t stacksize;
  46.  
  47.   Task *next, *prev;
  48.  
  49.   Task()
  50.     : rsp(0)
  51.     , state(INVALID)
  52.     , stack(0)
  53.   {
  54.     next = prev = this;
  55.   }
  56. };
  57.  
  58. // Circular lists to track runnable and waiting tasks
  59. static Task root_runnable;
  60. static Task root_waiting;
  61. static Task *task = &root_runnable;
  62. extern "C" Task *current_task;
  63.  
  64. Task *current_task;
  65.  
  66. extern "C" void TaskBootup(void *rsp);
  67. extern "C" void SwitchToTask(void *rsp, void **old_task_rsp);
  68. extern "C" void SwitchToNextTask();
  69. extern "C" void StartNewTask();
  70.  
  71. extern "C" SavedContextFrame *ScheduleTask(SavedContextFrame *rsp)
  72. {
  73.   // Save outgoing task's frame
  74.   current_task->rsp = rsp;
  75.  
  76.   // See if outgoing task needs self destruct
  77.   if (current_task->state == Task::EXITED)
  78.   {
  79.     // Capture node being deleted
  80.     auto *tmp = current_task;
  81.  
  82.     // Advance to next
  83.     current_task = current_task->next;
  84.  
  85.     // Unlink
  86.     tmp->next->prev = tmp->prev;
  87.     tmp->prev->next = tmp->next;
  88.  
  89.     // Wipe dangling pointers
  90.     tmp->next = 0;
  91.     tmp->prev = 0;
  92.  
  93.     // Free memory
  94.     delete tmp;
  95.   }
  96.  
  97.   for ( ; root_runnable.next != root_runnable.prev; )
  98.   {
  99.     // Go to next task
  100.     current_task = current_task->next;
  101.  
  102.     // Skip over first node
  103.     if (current_task == &root_runnable)
  104.       continue;
  105.  
  106.     return current_task->rsp;
  107.   }
  108.  
  109.   // No more tasks to run, switch back to root task
  110.   current_task = &root_runnable;
  111.  
  112.   assert(current_task->rsp != 0);
  113.  
  114.   return current_task->rsp;
  115. }
  116.  
  117. static void task_exit(void *a1, void *a2, void *a3, void *a4)
  118. {
  119.   current_task->state = Task::EXITED;
  120.   SwitchToNextTask();
  121. }
  122.  
  123. void test_thread(void *a1, void *a2, void *a3, void *a4)
  124. {
  125.   for (auto i = 0; i < 4; ++i)
  126.   {
  127.     printf("0x%p 0x%p 0x%p 0x%p\n", a1, a2, a3, a4);
  128.     SwitchToNextTask();
  129.   }
  130.   printf("0x%p 0x%p 0x%p 0x%p - done\n", a1, a2, a3, a4);
  131. }
  132.  
  133. void CreateTask(void (*f)(void*,void*,void*,void*),
  134.   void *a0, void *a1, void *a2, void *a3)
  135. {
  136.   Task *task = new Task;
  137.  
  138.   // Allocate a new stack and put the context at the end of it
  139.   task->stacksize = 1<<20;
  140.   task->stack = malloc(task->stacksize);
  141.  
  142.   auto frame = (NewFrame*)((char*)task->stack + task->stacksize) - 1;
  143.   memset(frame, 0, sizeof(*frame));
  144.  
  145.   frame->context.rip = StartNewTask;
  146.   frame->threadexit = task_exit;
  147.   frame->zero = 0;
  148.  
  149.   // When we're creating a new task, we own all the registers
  150.   // in the frame, so we put all the information into those
  151.   // and make it start at a task creation thunk
  152.  
  153.   frame->context.rbx = task;
  154.   frame->context.rbp = f;
  155.   frame->context.r12 = a0;
  156.   frame->context.r13 = a1;
  157.   frame->context.r14 = a2;
  158.   frame->context.r15 = a3;
  159.  
  160.   task->rsp = &frame->context;
  161.  
  162.   // Link into start of circular list
  163.   task->prev = root_runnable.prev;
  164.   task->next = &root_runnable;
  165.   task->prev->next = task;
  166.   task->next->prev = task;
  167.  
  168.   task->state = Task::CREATED;
  169.  
  170.   if (current_task)
  171.     return;
  172.  
  173.   // We only reach here first time
  174.   current_task = &root_runnable;
  175.   current_task->state = Task::ROOT;
  176.  
  177.   current_task = &root_runnable;
  178. }
  179.  
  180. class FiberGroup
  181. {
  182. };
  183.  
  184. int main()
  185. {
  186.   void *tasks[16];
  187.  
  188.   for (auto i = (char *)0; i < (char *)8; ++i)
  189.     tasks[i] = CreateFiber(0, test_fiber, 0);
  190.  
  191.   ConvertThreadToFiber(0);
  192.   SwitchToFiber(tasks[0]);
  193.  
  194.   for (auto i = (char *)0; i < (char *)8; ++i)
  195.     CreateTask(test_thread, i + 1, i + 2, i + 3, i + 4);
  196.  
  197.   while (root_runnable.next != root_runnable.prev)
  198.     SwitchToNextTask();
  199.  
  200.   printf("Root done\n");
  201.  
  202.   return 0;
  203. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement