condvar_unittest.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <exceptions/exceptions.h>
  15. #include <util/threads/lock.h>
  16. #include <util/threads/thread.h>
  17. #include <gtest/gtest.h>
  18. #include <boost/bind.hpp>
  19. #include <boost/scoped_ptr.hpp>
  20. #include <cstring>
  21. #include <unistd.h>
  22. #include <signal.h>
  23. using namespace isc::util::thread;
  24. namespace {
  25. // Used as a signal handler below.
  26. volatile bool do_exit; // use for emergency escape
  27. void
  28. alarmHandler(int) {
  29. do_exit = true;
  30. }
  31. class CondVarTest : public ::testing::Test {
  32. protected:
  33. // We use a signal in case some of the thread synchronization tests
  34. // unexpectedly cause a deadlock.
  35. void SetUp() {
  36. do_exit = false;
  37. std::memset(&handler_, 0, sizeof(handler_));
  38. handler_.sa_handler = alarmHandler;
  39. if (sigaction(SIGALRM, &handler_, &original_) != 0) {
  40. FAIL() << "Couldn't set alarm";
  41. }
  42. alarm(10); // 10sec duration: arbitrary choice
  43. }
  44. void TearDown() {
  45. // Cancel the alarm and return the original handler
  46. alarm(0);
  47. if (sigaction(SIGALRM, &original_, NULL)) {
  48. FAIL() << "Couldn't restore alarm";
  49. }
  50. }
  51. CondVar condvar_;
  52. Mutex mutex_;
  53. private:
  54. struct sigaction handler_, original_;
  55. };
  56. TEST(CondVarTest0, create) {
  57. // Just construct and destruct it. Nothing unusual should happen.
  58. EXPECT_NO_THROW(CondVar condvar);
  59. }
  60. // Running on a separate thread, just updating the argument and waking up
  61. // the other thread via the condition variable passed.
  62. void
  63. ringSignal(CondVar* condvar, Mutex* mutex, int* arg) {
  64. assert(*arg == 0);
  65. Mutex::Locker locker(*mutex);
  66. ++*arg;
  67. condvar->signal();
  68. }
  69. // A simple wait-signal operation on a condition variable.
  70. TEST_F(CondVarTest, waitAndSignal) {
  71. Mutex::Locker locker(mutex_);
  72. int shared_var = 0; // let the other thread increment this
  73. Thread t(boost::bind(&ringSignal, &condvar_, &mutex_, &shared_var));
  74. condvar_.wait(mutex_);
  75. t.wait();
  76. EXPECT_EQ(1, shared_var);
  77. }
  78. // Thread's main code for the next test
  79. void
  80. signalAndWait(CondVar* condvar1, CondVar* condvar2, Mutex* mutex, int* arg) {
  81. Mutex::Locker locker(*mutex);
  82. ++*arg;
  83. condvar2->signal(); // let the main thread know this one is ready
  84. condvar1->wait(*mutex);
  85. ++*arg;
  86. }
  87. // Similar to the previous test, but having two threads wait for a condvar.
  88. TEST_F(CondVarTest, multiWaits) {
  89. boost::scoped_ptr<Mutex::Locker> locker(new Mutex::Locker(mutex_));
  90. CondVar condvar2; // separate cond var for initial synchronization
  91. int shared_var = 0; // let the other thread increment this
  92. Thread t1(boost::bind(&signalAndWait, &condvar_, &condvar2, &mutex_,
  93. &shared_var));
  94. Thread t2(boost::bind(&signalAndWait, &condvar_, &condvar2, &mutex_,
  95. &shared_var));
  96. // Wait until both threads are waiting on condvar_.
  97. while (shared_var < 2 && !do_exit) {
  98. condvar2.wait(mutex_);
  99. }
  100. // Check we exited from the loop successfully.
  101. ASSERT_FALSE(do_exit);
  102. ASSERT_EQ(2, shared_var);
  103. // release the lock, wake up both threads, wait for them to die, and
  104. // confirm they successfully woke up.
  105. locker.reset();
  106. condvar_.signal();
  107. condvar_.signal();
  108. t1.wait();
  109. t2.wait();
  110. EXPECT_EQ(4, shared_var);
  111. }
  112. void
  113. waiter(CondVar* condver, Mutex* mutex) {
  114. Mutex::Locker locker(*mutex);
  115. condver->wait(*mutex);
  116. }
  117. // Similar to the previous version of the same function, but just do
  118. // condvar operations. It will never wake up.
  119. void
  120. signalAndWait(CondVar* condvar, Mutex* mutex) {
  121. Mutex::Locker locker(*mutex);
  122. condvar->signal();
  123. condvar->wait(*mutex);
  124. }
  125. #ifdef EXPECT_DEATH
  126. TEST_F(CondVarTest, bad) {
  127. // We'll destroy a CondVar object while the thread is still waiting
  128. // on it. This will trigger an assertion failure.
  129. EXPECT_DEATH({
  130. CondVar cond;
  131. Mutex::Locker locker(mutex_);
  132. Thread t(boost::bind(&signalAndWait, &cond, &mutex_));
  133. cond.wait(mutex_);
  134. }, "");
  135. }
  136. #endif
  137. TEST_F(CondVarTest, badWait) {
  138. // In our implementation, wait() requires acquiring the lock beforehand.
  139. EXPECT_THROW(condvar_.wait(mutex_), isc::InvalidOperation);
  140. }
  141. TEST_F(CondVarTest, emptySignal) {
  142. // It's okay to call signal when no one waits.
  143. EXPECT_NO_THROW(condvar_.signal());
  144. }
  145. }