thread.cc 5.6 KB

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