123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- #include <util/threads/thread.h>
- #include <util/threads/sync.h>
- #include <memory>
- #include <string>
- #include <cstring>
- #include <cerrno>
- #include <pthread.h>
- #include <signal.h>
- #include <boost/noncopyable.hpp>
- #include <boost/scoped_ptr.hpp>
- using std::string;
- using std::exception;
- using std::auto_ptr;
- using boost::scoped_ptr;
- namespace isc {
- namespace util {
- namespace thread {
- namespace {
- class Blocker : boost::noncopyable {
- public:
-
- Blocker() {
- sigset_t new_mask;
- sigfillset(&new_mask);
- pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_);
- }
-
- ~Blocker() {
- pthread_sigmask(SIG_SETMASK, &old_mask_, 0);
- }
- private:
-
- sigset_t old_mask_;
- };
- }
- class Thread::Impl {
- public:
- Impl(const boost::function<void ()>& main) :
-
-
- waiting_(2),
- main_(main),
- exception_(false),
- tid_(0)
- {}
-
-
- static void done(Impl* impl) {
- bool should_delete(false);
- {
- Mutex::Locker locker(impl->mutex_);
- if (--impl->waiting_ == 0) {
- should_delete = true;
- }
- }
- if (should_delete) {
- delete impl;
- }
- }
-
- static void* run(void* impl_raw) {
- Impl* impl = static_cast<Impl*>(impl_raw);
- try {
- impl->main_();
- } catch (const exception& e) {
- impl->exception_ = true;
- impl->exception_text_ = e.what();
- } catch (...) {
- impl->exception_ = true;
- impl->exception_text_ = "Unknown exception";
- }
- done(impl);
- return (NULL);
- }
-
-
-
- size_t waiting_;
-
- boost::function<void ()> main_;
-
- bool exception_;
- string exception_text_;
-
-
-
-
-
-
-
-
- Mutex mutex_;
-
- pthread_t tid_;
- };
- Thread::Thread(const boost::function<void ()>& main) :
- impl_(NULL)
- {
- auto_ptr<Impl> impl(new Impl(main));
- Blocker blocker;
- const int result = pthread_create(&impl->tid_, NULL, &Impl::run,
- impl.get());
-
- switch (result) {
- case 0:
- impl_ = impl.release();
- break;
- case EAGAIN:
- throw std::bad_alloc();
- default:
- isc_throw(isc::InvalidOperation, std::strerror(result));
- }
- }
- Thread::~Thread() {
- if (impl_ != NULL) {
-
- const int result = pthread_detach(impl_->tid_);
- Impl::done(impl_);
- impl_ = NULL;
-
- assert(result == 0);
- }
- }
- void
- Thread::wait() {
- if (impl_ == NULL) {
- isc_throw(isc::InvalidOperation,
- "Wait called and no thread to wait for");
- }
- const int result = pthread_join(impl_->tid_, NULL);
- if (result != 0) {
- isc_throw(isc::InvalidOperation, std::strerror(result));
- }
-
- scoped_ptr<UncaughtException> ex;
-
-
-
- try {
- if (impl_->exception_) {
- ex.reset(new UncaughtException(__FILE__, __LINE__,
- impl_->exception_text_.c_str()));
- }
- } catch (...) {
- Impl::done(impl_);
- impl_ = NULL;
-
-
- throw;
- }
- Impl::done(impl_);
- impl_ = NULL;
- if (ex.get() != NULL) {
- throw UncaughtException(*ex);
- }
- }
- }
- }
- }
|