ThreadLoop.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #include "ThreadLoop.h"
  2. #include <limits.h>
  3. lifo_t ThreadLoop::procedure_cache = {0,};
  4. lifo_t ThreadLoop::cache_bases= {0,};
  5. #define PROCEDURE_CACHE_SEED 64
  6. ThreadLoop::ThreadLoop()
  7. {
  8. mpscq_init(&procedure_queue);
  9. procedure_notification = CreateSemaphoreW(0, 0, LONG_MAX, 0);
  10. kill_switch = CreateEvent(0, TRUE, FALSE, 0);
  11. }
  12. ThreadLoop::~ThreadLoop()
  13. {
  14. CloseHandle(procedure_notification);
  15. CloseHandle(kill_switch);
  16. }
  17. void ThreadLoop::RefillCache()
  18. {
  19. threadloop_node_t *cache_seed = (threadloop_node_t *)malloc(PROCEDURE_CACHE_SEED*sizeof(threadloop_node_t));
  20. if (cache_seed)
  21. {
  22. int i=PROCEDURE_CACHE_SEED;
  23. while (--i)
  24. {
  25. lifo_push(&procedure_cache, (queue_node_t *)&cache_seed[i]);
  26. }
  27. lifo_push(&cache_bases, (queue_node_t *)cache_seed);
  28. }
  29. else
  30. {
  31. Sleep(0); // yield and hope that someone else pops something off soon
  32. }
  33. }
  34. void ThreadLoop::Run()
  35. {
  36. HANDLE events[] = {kill_switch, procedure_notification};
  37. while (WaitForMultipleObjects(2, events, FALSE, INFINITE) == WAIT_OBJECT_0 + 1)
  38. {
  39. for (;;)
  40. {
  41. threadloop_node_t *apc = (threadloop_node_t *)mpscq_pop(&procedure_queue);
  42. if (apc == (threadloop_node_t *)1) /* special return value that indicates a busy list */
  43. {
  44. Sleep(0); // yield so that the thread that got pre-empted during push can finish
  45. }
  46. else
  47. {
  48. if (apc)
  49. {
  50. apc->func(apc->param1, apc->param2, apc->real_value);
  51. lifo_push(&procedure_cache, apc);
  52. }
  53. else
  54. {
  55. break;
  56. }
  57. }
  58. }
  59. }
  60. }
  61. void ThreadLoop::Step(unsigned int milliseconds)
  62. {
  63. HANDLE events[] = {kill_switch, procedure_notification};
  64. if (WaitForMultipleObjects(2, events, FALSE, milliseconds) == WAIT_OBJECT_0 + 1)
  65. {
  66. for (;;)
  67. {
  68. threadloop_node_t *apc = (threadloop_node_t *)mpscq_pop(&procedure_queue);
  69. if (apc == (threadloop_node_t *)1) /* special return value that indicates a busy list */
  70. {
  71. Sleep(0); // yield so that the thread that got pre-empted during push can finish
  72. }
  73. else
  74. {
  75. if (apc)
  76. {
  77. apc->func(apc->param1, apc->param2, apc->real_value);
  78. lifo_push(&procedure_cache, apc);
  79. }
  80. else
  81. {
  82. break;
  83. }
  84. }
  85. }
  86. }
  87. }
  88. void ThreadLoop::Step()
  89. {
  90. HANDLE events[] = {kill_switch, procedure_notification};
  91. if (WaitForMultipleObjects(2, events, FALSE, INFINITE) == WAIT_OBJECT_0 + 1)
  92. {
  93. for (;;)
  94. {
  95. threadloop_node_t *apc = (threadloop_node_t *)mpscq_pop(&procedure_queue);
  96. if (apc == (threadloop_node_t *)1) /* special return value that indicates a busy list */
  97. {
  98. Sleep(0); // yield so that the thread that got pre-empted during push can finish
  99. }
  100. else
  101. {
  102. if (apc)
  103. {
  104. apc->func(apc->param1, apc->param2, apc->real_value);
  105. lifo_push(&procedure_cache, apc);
  106. }
  107. else
  108. {
  109. break;
  110. }
  111. }
  112. }
  113. }
  114. }
  115. threadloop_node_t *ThreadLoop::GetAPC()
  116. {
  117. threadloop_node_t *apc = 0;
  118. do
  119. {
  120. apc = (threadloop_node_t *)lifo_pop(&procedure_cache);
  121. if (!apc)
  122. RefillCache();
  123. } while (!apc);
  124. return apc;
  125. }
  126. void ThreadLoop::Schedule(threadloop_node_t *apc)
  127. {
  128. if (mpscq_push(&procedure_queue, apc) == 0)
  129. ReleaseSemaphore(procedure_notification, 1, 0);
  130. }
  131. void ThreadLoop::Kill()
  132. {
  133. SetEvent(kill_switch);
  134. }