thread.cc 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <util/threads/thread.h>
  8. #include <util/threads/sync.h>
  9. #include <memory>
  10. #include <string>
  11. #include <cstring>
  12. #include <cerrno>
  13. #include <pthread.h>
  14. #include <signal.h>
  15. #include <boost/noncopyable.hpp>
  16. #include <boost/scoped_ptr.hpp>
  17. using std::string;
  18. using std::exception;
  19. using std::unique_ptr;
  20. using boost::scoped_ptr;
  21. namespace isc {
  22. namespace util {
  23. namespace thread {
  24. namespace {
  25. // Signal blocker class.
  26. class Blocker : boost::noncopyable {
  27. public:
  28. // Constructor blocks all signals
  29. Blocker() {
  30. sigset_t new_mask;
  31. sigfillset(&new_mask);
  32. pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_);
  33. }
  34. // Destructor restores the previous signal mask
  35. ~Blocker() {
  36. pthread_sigmask(SIG_SETMASK, &old_mask_, 0);
  37. }
  38. private:
  39. // The previous signal mask
  40. sigset_t old_mask_;
  41. };
  42. }
  43. // The implementation of the Thread class.
  44. //
  45. // This internal state is not deleted until the thread terminates and is either
  46. // waited for or detached. We could do this with shared_ptr (or, shared_ptr and
  47. // weak_ptr), but we plan on compiling boost without thread support, so it
  48. // might not be safe. Therefore we use an explicit mutex. It is being locked
  49. // only 2-3 times in the lifetime of the thread, which should be negligible
  50. // overhead anyway.
  51. class Thread::Impl {
  52. public:
  53. Impl(const boost::function<void ()>& main) :
  54. // Two things to happen before destruction - thread needs to terminate
  55. // and the creating thread needs to release it.
  56. waiting_(2),
  57. main_(main),
  58. exception_(false),
  59. tid_(0)
  60. {}
  61. // Another of the waiting events is done. If there are no more, delete
  62. // impl.
  63. static void done(Impl* impl) {
  64. bool should_delete(false);
  65. { // We need to make sure the mutex is unlocked before it is deleted
  66. Mutex::Locker locker(impl->mutex_);
  67. if (--impl->waiting_ == 0) {
  68. should_delete = true;
  69. }
  70. }
  71. if (should_delete) {
  72. delete impl;
  73. }
  74. }
  75. // Run the thread. The type of parameter is because the pthread API.
  76. static void* run(void* impl_raw) {
  77. Impl* impl = static_cast<Impl*>(impl_raw);
  78. try {
  79. impl->main_();
  80. } catch (const exception& e) {
  81. impl->exception_ = true;
  82. impl->exception_text_ = e.what();
  83. } catch (...) {
  84. impl->exception_ = true;
  85. impl->exception_text_ = "Unknown exception";
  86. }
  87. done(impl);
  88. return (NULL);
  89. }
  90. // How many events are waiting? One is for the thread to finish, one
  91. // for the destructor of Thread or wait. Once both happen, this is
  92. // no longer needed.
  93. size_t waiting_;
  94. // The main function of the thread.
  95. boost::function<void ()> main_;
  96. // Was there an exception?
  97. bool exception_;
  98. string exception_text_;
  99. // The mutex protects the waiting_ member, which ensures there are
  100. // no race conditions and collisions when terminating. The other members
  101. // should be safe, because:
  102. // * tid_ is read only.
  103. // * exception_ and exception_text_ is accessed outside of the thread
  104. // only after join, by that time the thread must have terminated.
  105. // * main_ is used in a read-only way here. If there are any shared
  106. // resources used inside, it is up to the main_ itself to take care.
  107. Mutex mutex_;
  108. // Which thread are we talking about anyway?
  109. pthread_t tid_;
  110. };
  111. Thread::Thread(const boost::function<void ()>& main) :
  112. impl_(NULL)
  113. {
  114. unique_ptr<Impl> impl(new Impl(main));
  115. Blocker blocker;
  116. const int result = pthread_create(&impl->tid_, NULL, &Impl::run,
  117. impl.get());
  118. // Any error here?
  119. switch (result) {
  120. case 0: // All 0K
  121. impl_ = impl.release();
  122. break;
  123. case EAGAIN:
  124. throw std::bad_alloc();
  125. default: // Other errors. They should not happen.
  126. isc_throw(isc::InvalidOperation, std::strerror(result));
  127. }
  128. }
  129. Thread::~Thread() {
  130. if (impl_ != NULL) {
  131. // In case we didn't call wait yet
  132. const int result = pthread_detach(impl_->tid_);
  133. Impl::done(impl_);
  134. impl_ = NULL;
  135. // If the detach ever fails, something is screwed rather badly.
  136. assert(result == 0);
  137. }
  138. }
  139. void
  140. Thread::wait() {
  141. if (impl_ == NULL) {
  142. isc_throw(isc::InvalidOperation,
  143. "Wait called and no thread to wait for");
  144. }
  145. const int result = pthread_join(impl_->tid_, NULL);
  146. if (result != 0) {
  147. isc_throw(isc::InvalidOperation, std::strerror(result));
  148. }
  149. // Was there an exception in the thread?
  150. scoped_ptr<UncaughtException> ex;
  151. // Something here could in theory throw. But we already terminated the thread, so
  152. // we need to make sure we are in consistent state even in such situation (like
  153. // releasing the mutex and impl_).
  154. try {
  155. if (impl_->exception_) {
  156. ex.reset(new UncaughtException(__FILE__, __LINE__,
  157. impl_->exception_text_.c_str()));
  158. }
  159. } catch (...) {
  160. Impl::done(impl_);
  161. impl_ = NULL;
  162. // We have eaten the UncaughtException by now, but there's another
  163. // exception instead, so we have at least something.
  164. throw;
  165. }
  166. Impl::done(impl_);
  167. impl_ = NULL;
  168. if (ex.get() != NULL) {
  169. throw UncaughtException(*ex);
  170. }
  171. }
  172. }
  173. }
  174. }