thread.cc 5.7 KB

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