tb_msg.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. // ================================================================================
  2. // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås ==
  3. // == See tb_core.h for more information. ==
  4. // ================================================================================
  5. #include "tb_msg.h"
  6. #include "tb_system.h"
  7. #include <stddef.h>
  8. namespace tb {
  9. /** List of all delayed messages */
  10. TBLinkListOf<TBMessageLink> g_all_delayed_messages;
  11. /** List of all nondelayed messages. */
  12. TBLinkListOf<TBMessageLink> g_all_normal_messages;
  13. // == TBMessage =========================================================================
  14. TBMessage::TBMessage(TBID message, TBMessageData *data, double fire_time_ms, TBMessageHandler *mh)
  15. : message(message), data(data), fire_time_ms(fire_time_ms), mh(mh)
  16. {
  17. }
  18. TBMessage::~TBMessage()
  19. {
  20. delete data;
  21. }
  22. // == TBMessageHandler ==================================================================
  23. TBMessageHandler::TBMessageHandler()
  24. {
  25. }
  26. TBMessageHandler::~TBMessageHandler()
  27. {
  28. DeleteAllMessages();
  29. }
  30. bool TBMessageHandler::PostMessageDelayed(TBID message, TBMessageData *data, uint32 delay_in_ms)
  31. {
  32. return PostMessageOnTime(message, data, TBSystem::GetTimeMS() + (double)delay_in_ms);
  33. }
  34. bool TBMessageHandler::PostMessageOnTime(TBID message, TBMessageData *data, double fire_time)
  35. {
  36. if (TBMessage *msg = new TBMessage(message, data, fire_time, this))
  37. {
  38. // Find the message that is already in the list that should fire later, so we can
  39. // insert msg just before that. (Always keep the list ordered after fire time)
  40. // NOTE: If another message is added during OnMessageReceived, it might or might not be fired
  41. // in the right order compared to other delayed messages, depending on if it's inserted before or
  42. // after the message being processed!
  43. TBMessage *later_msg = nullptr;
  44. TBMessageLink *link = g_all_delayed_messages.GetFirst();
  45. while (link)
  46. {
  47. TBMessage *msg_in_list = static_cast<TBMessage*>(link);
  48. if (msg_in_list->fire_time_ms > msg->fire_time_ms)
  49. {
  50. later_msg = msg_in_list;
  51. break;
  52. }
  53. link = link->GetNext();
  54. }
  55. // Add it to the global list in the right order.
  56. if (later_msg)
  57. g_all_delayed_messages.AddBefore(msg, later_msg);
  58. else
  59. g_all_delayed_messages.AddLast(msg);
  60. // Add it to the list in messagehandler.
  61. m_messages.AddLast(msg);
  62. // If we added it first and there's no normal messages, the next fire time has
  63. // changed and we have to reschedule the timer.
  64. if (!g_all_normal_messages.GetFirst() && g_all_delayed_messages.GetFirst() == msg)
  65. TBSystem::RescheduleTimer(msg->fire_time_ms);
  66. return true;
  67. }
  68. return false;
  69. }
  70. bool TBMessageHandler::PostMessage(TBID message, TBMessageData *data)
  71. {
  72. if (TBMessage *msg = new TBMessage(message, data, 0, this))
  73. {
  74. g_all_normal_messages.AddLast(msg);
  75. m_messages.AddLast(msg);
  76. // If we added it and there was no messages, the next fire time has
  77. // changed and we have to rescedule the timer.
  78. if (g_all_normal_messages.GetFirst() == msg)
  79. TBSystem::RescheduleTimer(0);
  80. return true;
  81. }
  82. return false;
  83. }
  84. TBMessage *TBMessageHandler::GetMessageByID(TBID message)
  85. {
  86. TBLinkListOf<TBMessage>::Iterator iter = m_messages.IterateForward();
  87. while (TBMessage *msg = iter.GetAndStep())
  88. if (msg->message == message)
  89. return msg;
  90. return nullptr;
  91. }
  92. void TBMessageHandler::DeleteMessage(TBMessage *msg)
  93. {
  94. assert(msg->mh == this); // This is not the message handler owning the message!
  95. // Remove from global list (g_all_delayed_messages or g_all_normal_messages)
  96. if (g_all_delayed_messages.ContainsLink(msg))
  97. g_all_delayed_messages.Remove(msg);
  98. else if (g_all_normal_messages.ContainsLink(msg))
  99. g_all_normal_messages.Remove(msg);
  100. // Remove from local list
  101. m_messages.Remove(msg);
  102. delete msg;
  103. // Note: We could call TBSystem::RescheduleTimer if we think that deleting
  104. // this message changed the time for the next message.
  105. }
  106. void TBMessageHandler::DeleteAllMessages()
  107. {
  108. while (TBMessage *msg = m_messages.GetFirst())
  109. DeleteMessage(msg);
  110. }
  111. //static
  112. void TBMessageHandler::ProcessMessages()
  113. {
  114. // Handle delayed messages
  115. TBLinkListOf<TBMessageLink>::Iterator iter = g_all_delayed_messages.IterateForward();
  116. while (TBMessage *msg = static_cast<TBMessage*>(iter.GetAndStep()))
  117. {
  118. if (TBSystem::GetTimeMS() >= msg->fire_time_ms)
  119. {
  120. // Remove from global list
  121. g_all_delayed_messages.Remove(msg);
  122. // Remove from local list
  123. msg->mh->m_messages.Remove(msg);
  124. msg->mh->OnMessageReceived(msg);
  125. delete msg;
  126. }
  127. else
  128. break; // Since the list is sorted, all remaining messages should fire later
  129. }
  130. // Handle normal messages
  131. iter = g_all_normal_messages.IterateForward();
  132. while (TBMessage *msg = static_cast<TBMessage*>(iter.GetAndStep()))
  133. {
  134. // Remove from global list
  135. g_all_normal_messages.Remove(msg);
  136. // Remove from local list
  137. msg->mh->m_messages.Remove(msg);
  138. msg->mh->OnMessageReceived(msg);
  139. delete msg;
  140. }
  141. }
  142. //static
  143. double TBMessageHandler::GetNextMessageFireTime()
  144. {
  145. if (g_all_normal_messages.GetFirst())
  146. return 0;
  147. if (g_all_delayed_messages.GetFirst())
  148. {
  149. TBMessage *first_delayed_msg = static_cast<TBMessage*>(g_all_delayed_messages.GetFirst());
  150. return first_delayed_msg->fire_time_ms;
  151. }
  152. return TB_NOT_SOON;
  153. }
  154. }; // namespace tb