EventLoop.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #ifndef HV_EVENT_LOOP_HPP_
  2. #define HV_EVENT_LOOP_HPP_
  3. #include <functional>
  4. #include <queue>
  5. #include <map>
  6. #include <mutex>
  7. #include "hloop.h"
  8. #include "hthread.h"
  9. #include "Status.h"
  10. #include "Event.h"
  11. namespace hv {
  12. class EventLoop : public Status {
  13. public:
  14. typedef std::function<void()> Functor;
  15. // New an EventLoop using an existing hloop_t object,
  16. // so we can embed an EventLoop object into the old application based on hloop.
  17. // NOTE: Be careful to deal with destroy of hloop_t.
  18. EventLoop(hloop_t* loop = NULL) {
  19. setStatus(kInitializing);
  20. if (loop) {
  21. loop_ = loop;
  22. } else {
  23. loop_ = hloop_new(HLOOP_FLAG_AUTO_FREE);
  24. }
  25. setStatus(kInitialized);
  26. }
  27. ~EventLoop() {
  28. stop();
  29. }
  30. hloop_t* loop() {
  31. return loop_;
  32. }
  33. // @brief Run loop forever
  34. void run() {
  35. if (loop_ == NULL) return;
  36. setStatus(kRunning);
  37. hloop_run(loop_);
  38. setStatus(kStopped);
  39. }
  40. void stop() {
  41. if (loop_ == NULL) return;
  42. setStatus(kStopping);
  43. hloop_stop(loop_);
  44. loop_ = NULL;
  45. }
  46. void pause() {
  47. if (loop_ == NULL) return;
  48. if (isRunning()) {
  49. hloop_pause(loop_);
  50. setStatus(kPause);
  51. }
  52. }
  53. void resume() {
  54. if (loop_ == NULL) return;
  55. if (isPause()) {
  56. hloop_resume(loop_);
  57. setStatus(kRunning);
  58. }
  59. }
  60. // Timer interfaces: setTimer, killTimer, resetTimer
  61. TimerID setTimer(int timeout_ms, TimerCallback cb, int repeat = INFINITE) {
  62. htimer_t* htimer = htimer_add(loop_, onTimer, timeout_ms, repeat);
  63. Timer timer(htimer, cb, repeat);
  64. hevent_set_userdata(htimer, this);
  65. TimerID timerID = hevent_id(htimer);
  66. mutex_.lock();
  67. timers[timerID] = timer;
  68. mutex_.unlock();
  69. return timerID;
  70. }
  71. // alias javascript setTimeout, setInterval
  72. TimerID setTimeout(int timeout_ms, TimerCallback cb) {
  73. return setTimer(timeout_ms, cb, 1);
  74. }
  75. TimerID setInterval(int interval_ms, TimerCallback cb) {
  76. return setTimer(interval_ms, cb, INFINITE);
  77. }
  78. void killTimer(TimerID timerID) {
  79. std::lock_guard<std::mutex> locker(mutex_);
  80. auto iter = timers.find(timerID);
  81. if (iter != timers.end()) {
  82. Timer& timer = iter->second;
  83. htimer_del(timer.timer);
  84. timers.erase(iter);
  85. }
  86. }
  87. void resetTimer(TimerID timerID) {
  88. std::lock_guard<std::mutex> locker(mutex_);
  89. auto iter = timers.find(timerID);
  90. if (iter != timers.end()) {
  91. Timer& timer = iter->second;
  92. htimer_reset(timer.timer);
  93. if (timer.repeat == 0) {
  94. timer.repeat = 1;
  95. }
  96. }
  97. }
  98. long tid() {
  99. if (loop_ == NULL) hv_gettid();
  100. return hloop_tid(loop_);
  101. }
  102. bool isInLoopThread() {
  103. return hv_gettid() == hloop_tid(loop_);
  104. }
  105. void assertInLoopThread() {
  106. assert(isInLoopThread());
  107. }
  108. void runInLoop(Functor fn) {
  109. if (isInLoopThread()) {
  110. if (fn) fn();
  111. } else {
  112. queueInLoop(fn);
  113. }
  114. }
  115. void queueInLoop(Functor fn) {
  116. postEvent([fn](Event* ev) {
  117. if (fn) fn();
  118. });
  119. }
  120. void postEvent(EventCallback cb) {
  121. if (loop_ == NULL) return;
  122. EventPtr ev(new Event(cb));
  123. hevent_set_userdata(&ev->event, this);
  124. ev->event.cb = onCustomEvent;
  125. mutex_.lock();
  126. customEvents.push(ev);
  127. mutex_.unlock();
  128. hloop_post_event(loop_, &ev->event);
  129. }
  130. private:
  131. static void onTimer(htimer_t* htimer) {
  132. EventLoop* loop = (EventLoop*)hevent_userdata(htimer);
  133. TimerID timerID = hevent_id(htimer);
  134. TimerCallback cb = NULL;
  135. loop->mutex_.lock();
  136. auto iter = loop->timers.find(timerID);
  137. if (iter != loop->timers.end()) {
  138. Timer& timer = iter->second;
  139. cb = timer.cb;
  140. --timer.repeat;
  141. }
  142. loop->mutex_.unlock();
  143. if (cb) cb(timerID);
  144. // NOTE: refind iterator, because iterator may be invalid
  145. // if the timer-related interface is called in the callback function above.
  146. loop->mutex_.lock();
  147. iter = loop->timers.find(timerID);
  148. if (iter != loop->timers.end()) {
  149. Timer& timer = iter->second;
  150. if (timer.repeat == 0) {
  151. // htimer_t alloc and free by hloop, but timers[timerID] managed by EventLoop.
  152. loop->timers.erase(iter);
  153. }
  154. }
  155. loop->mutex_.unlock();
  156. }
  157. static void onCustomEvent(hevent_t* hev) {
  158. EventLoop* loop = (EventLoop*)hevent_userdata(hev);
  159. loop->mutex_.lock();
  160. EventPtr ev = loop->customEvents.front();
  161. loop->customEvents.pop();
  162. loop->mutex_.unlock();
  163. if (ev && ev->cb) ev->cb(ev.get());
  164. }
  165. private:
  166. hloop_t* loop_;
  167. std::mutex mutex_;
  168. std::queue<EventPtr> customEvents; // GUAREDE_BY(mutex_)
  169. std::map<TimerID, Timer> timers; // GUAREDE_BY(mutex_)
  170. };
  171. typedef std::shared_ptr<EventLoop> EventLoopPtr;
  172. }
  173. #endif // HV_EVENT_LOOP_HPP_