2
0
mirror of https://github.com/boostorg/fiber.git synced 2026-02-02 08:52:07 +00:00
Files
fiber/src/detail/worker_fiber.cpp
2014-03-16 13:33:07 +01:00

190 lines
3.9 KiB
C++

// 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/worker_fiber.hpp"
#include <exception>
#include <boost/exception_ptr.hpp>
#include <boost/foreach.hpp>
#include <boost/thread/locks.hpp>
#include "boost/fiber/detail/scheduler.hpp"
#include "boost/fiber/exceptions.hpp"
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_PREFIX
#endif
namespace boost {
namespace fibers {
namespace detail {
void
worker_fiber::trampoline_( coro_t::yield_type & yield)
{
BOOST_ASSERT( yield);
BOOST_ASSERT( ! is_terminated() );
callee_ = & yield;
set_running();
suspend();
try
{
BOOST_ASSERT( is_running() );
run();
BOOST_ASSERT( is_running() );
}
catch ( coro::detail::forced_unwind const&)
{
set_terminated();
release();
throw;
}
catch ( fiber_interrupted const&)
{ except_ = current_exception(); }
catch (...)
{ std::terminate(); }
set_terminated();
release();
suspend();
BOOST_ASSERT_MSG( false, "fiber already terminated");
}
worker_fiber::worker_fiber( attributes const& attrs) :
fiber_base(),
fss_data_(),
nxt_(),
tp_( (clock_type::time_point::max)() ),
callee_( 0),
caller_(
boost::bind( & worker_fiber::trampoline_, this, _1),
attrs),
state_( READY),
flags_( 0),
priority_( 0),
except_(),
waiting_()
{}
worker_fiber::~worker_fiber()
{
BOOST_ASSERT( is_terminated() );
BOOST_ASSERT( waiting_.empty() );
}
void
worker_fiber::release()
{
BOOST_ASSERT( is_terminated() );
std::vector< ptr_t > waiting;
// get all waiting fibers
splk_.lock();
waiting.swap( waiting_);
splk_.unlock();
// notify all waiting fibers
BOOST_FOREACH( worker_fiber::ptr_t p, waiting)
{ p->set_ready(); }
// release all fiber-specific-pointers
BOOST_FOREACH( fss_data_t::value_type & data, fss_data_)
{ data.second.do_cleanup(); }
}
bool
worker_fiber::join( ptr_t const& p)
{
unique_lock< spinlock > lk( splk_);
if ( is_terminated() ) return false;
waiting_.push_back( p);
return true;
}
void
worker_fiber::interruption_blocked( bool blck) BOOST_NOEXCEPT
{
if ( blck)
flags_ |= flag_interruption_blocked;
else
flags_ &= ~flag_interruption_blocked;
}
void
worker_fiber::request_interruption( bool req) BOOST_NOEXCEPT
{
if ( req)
flags_ |= flag_interruption_requested;
else
flags_ &= ~flag_interruption_requested;
}
void
worker_fiber::thread_affinity( bool req) BOOST_NOEXCEPT
{
if ( req)
flags_ |= flag_thread_affinity;
else
flags_ &= ~flag_thread_affinity;
}
void *
worker_fiber::get_fss_data( void const* vp) const
{
uintptr_t key( reinterpret_cast< uintptr_t >( vp) );
fss_data_t::const_iterator i( fss_data_.find( key) );
return fss_data_.end() != i ? i->second.vp : 0;
}
void
worker_fiber::set_fss_data(
void const* vp,
fss_cleanup_function::ptr_t const& cleanup_fn,
void * data, bool cleanup_existing)
{
BOOST_ASSERT( cleanup_fn);
uintptr_t key( reinterpret_cast< uintptr_t >( vp) );
fss_data_t::iterator i( fss_data_.find( key) );
if ( fss_data_.end() != i)
{
if( cleanup_existing) i->second.do_cleanup();
if ( data)
fss_data_.insert(
i,
std::make_pair(
key,
fss_data( data, cleanup_fn) ) );
else fss_data_.erase( i);
}
else
fss_data_.insert(
std::make_pair(
key,
fss_data( data, cleanup_fn) ) );
}
void
worker_fiber::rethrow() const
{
BOOST_ASSERT( has_exception() );
rethrow_exception( except_);
}
}}}
#ifdef BOOST_HAS_ABI_HEADERS
# include BOOST_ABI_SUFFIX
#endif