From dd0e1d18933923339a6c60dbbd01c278f38e4e71 Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Wed, 16 Sep 2015 21:07:26 +0200 Subject: [PATCH] add autoreset_event for waling up dispatcher context - dispatcher waits on autoreset_event if ready-queue is empty - autoreset_event is set if a ready context is pushed to the ready-queue --- .../boost/fiber/detail/autoreset_event.hpp | 60 +++++++++++++++++++ include/boost/fiber/scheduler.hpp | 2 + src/scheduler.cpp | 21 +++++-- 3 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 include/boost/fiber/detail/autoreset_event.hpp diff --git a/include/boost/fiber/detail/autoreset_event.hpp b/include/boost/fiber/detail/autoreset_event.hpp new file mode 100644 index 00000000..c83d4c91 --- /dev/null +++ b/include/boost/fiber/detail/autoreset_event.hpp @@ -0,0 +1,60 @@ + +// Copyright Oliver Kowalke 2013. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_FIBERS_DETAIL_AUTORESET_EVENT_H +#define BOOST_FIBERS_DETAIL_AUTORESET_EVENT_H + +#include +#include +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace fibers { +namespace detail { + +class autoreset_event { +private: + std::mutex mtx_; + std::condition_variable cnd_; + bool flag_; + +public: + autoreset_event() : + mtx_(), cnd_(), flag_( false) { + } + + autoreset_event( autoreset_event const&) = delete; + autoreset_event & operator=( autoreset_event const&) = delete; + + void set() { + std::unique_lock< std::mutex > lk( mtx_); + flag_ = true; + lk.unlock(); + cnd_.notify_all(); + } + + void reset( std::chrono::steady_clock::time_point const& time_point) { + std::unique_lock< std::mutex > lk( mtx_); + cnd_.wait_until( lk, time_point, [=](){ return flag_; }); + flag_ = false; + } +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_FIBERS_DETAIL_AUTORESET_EVENT_H diff --git a/include/boost/fiber/scheduler.hpp b/include/boost/fiber/scheduler.hpp index 0dbf3cea..07b3a553 100644 --- a/include/boost/fiber/scheduler.hpp +++ b/include/boost/fiber/scheduler.hpp @@ -11,6 +11,7 @@ #include #include +#include #include #ifdef BOOST_HAS_ABI_HEADERS @@ -38,6 +39,7 @@ private: ready_queue_t ready_queue_; terminated_queue_t terminated_queue_; bool shutdown_; + detail::autoreset_event ready_queue_ev_; void resume_( context *, context *); diff --git a/src/scheduler.cpp b/src/scheduler.cpp index c9158716..90282922 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -6,6 +6,8 @@ #include "boost/fiber/scheduler.hpp" +#include + #include #include "boost/fiber/context.hpp" @@ -35,9 +37,11 @@ scheduler::resume_( context * actx, context * ctx) { context * scheduler::get_next_() noexcept { - BOOST_ASSERT( ! ready_queue_.empty() ); - context * ctx = & ready_queue_.front(); - ready_queue_.pop_front(); + context * ctx( nullptr); + if ( ! ready_queue_.empty() ) { + ctx = & ready_queue_.front(); + ready_queue_.pop_front(); + } return ctx; } @@ -57,7 +61,8 @@ scheduler::scheduler() noexcept : dispatcher_ctx_(), ready_queue_(), terminated_queue_(), - shutdown_( false) { + shutdown_( false), + ready_queue_ev_() { } scheduler::~scheduler() noexcept { @@ -99,7 +104,13 @@ void scheduler::dispatch() { while ( ! shutdown_) { release_terminated_(); - auto ctx = get_next_(); + context * ctx( nullptr); + // loop till we get next ready context + while ( nullptr == ( ctx = get_next_() ) ) { + // no ready context, wait till signaled + ready_queue_ev_.reset( + (std::chrono::steady_clock::time_point::max)()); + } // push dispatcher context to ready-queue // so that ready-queue never becomes empty auto active_ctx = context::active();