diff --git a/asio/include/asio/detail/null_event.hpp b/asio/include/asio/detail/null_event.hpp index df522ce0..99bcbc6a 100644 --- a/asio/include/asio/detail/null_event.hpp +++ b/asio/include/asio/detail/null_event.hpp @@ -43,17 +43,20 @@ public: } // Signal the event. - void signal() + template + void signal(Lock&) { } // Reset the event. - void clear() + template + void clear(Lock&) { } // Wait for the event to become signalled. - void wait() + template + void wait(Lock&) { } }; diff --git a/asio/include/asio/detail/posix_event.hpp b/asio/include/asio/detail/posix_event.hpp index 408c23bb..1197ac3f 100644 --- a/asio/include/asio/detail/posix_event.hpp +++ b/asio/include/asio/detail/posix_event.hpp @@ -24,6 +24,7 @@ #if defined(BOOST_HAS_PTHREADS) #include "asio/detail/push_options.hpp" +#include #include #include #include "asio/detail/pop_options.hpp" @@ -42,7 +43,7 @@ public: posix_event() : signalled_(false) { - int error = ::pthread_mutex_init(&mutex_, 0); + int error = ::pthread_cond_init(&cond_, 0); if (error != 0) { asio::system_error e( @@ -50,53 +51,43 @@ public: "event"); boost::throw_exception(e); } - - error = ::pthread_cond_init(&cond_, 0); - if (error != 0) - { - ::pthread_mutex_destroy(&mutex_); - asio::system_error e( - asio::error_code(error, asio::native_ecat), - "event"); - boost::throw_exception(e); - } } // Destructor. ~posix_event() { ::pthread_cond_destroy(&cond_); - ::pthread_mutex_destroy(&mutex_); } // Signal the event. - void signal() + template + void signal(Lock& lock) { - ::pthread_mutex_lock(&mutex_); // Ignore EINVAL and EDEADLK. + BOOST_ASSERT(lock.locked()); + (void)lock; signalled_ = true; ::pthread_cond_signal(&cond_); // Ignore EINVAL. - ::pthread_mutex_unlock(&mutex_); // Ignore EINVAL and EPERM. } // Reset the event. - void clear() + template + void clear(Lock& lock) { - ::pthread_mutex_lock(&mutex_); // Ignore EINVAL and EDEADLK. + BOOST_ASSERT(lock.locked()); + (void)lock; signalled_ = false; - ::pthread_mutex_unlock(&mutex_); // Ignore EINVAL and EPERM. } // Wait for the event to become signalled. - void wait() + template + void wait(Lock& lock) { - ::pthread_mutex_lock(&mutex_); // Ignore EINVAL and EDEADLK. + BOOST_ASSERT(lock.locked()); while (!signalled_) - ::pthread_cond_wait(&cond_, &mutex_); // Ignore EINVAL. - ::pthread_mutex_unlock(&mutex_); // Ignore EINVAL and EPERM. + ::pthread_cond_wait(&cond_, &lock.mutex().mutex_); // Ignore EINVAL. } private: - ::pthread_mutex_t mutex_; ::pthread_cond_t cond_; bool signalled_; }; diff --git a/asio/include/asio/detail/posix_mutex.hpp b/asio/include/asio/detail/posix_mutex.hpp index 154089f3..224722bb 100644 --- a/asio/include/asio/detail/posix_mutex.hpp +++ b/asio/include/asio/detail/posix_mutex.hpp @@ -35,6 +35,8 @@ namespace asio { namespace detail { +class posix_event; + class posix_mutex : private noncopyable { @@ -87,6 +89,7 @@ public: } private: + friend class posix_event; ::pthread_mutex_t mutex_; }; diff --git a/asio/include/asio/detail/scoped_lock.hpp b/asio/include/asio/detail/scoped_lock.hpp index 64c77cba..57f8cb8f 100644 --- a/asio/include/asio/detail/scoped_lock.hpp +++ b/asio/include/asio/detail/scoped_lock.hpp @@ -63,6 +63,18 @@ public: } } + // Test whether the lock is held. + bool locked() const + { + return locked_; + } + + // Get the underlying mutex. + Mutex& mutex() + { + return mutex_; + } + private: // The underlying mutex. Mutex& mutex_; diff --git a/asio/include/asio/detail/task_io_service.hpp b/asio/include/asio/detail/task_io_service.hpp index f47b77a6..a1c2a5d2 100644 --- a/asio/include/asio/detail/task_io_service.hpp +++ b/asio/include/asio/detail/task_io_service.hpp @@ -132,7 +132,7 @@ public: void stop() { asio::detail::mutex::scoped_lock lock(mutex_); - stop_all_threads(); + stop_all_threads(lock); } // Reset in preparation for a subsequent run invocation. @@ -154,7 +154,7 @@ public: { asio::detail::mutex::scoped_lock lock(mutex_); if (--outstanding_work_ == 0) - stop_all_threads(); + stop_all_threads(lock); } // Request invocation of the given handler. @@ -199,7 +199,7 @@ public: ++outstanding_work_; // Wake up a thread to execute the handler. - if (!interrupt_one_idle_thread()) + if (!interrupt_one_idle_thread(lock)) if (task_handler_.next_ == 0 && handler_queue_end_ != &task_handler_) task_.interrupt(); } @@ -212,7 +212,7 @@ private: { if (outstanding_work_ == 0 && !stopped_) { - stop_all_threads(); + stop_all_threads(lock); ec = asio::error_code(); return 0; } @@ -267,10 +267,8 @@ private: // Nothing to run right now, so just wait for work to do. this_idle_thread->next = first_idle_thread_; first_idle_thread_ = this_idle_thread; - this_idle_thread->wakeup_event.clear(); - lock.unlock(); - this_idle_thread->wakeup_event.wait(); - lock.lock(); + this_idle_thread->wakeup_event.clear(lock); + this_idle_thread->wakeup_event.wait(lock); } else { @@ -284,38 +282,41 @@ private: } // Stop the task and all idle threads. - void stop_all_threads() + void stop_all_threads( + asio::detail::mutex::scoped_lock& lock) { stopped_ = true; - interrupt_all_idle_threads(); + interrupt_all_idle_threads(lock); if (task_handler_.next_ == 0 && handler_queue_end_ != &task_handler_) task_.interrupt(); } // Interrupt a single idle thread. Returns true if a thread was interrupted, // false if no running thread could be found to interrupt. - bool interrupt_one_idle_thread() + bool interrupt_one_idle_thread( + asio::detail::mutex::scoped_lock& lock) { if (first_idle_thread_) { idle_thread_info* idle_thread = first_idle_thread_; first_idle_thread_ = idle_thread->next; idle_thread->next = 0; - idle_thread->wakeup_event.signal(); + idle_thread->wakeup_event.signal(lock); return true; } return false; } // Interrupt all idle threads. - void interrupt_all_idle_threads() + void interrupt_all_idle_threads( + asio::detail::mutex::scoped_lock& lock) { while (first_idle_thread_) { idle_thread_info* idle_thread = first_idle_thread_; first_idle_thread_ = idle_thread->next; idle_thread->next = 0; - idle_thread->wakeup_event.signal(); + idle_thread->wakeup_event.signal(lock); } } @@ -459,7 +460,7 @@ private: { lock_.lock(); if (--task_io_service_.outstanding_work_ == 0) - task_io_service_.stop_all_threads(); + task_io_service_.stop_all_threads(lock_); } private: diff --git a/asio/include/asio/detail/win_event.hpp b/asio/include/asio/detail/win_event.hpp index 8de9383d..68f55ff1 100644 --- a/asio/include/asio/detail/win_event.hpp +++ b/asio/include/asio/detail/win_event.hpp @@ -28,6 +28,7 @@ #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" +#include #include #include "asio/detail/pop_options.hpp" @@ -59,21 +60,31 @@ public: } // Signal the event. - void signal() + template + void signal(Lock& lock) { + BOOST_ASSERT(lock.locked()); + (void)lock; ::SetEvent(event_); } // Reset the event. - void clear() + template + void clear(Lock& lock) { + BOOST_ASSERT(lock.locked()); + (void)lock; ::ResetEvent(event_); } // Wait for the event to become signalled. - void wait() + template + void wait(Lock& lock) { + BOOST_ASSERT(lock.locked()); + lock.unlock(); ::WaitForSingleObject(event_, INFINITE); + lock.lock(); } private: