bthread_timer_thread_unittest.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // Licensed to the Apache Software Foundation (ASF) under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. The ASF licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing,
  12. // software distributed under the License is distributed on an
  13. // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. // KIND, either express or implied. See the License for the
  15. // specific language governing permissions and limitations
  16. // under the License.
  17. #include <gtest/gtest.h>
  18. #include <gflags/gflags.h>
  19. #include "bthread/sys_futex.h"
  20. #include "bthread/timer_thread.h"
  21. #include "bthread/bthread.h"
  22. #include "butil/logging.h"
  23. namespace {
  24. long timespec_diff_us(const timespec& ts1, const timespec& ts2) {
  25. return (ts1.tv_sec - ts2.tv_sec) * 1000000L +
  26. (ts1.tv_nsec - ts2.tv_nsec) / 1000;
  27. }
  28. // A simple class, could keep track of the time when it is invoked.
  29. class TimeKeeper {
  30. public:
  31. TimeKeeper(timespec run_time)
  32. : _expect_run_time(run_time), _name(NULL), _sleep_ms(0) {}
  33. TimeKeeper(timespec run_time, const char* name/*must be string constant*/)
  34. : _expect_run_time(run_time), _name(name), _sleep_ms(0) {}
  35. TimeKeeper(timespec run_time, const char* name/*must be string constant*/,
  36. int sleep_ms)
  37. : _expect_run_time(run_time), _name(name), _sleep_ms(sleep_ms) {}
  38. void schedule(bthread::TimerThread* timer_thread) {
  39. _task_id = timer_thread->schedule(
  40. TimeKeeper::routine, this, _expect_run_time);
  41. }
  42. void run()
  43. {
  44. timespec current_time;
  45. clock_gettime(CLOCK_REALTIME, &current_time);
  46. if (_name) {
  47. LOG(INFO) << "Run `" << _name << "' task_id=" << _task_id;
  48. } else {
  49. LOG(INFO) << "Run task_id=" << _task_id;
  50. }
  51. _run_times.push_back(current_time);
  52. const int saved_sleep_ms = _sleep_ms;
  53. if (saved_sleep_ms > 0) {
  54. timespec timeout = butil::milliseconds_to_timespec(saved_sleep_ms);
  55. bthread::futex_wait_private(&_sleep_ms, saved_sleep_ms, &timeout);
  56. }
  57. }
  58. void wakeup() {
  59. if (_sleep_ms != 0) {
  60. _sleep_ms = 0;
  61. bthread::futex_wake_private(&_sleep_ms, 1);
  62. } else {
  63. LOG(ERROR) << "No need to wakeup "
  64. << (_name ? _name : "") << " task_id=" << _task_id;
  65. }
  66. }
  67. // verify the first run is in specified time range.
  68. void expect_first_run()
  69. {
  70. expect_first_run(_expect_run_time);
  71. }
  72. void expect_first_run(timespec expect_run_time)
  73. {
  74. ASSERT_TRUE(!_run_times.empty());
  75. long diff = timespec_diff_us(_run_times[0], expect_run_time);
  76. EXPECT_LE(labs(diff), 50000);
  77. }
  78. void expect_not_run() {
  79. EXPECT_TRUE(_run_times.empty());
  80. }
  81. static void routine(void *arg)
  82. {
  83. TimeKeeper* keeper = (TimeKeeper*)arg;
  84. keeper->run();
  85. }
  86. timespec _expect_run_time;
  87. bthread::TimerThread::TaskId _task_id;
  88. private:
  89. const char* _name;
  90. int _sleep_ms;
  91. std::vector<timespec> _run_times;
  92. };
  93. TEST(TimerThreadTest, RunTasks) {
  94. bthread::TimerThread timer_thread;
  95. ASSERT_EQ(0, timer_thread.start(NULL));
  96. timespec _2s_later = butil::seconds_from_now(2);
  97. TimeKeeper keeper1(_2s_later, "keeper1");
  98. keeper1.schedule(&timer_thread);
  99. TimeKeeper keeper2(_2s_later, "keeper2"); // same time with keeper1
  100. keeper2.schedule(&timer_thread);
  101. timespec _1s_later = butil::seconds_from_now(1);
  102. TimeKeeper keeper3(_1s_later, "keeper3");
  103. keeper3.schedule(&timer_thread);
  104. timespec _10s_later = butil::seconds_from_now(10);
  105. TimeKeeper keeper4(_10s_later, "keeper4");
  106. keeper4.schedule(&timer_thread);
  107. TimeKeeper keeper5(_10s_later, "keeper5");
  108. keeper5.schedule(&timer_thread);
  109. // sleep 1 second, and unschedule task2
  110. LOG(INFO) << "Sleep 1s";
  111. sleep(1);
  112. timer_thread.unschedule(keeper2._task_id);
  113. timer_thread.unschedule(keeper4._task_id);
  114. timespec old_time = { 0, 0 };
  115. TimeKeeper keeper6(old_time, "keeper6");
  116. keeper6.schedule(&timer_thread);
  117. const timespec keeper6_addtime = butil::seconds_from_now(0);
  118. // sleep 10 seconds and stop.
  119. LOG(INFO) << "Sleep 2s";
  120. sleep(2);
  121. LOG(INFO) << "Stop timer_thread";
  122. butil::Timer tm;
  123. tm.start();
  124. timer_thread.stop_and_join();
  125. tm.stop();
  126. ASSERT_LE(tm.m_elapsed(), 15);
  127. // verify all runs in expected time range.
  128. keeper1.expect_first_run();
  129. keeper2.expect_not_run();
  130. keeper3.expect_first_run();
  131. keeper4.expect_not_run();
  132. keeper5.expect_not_run();
  133. keeper6.expect_first_run(keeper6_addtime);
  134. }
  135. // If the scheduled time is before start time, then should run it
  136. // immediately.
  137. TEST(TimerThreadTest, start_after_schedule) {
  138. bthread::TimerThread timer_thread;
  139. timespec past_time = { 0, 0 };
  140. TimeKeeper keeper(past_time, "keeper1");
  141. keeper.schedule(&timer_thread);
  142. ASSERT_EQ(bthread::TimerThread::INVALID_TASK_ID, keeper._task_id);
  143. ASSERT_EQ(0, timer_thread.start(NULL));
  144. keeper.schedule(&timer_thread);
  145. ASSERT_NE(bthread::TimerThread::INVALID_TASK_ID, keeper._task_id);
  146. timespec current_time = butil::seconds_from_now(0);
  147. sleep(1); // make sure timer thread start and run
  148. timer_thread.stop_and_join();
  149. keeper.expect_first_run(current_time);
  150. }
  151. class TestTask {
  152. public:
  153. TestTask(bthread::TimerThread* timer_thread, TimeKeeper* keeper1,
  154. TimeKeeper* keeper2, int expected_unschedule_result)
  155. : _timer_thread(timer_thread)
  156. , _keeper1(keeper1)
  157. , _keeper2(keeper2)
  158. , _expected_unschedule_result(expected_unschedule_result) {
  159. }
  160. void run()
  161. {
  162. clock_gettime(CLOCK_REALTIME, &_running_time);
  163. EXPECT_EQ(_expected_unschedule_result,
  164. _timer_thread->unschedule(_keeper1->_task_id));
  165. _keeper2->schedule(_timer_thread);
  166. }
  167. static void routine(void* arg)
  168. {
  169. TestTask* task = (TestTask*)arg;
  170. task->run();
  171. }
  172. timespec _running_time;
  173. private:
  174. bthread::TimerThread* _timer_thread; // not owned.
  175. TimeKeeper* _keeper1; // not owned.
  176. TimeKeeper* _keeper2; // not owned.
  177. int _expected_unschedule_result;
  178. };
  179. // Perform schedule and unschedule inside a running task
  180. TEST(TimerThreadTest, schedule_and_unschedule_in_task) {
  181. bthread::TimerThread timer_thread;
  182. timespec past_time = { 0, 0 };
  183. timespec future_time = { std::numeric_limits<int>::max(), 0 };
  184. const timespec _500ms_after = butil::milliseconds_from_now(500);
  185. TimeKeeper keeper1(future_time, "keeper1");
  186. TimeKeeper keeper2(past_time, "keeper2");
  187. TimeKeeper keeper3(past_time, "keeper3");
  188. TimeKeeper keeper4(past_time, "keeper4");
  189. TimeKeeper keeper5(_500ms_after, "keeper5", 10000/*10s*/);
  190. ASSERT_EQ(0, timer_thread.start(NULL));
  191. keeper1.schedule(&timer_thread); // start keeper1
  192. keeper3.schedule(&timer_thread); // start keeper3
  193. timespec keeper3_addtime = butil::seconds_from_now(0);
  194. keeper5.schedule(&timer_thread); // start keeper5
  195. sleep(1); // let keeper1/3/5 run
  196. TestTask test_task1(&timer_thread, &keeper1, &keeper2, 0);
  197. timer_thread.schedule(TestTask::routine, &test_task1, past_time);
  198. TestTask test_task2(&timer_thread, &keeper3, &keeper4, -1);
  199. timer_thread.schedule(TestTask::routine, &test_task2, past_time);
  200. sleep(1);
  201. // test_task1/2 should be both blocked by keeper5.
  202. keeper2.expect_not_run();
  203. keeper4.expect_not_run();
  204. // unscheduling (running) keeper5 should have no effect and returns 1
  205. ASSERT_EQ(1, timer_thread.unschedule(keeper5._task_id));
  206. // wake up keeper5 to let test_task1/2 run.
  207. keeper5.wakeup();
  208. sleep(1);
  209. timer_thread.stop_and_join();
  210. timespec finish_time;
  211. clock_gettime(CLOCK_REALTIME, &finish_time);
  212. keeper1.expect_not_run();
  213. keeper2.expect_first_run(test_task1._running_time);
  214. keeper3.expect_first_run(keeper3_addtime);
  215. keeper4.expect_first_run(test_task2._running_time);
  216. keeper5.expect_first_run();
  217. }
  218. } // end namespace