ThreadLoop.cpp 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #include "ThreadLoop.h"
  2. lifo_t ThreadLoop::procedure_cache = {0,};
  3. lifo_t ThreadLoop::cache_bases= {0,};
  4. #define PROCEDURE_CACHE_SEED 64
  5. ThreadLoop::ThreadLoop()
  6. {
  7. mpscq_init(&procedure_queue);
  8. procedure_notification = CreateSemaphore(0, 0, LONG_MAX, 0);
  9. kill_switch = CreateEvent(0, TRUE, FALSE, 0);
  10. }
  11. void ThreadLoop::RefillCache()
  12. {
  13. threadloop_node_t *cache_seed = (threadloop_node_t *)malloc(PROCEDURE_CACHE_SEED*sizeof(threadloop_node_t));
  14. if (cache_seed)
  15. {
  16. int i=PROCEDURE_CACHE_SEED;
  17. while (--i)
  18. {
  19. lifo_push(&procedure_cache, (queue_node_t *)&cache_seed[i]);
  20. }
  21. lifo_push(&cache_bases, (queue_node_t *)cache_seed);
  22. }
  23. else
  24. {
  25. Sleep(0); // yield and hope that someone else pops something off soon
  26. }
  27. }
  28. void ThreadLoop::Run()
  29. {
  30. HANDLE events[] = {kill_switch, procedure_notification};
  31. while (WaitForMultipleObjects(2, events, FALSE, INFINITE) == WAIT_OBJECT_0 + 1)
  32. {
  33. for (;;)
  34. {
  35. threadloop_node_t *apc = (threadloop_node_t *)mpscq_pop(&procedure_queue);
  36. if (apc == (threadloop_node_t *)1) /* special return value that indicates a busy list */
  37. {
  38. Sleep(0); // yield so that the thread that got pre-empted during push can finish
  39. }
  40. else
  41. {
  42. if (apc)
  43. {
  44. apc->func(apc->param1, apc->param2, apc->real_value);
  45. lifo_push(&procedure_cache, apc);
  46. }
  47. else
  48. {
  49. break;
  50. }
  51. }
  52. }
  53. }
  54. }
  55. threadloop_node_t *ThreadLoop::GetAPC()
  56. {
  57. threadloop_node_t *apc = 0;
  58. do
  59. {
  60. apc = (threadloop_node_t *)lifo_pop(&procedure_cache);
  61. if (!apc)
  62. RefillCache();
  63. } while (!apc);
  64. return apc;
  65. }
  66. void ThreadLoop::Schedule(threadloop_node_t *apc)
  67. {
  68. if (mpscq_push(&procedure_queue, apc) == 0)
  69. ReleaseSemaphore(procedure_notification, 1, 0);
  70. }
  71. void ThreadLoop::Kill()
  72. {
  73. SetEvent(kill_switch);
  74. }