diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 864eccba..8145bc95 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -32,6 +32,7 @@ lib boost_fiber condition.cpp detail/fifo.cpp detail/spinlock.cpp + detail/terminated_queue.cpp detail/waiting_queue.cpp fiber.cpp fiber_context.cpp diff --git a/include/boost/fiber/detail/terminated_queue.hpp b/include/boost/fiber/detail/terminated_queue.hpp new file mode 100644 index 00000000..304b90c8 --- /dev/null +++ b/include/boost/fiber/detail/terminated_queue.hpp @@ -0,0 +1,62 @@ + +// 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_TERMINATED_QUEUE_H +#define BOOST_FIBERS_DETAIL_TERMINATED_QUEUE_H + +#include +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace fibers { + +class fiber_context; + +namespace detail { + +class terminated_queue { +public: + terminated_queue() noexcept : + head_( nullptr), + tail_( & head_) { + } + + terminated_queue( terminated_queue const&) = delete; + terminated_queue & operator=( terminated_queue const&) = delete; + + void push( fiber_context * item) noexcept; + + void clear() noexcept; + + void swap( terminated_queue & other) { + std::swap( head_, other.head_); + std::swap( tail_, other.tail_); + } + +private: + fiber_context * head_; + // tail_ points to the nxt field that contains the null that marks the end + // of the terminated_queue. When the terminated_queue is empty, tail_ points to head_. tail_ must + // never be null: it always points to a real fiber_context*. However, in + // normal use, (*tail_) is always null. + fiber_context ** tail_; +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_FIBERS_DETAIL_TERMINATED_QUEUE_H diff --git a/include/boost/fiber/fiber_manager.hpp b/include/boost/fiber/fiber_manager.hpp index bcba2597..8d651807 100644 --- a/include/boost/fiber/fiber_manager.hpp +++ b/include/boost/fiber/fiber_manager.hpp @@ -14,8 +14,8 @@ #include #include -#include #include +#include #include #ifdef BOOST_HAS_ABI_HEADERS @@ -31,7 +31,7 @@ struct sched_algorithm; struct fiber_manager { private: typedef detail::waiting_queue wqueue_t; - typedef detail::fifo tqueue_t; + typedef detail::terminated_queue tqueue_t; sched_algorithm * sched_algo_; fiber_context * active_fiber_; diff --git a/src/detail/terminated_queue.cpp b/src/detail/terminated_queue.cpp new file mode 100644 index 00000000..afbc32a2 --- /dev/null +++ b/src/detail/terminated_queue.cpp @@ -0,0 +1,51 @@ + +// 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) + +#include "boost/fiber/detail/terminated_queue.hpp" + +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace fibers { +namespace detail { + +void +terminated_queue::push( fiber_context * item) noexcept { + BOOST_ASSERT( nullptr != item); + BOOST_ASSERT( nullptr == item->nxt); + + // * tail_ holds the null marking the end of the terminated_queue. So we can extend + // the terminated_queue by assigning to * tail_. + * tail_ = item; + // Advance tail_ to point to the new end marker. + tail_ = & item->nxt; +} + +void +terminated_queue::clear() noexcept { + while ( nullptr != head_) { + fiber_context * item( head_); + head_ = head_->nxt; + if ( nullptr == head_) { + tail_ = & head_; + } + // should call ~fiber_context() + intrusive_ptr_release( item); + } +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif diff --git a/src/fiber_manager.cpp b/src/fiber_manager.cpp index 47dffed9..7f714c15 100644 --- a/src/fiber_manager.cpp +++ b/src/fiber_manager.cpp @@ -111,23 +111,13 @@ fiber_manager::run() { BOOST_ASSERT_MSG( f->is_ready(), "fiber with invalid state in ready-queue"); // destroy terminated fibers from tqueue_ - while ( ! tqueue_.empty() ) { - fiber_context * f_( tqueue_.pop() ); - BOOST_ASSERT( nullptr != f_); - BOOST_ASSERT( f_->is_terminated() ); - intrusive_ptr_release( f_); - } + tqueue_.clear(); // resume fiber f resume_( f); // destroy terminated fibers from tqueue_ - while ( ! tqueue_.empty() ) { - fiber_context * f_( tqueue_.pop() ); - BOOST_ASSERT( nullptr != f_); - BOOST_ASSERT( f_->is_terminated() ); - intrusive_ptr_release( f_); - } + tqueue_.clear(); return; } else {