MessageLoop.cpp 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #include "MessageLoop.h"
  2. #include <assert.h>
  3. lifo_t nu::MessageLoop::message_cache = {0,};
  4. lifo_t nu::MessageLoop::cache_bases= {0,};
  5. #define MESSAAGE_CACHE_SEED 64
  6. typedef uint8_t message_data_t[64]; // ensure all messages are this size
  7. nu::MessageLoop::MessageLoop()
  8. {
  9. mpscq_init(&message_queue);
  10. message_notification = CreateEvent(0, FALSE, FALSE, 0);
  11. }
  12. nu::MessageLoop::~MessageLoop()
  13. {
  14. CloseHandle(message_notification);
  15. }
  16. void nu::MessageLoop::RefillCache()
  17. {
  18. message_data_t *cache_seed = (message_data_t *)_aligned_malloc(MESSAAGE_CACHE_SEED*sizeof(message_data_t), 64);
  19. if (cache_seed)
  20. {
  21. int i=MESSAAGE_CACHE_SEED;
  22. while (--i)
  23. {
  24. lifo_push(&message_cache, (queue_node_t *)&cache_seed[i]);
  25. }
  26. lifo_push(&cache_bases, (queue_node_t *)cache_seed);
  27. }
  28. else
  29. {
  30. Sleep(0); // yield and hope that someone else pops something off soon
  31. }
  32. }
  33. nu::message_node_t *nu::MessageLoop::AllocateMessage()
  34. {
  35. message_node_t *apc = 0;
  36. do
  37. {
  38. apc = (message_node_t *)lifo_pop(&message_cache);
  39. if (!apc)
  40. RefillCache();
  41. } while (!apc);
  42. return apc;
  43. }
  44. void nu::MessageLoop::PostMessage(nu::message_node_t *message)
  45. {
  46. if (mpscq_push(&message_queue, message) == 0)
  47. SetEvent(message_notification);
  48. }
  49. void nu::MessageLoop::FreeMessage(nu::message_node_t *message)
  50. {
  51. lifo_push(&message_cache, message);
  52. }
  53. nu::message_node_t *nu::MessageLoop::GetMessage()
  54. {
  55. message_node_t *message = PeekMessage();
  56. if (message)
  57. {
  58. return message;
  59. }
  60. while (WaitForSingleObject(message_notification, INFINITE) == WAIT_OBJECT_0)
  61. {
  62. message = PeekMessage();
  63. if (message)
  64. {
  65. return message;
  66. }
  67. }
  68. return 0;
  69. }
  70. nu::message_node_t *nu::MessageLoop::PeekMessage()
  71. {
  72. for (;;) // loop because we need to handle 'busy' from the queue
  73. {
  74. message_node_t *message = (message_node_t *)mpscq_pop(&message_queue);
  75. if (message == (message_node_t *)1) /* special return value that indicates a busy list */
  76. {
  77. // benski> although it's tempting to return 0 here, doing so will mess up the Event logic
  78. Sleep(0); // yield so that the thread that got pre-empted during push can finish
  79. }
  80. else
  81. {
  82. if (message)
  83. {
  84. return message;
  85. }
  86. else
  87. {
  88. return 0;
  89. }
  90. }
  91. }
  92. }
  93. nu::message_node_t *nu::MessageLoop::PeekMessage(unsigned int milliseconds)
  94. {
  95. message_node_t *message = PeekMessage();
  96. if (message)
  97. return message;
  98. if (WaitForSingleObject(message_notification, milliseconds) == WAIT_OBJECT_0)
  99. {
  100. message = PeekMessage();
  101. if (message)
  102. return message;
  103. }
  104. return 0;
  105. }