Imported existing code

This commit is contained in:
Hazim Gazov
2010-04-02 02:48:44 -03:00
parent 48fbc5ae91
commit 7a86d01598
13996 changed files with 2468699 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_ARG_MAX_HPP_20060728
# define BOOST_COROUTINE_DETAIL_ARG_MAX_HPP_20060728
# ifndef BOOST_COROUTINE_ARG_MAX
# define BOOST_COROUTINE_ARG_MAX 10
# endif
#endif

View File

@@ -0,0 +1,70 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_ARGUMENT_PACKER_HPP_20060601
#define BOOST_COROUTINE_ARGUMENT_PACKER_HPP_20060601
#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/repetition.hpp>
#include <boost/preprocessor/tuple/eat.hpp>
namespace boost { namespace coroutines { namespace detail {
#define BOOST_COROUTINE_DETAIL_TEMPLATE_PARAMETERS(n) \
template<BOOST_PP_ENUM_PARAMS(n, typename T)> \
/**/
#define BOOST_COROUTINE_ARGUMENT_PACKER(z, n, parm_tuple) \
BOOST_PP_IF(n, \
BOOST_COROUTINE_DETAIL_TEMPLATE_PARAMETERS , \
BOOST_PP_TUPLE_EAT(1) )(n) \
BOOST_PP_TUPLE_ELEM(3, 0, parm_tuple) \
(BOOST_PP_ENUM_BINARY_PARAMS(n, T, arg)) { \
typedef BOOST_PP_TUPLE_ELEM(3, 2, parm_tuple) parm_type; \
return BOOST_PP_TUPLE_ELEM(3, 1, parm_tuple) \
(parm_type \
(BOOST_PP_ENUM_PARAMS(n, arg))); \
} \
/**/
#define BOOST_COROUTINE_ARGUMENT_PACKER_EX(z, n, parm_tuple) \
template<typename Arg \
BOOST_PP_COMMA_IF(n) \
BOOST_PP_ENUM_PARAMS(n, typename T)> \
BOOST_PP_TUPLE_ELEM(3, 0, parm_tuple) \
(Arg arg \
BOOST_PP_COMMA_IF(n) \
BOOST_PP_ENUM_BINARY_PARAMS(n, T, arg)) { \
typedef BOOST_PP_TUPLE_ELEM(3, 2, parm_tuple) parm_type; \
return BOOST_PP_TUPLE_ELEM(3, 1, parm_tuple)( arg, parm_type \
(BOOST_PP_ENUM_PARAMS(n, arg))); \
} \
/**/
} } }
#endif

View File

@@ -0,0 +1,134 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_ARGUMENT_UNPACKER_HPP_20060601
#define BOOST_COROUTINE_ARGUMENT_UNPACKER_HPP_20060601
#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/repetition.hpp>
#include <boost/utility/result_of.hpp>
#include <boost/coroutine/detail/index.hpp>
#include <boost/coroutine/detail/arg_max.hpp>
namespace boost { namespace coroutines { namespace detail {
template<typename Traits, int Len>
struct unpacker_n;
template<typename Traits, int Len>
struct unpacker_ex_n;
#define BOOST_COROUTINE_ARGUMENT_UNPACKER(z, len, unused) \
template<typename Traits> \
struct unpacker_n<Traits, len> { \
template<typename Functor, typename Tuple> \
struct result {/*for result_of compatibility*/ \
typedef typename boost::result_of \
<Functor(BOOST_PP_ENUM_BINARY_PARAMS \
(len, typename Traits::template at<index_ , > \
::type BOOST_PP_INTERCEPT))>::type type; \
}; \
template<typename Functor, typename Tuple> \
typename result<Functor, Tuple>::type operator() \
(Functor& f, Tuple& parms){ \
using boost::get; /*tuples::get cannot be found via ADL*/ \
return f(BOOST_PP_ENUM_BINARY_PARAMS \
(len, \
get<index_, > \
(parms) BOOST_PP_INTERCEPT)); \
} \
}; \
/**/
#define BOOST_COROUTINE_ARGUMENT_UNPACKER_EX(z, len, unused) \
template<typename Traits> \
struct unpacker_ex_n<Traits, len > { \
template<typename Functor, \
typename First, \
typename Tuple> \
struct result { \
typedef typename boost::result_of \
<Functor(First BOOST_PP_COMMA_IF(len) \
BOOST_PP_ENUM_BINARY_PARAMS \
(len, typename Traits \
::template at<index_ , >::type BOOST_PP_INTERCEPT))> \
::type type; \
}; \
\
template<typename Functor, \
typename First, \
typename Tuple> \
typename result<Functor, First, Tuple>::type \
operator()(Functor& f, First& arg0, Tuple& parms){ \
using boost::get; /*tuples::get cannot be found via ADL*/ \
return f(arg0 \
BOOST_PP_COMMA_IF(len) \
BOOST_PP_ENUM_BINARY_PARAMS \
(len, \
get<index_, > \
(parms) BOOST_PP_INTERCEPT) ); \
} \
}; \
/**/
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_ARGUMENT_UNPACKER, ~);
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_ARGUMENT_UNPACKER_EX, ~);
// Somehow VCPP 8.0 chockes if the Trait for unpack[_ex]
// is explicitly specified. We use an empty dispatch
// tag to let the compiler deduce it.
template<typename Trait>
struct trait_tag {};
/**
* Inovoke function object @p f passing all
* elements in tuple @p parms as distinct parameters.
*/
template<typename Traits, typename Functor, typename Tuple>
inline
typename unpacker_n<Traits, Traits::length>
::template result<Functor, Tuple>::type
unpack(Functor f, Tuple& parms, trait_tag<Traits>) {
return unpacker_n<Traits, Traits::length>()(f, parms);
}
/**
* Inovke function object @p f passing argument @p arg0 and all
* elements in tuple @p parms as distinct parameters.
*/
template<typename Traits, typename Functor, typename First, typename Tuple>
inline
typename unpacker_ex_n<Traits, Traits::length>::
template result<Functor, First, Tuple>::type
unpack_ex(Functor f, First& arg0, Tuple& parms, trait_tag<Traits>) {
return unpacker_ex_n<Traits, Traits::length>()
(f, arg0, parms);
}
} } }
#endif

View File

@@ -0,0 +1,123 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_CALL_IMPL_HPP_20060728
#define BOOST_COROUTINE_DETAIL_CALL_IMPL_HPP_20060728
#include <boost/preprocessor/repetition.hpp>
#include <boost/call_traits.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/bind.hpp>
#include <boost/coroutine/coroutine.hpp>
#include <boost/coroutine/detail/arg_max.hpp>
#include <boost/coroutine/detail/signal.hpp>
#include <boost/coroutine/detail/coroutine_accessor.hpp>
namespace boost { namespace coroutines { namespace detail {
#define BOOST_COROUTINE_tuple_param_n(z, n, tuple)\
BOOST_DEDUCED_TYPENAME \
boost::tuples::element<n, tuple>::type \
BOOST_PP_CAT(arg, n) \
/**/
template<typename Future>
class callback {
public:
typedef void result_type;
callback(Future& future) :
m_future_pimpl(wait_gateway::get_impl(future)) {
m_future_pimpl->mark_pending();
}
typedef BOOST_DEDUCED_TYPENAME
Future::tuple_type tuple_type;
typedef BOOST_DEDUCED_TYPENAME
Future::tuple_traits_type tuple_traits_type;
/*
* By default a callback is one shot only.
* By calling this method you can revive a
* callback for another shot.
* You must guaranee that the future
* is still alive.
*/
void revive() {
m_future_pimpl->mark_pending();
}
#define BOOST_COROUTINE_gen_argn_type(z, n, unused) \
typedef BOOST_DEDUCED_TYPENAME \
tuple_traits_type:: \
template at<n>::type \
BOOST_PP_CAT(BOOST_PP_CAT(arg, n), _type); \
/**/
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_gen_argn_type,
~);
#define BOOST_COROUTINE_param_with_default(z, n, type_prefix) \
BOOST_DEDUCED_TYPENAME call_traits \
<BOOST_PP_CAT(BOOST_PP_CAT(type_prefix, n), _type)> \
::param_type \
BOOST_PP_CAT(arg, n) = \
BOOST_PP_CAT(BOOST_PP_CAT(type_prefix, n), _type)() \
/**/
void operator()
(BOOST_PP_ENUM
(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_param_with_default,
arg)) {
m_future_pimpl->assign(tuple_type
(BOOST_PP_ENUM_PARAMS
(BOOST_COROUTINE_ARG_MAX, arg)));
}
private:
BOOST_DEDUCED_TYPENAME
Future::impl_pointer
m_future_pimpl;
};
#undef BOOST_COROUTINE_gen_future_assigner
#undef BOOST_COROUTINE_tuple_param_n
template<typename Future, typename Functor, typename CoroutineSelf>
Future call_impl(Functor fun, const CoroutineSelf& coro_self) {
Future future(coro_self);
fun(callback<Future>(future));
return future;
}
} } }
#endif

View File

@@ -0,0 +1,416 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_CONTEXT_IMPL_HPP_20060810
#define BOOST_COROUTINE_CONTEXT_IMPL_HPP_20060810
/*
* Currently asio can, in some cases. call copy constructors and
* operator= from different threads, even if in the
* one-thread-per-service model. (i.e. from the resolver thread)
* This will be corrected in future versions, but for now
* we will play it safe and use an atomic count. The overhead shouldn't
* be big.
*/
#define BOOST_COROUTINE_USE_ATOMIC_COUNT
#ifdef BOOST_COROUTINE_USE_ATOMIC_COUNT
# include <boost/detail/atomic_count.hpp>
#endif
#include <cstddef>
#include <algorithm> //for swap
#include <boost/coroutine/detail/swap_context.hpp> //for swap hints
#include <boost/intrusive_ptr.hpp>
#include <boost/coroutine/exception.hpp>
#include <boost/coroutine/detail/noreturn.hpp>
namespace boost { namespace coroutines { namespace detail {
const std::ptrdiff_t default_stack_size = -1;
template<typename ContextImpl>
class context_base : public ContextImpl {
public:
typedef ContextImpl context_impl;
typedef context_base<context_impl> type;
typedef boost::intrusive_ptr<type> pointer;
typedef void deleter_type(const type*);
template<typename Derived>
context_base(Derived& derived,
std::ptrdiff_t stack_size) :
context_impl(derived, stack_size),
m_counter(0),
m_deleter(&deleter<Derived>),
m_state(ctx_ready),
m_exit_state(ctx_exit_not_requested),
m_exit_status(ctx_not_exited),
m_wait_counter(0),
m_operation_counter(0),
m_type_info(0) {}
friend
void intrusive_ptr_add_ref(type * ctx) {
ctx->acquire();
}
friend
void intrusive_ptr_release(type * ctx) {
ctx->release();
}
bool unique() const {
return count() == 1;
}
std::size_t count() const {
return m_counter;
}
void acquire() const {
++m_counter;
}
void release() const {
BOOST_ASSERT(m_counter);
if(--m_counter == 0) {
m_deleter(this);
}
}
void count_down() throw() {
BOOST_ASSERT(m_operation_counter) ;
--m_operation_counter;
}
void count_up() throw() {
++m_operation_counter;
}
// return true if there are operations pending.
int pending() const {
return m_operation_counter;
}
/*
* A signal may occur only when a context is
* not running (is delivered sinchrononously).
* This means that state MUST NOT be busy.
* It may be ready or waiting.
* returns 'ready()'.
* Nothrow.
*/
bool signal () throw() {
BOOST_ASSERT(!running() && !exited());
BOOST_ASSERT(m_wait_counter) ;
--m_wait_counter;
if(!m_wait_counter && m_state == ctx_waiting)
m_state = ctx_ready;
return ready();
}
/*
* Wake up a waiting context.
* Similar to invoke(), but *does not
* throw* if the coroutine exited normally
* or entered the wait state.
* It *does throw* if the coroutine
* exited abnormally.
* Return: false if invoke() would have thrown,
* true otherwise.
*
*/
bool wake_up() {
BOOST_ASSERT(ready());
do_invoke();
// TODO: could use a binary 'or' here to eliminate
// shortcut evaluation (and a branch), but maybe the compiler is
// smart enough to do it anyway as there are no side effects.
if(m_exit_status || m_state == ctx_waiting) {
if(m_state == ctx_waiting)
return false;
if(m_exit_status == ctx_exited_return)
return true;
if(m_exit_status == ctx_exited_abnormally) {
std::type_info const * tinfo =0;
std::swap(m_type_info, tinfo);
throw abnormal_exit(tinfo?*tinfo: typeid(unknown_exception_tag));
} else if(m_exit_status == ctx_exited_exit)
return false;
else {
BOOST_ASSERT(0 && "unkonw exit status");
}
}
return true;
}
/*
* Returns true if the context is runnable.
*/
bool ready() const {
return m_state == ctx_ready;
}
/*
* Returns true if the context is in wait
* state.
*/
bool waiting() const {
return m_state == ctx_waiting;
}
bool running() const {
return m_state == ctx_running;
}
bool exited() const {
return m_state == ctx_exited;
}
// Resume coroutine.
// Pre: The coroutine must be ready.
// Post: The coroutine relinquished control. It might be ready, waiting
// or exited.
// Throws:- 'waiting' if the coroutine entered the wait state,
// - 'coroutine_exited' if the coroutine exited by an uncaught
// 'exit_exception'.
// - 'abnormal_exit' if the coroutine was exited by another
// uncaught exception.
// Note, it guarantees that the coroutine is resumed. Can throw only
// on return.
void invoke() {
BOOST_ASSERT(ready());
do_invoke();
// TODO: could use a bynary or here to eliminate
// shortcut evaluation (and a branch), but maybe the compiler is
// smart enough to do it anyway as there are no side effects.
if(m_exit_status || m_state == ctx_waiting) {
if(m_state == ctx_waiting)
throw waiting();
if(m_exit_status == ctx_exited_return)
return;
if(m_exit_status == ctx_exited_abnormally) {
std::type_info const * tinfo =0;
std::swap(m_type_info, tinfo);
throw abnormal_exit(tinfo?*tinfo: typeid(unknown_exception_tag));
} else if(m_exit_status == ctx_exited_exit)
throw coroutine_exited();
else {
BOOST_ASSERT(0 && "unkonw exit status");
}
}
}
// Put coroutine in ready state and relinquish control
// to caller until resumed again.
// Pre: Coroutine is running.
// Exit not pending.
// Operations not pending.
// Post: Coroutine is running.
// Throws: exit_exception, if exit is pending *after* it has been
// resumed.
void yield() {
BOOST_ASSERT(m_exit_state < ctx_exit_signaled); //prevent infinite loops
BOOST_ASSERT(running());
BOOST_ASSERT(!pending());
m_state = ctx_ready;
do_yield();
BOOST_ASSERT(running());
check_exit_state();
}
//
// If n > 0, put the coroutine in the wait state
// then relinquish control to caller.
// If n = 0 do nothing.
// The coroutine will remain in the wait state until
// is signaled 'n' times.
// Pre: 0 <= n < pending()
// Coroutine is running.
// Exit not pending.
// Post: Coroutine is running.
// The coroutine has been signaled 'n' times unless an exit
// has been signaled.
// Throws: exit_exception.
// FIXME: currently there is a BIG problem. A coroutine cannot
// be exited as long as there are futures pending.
// The exit_exception would cause the future to be destroyed and
// an assertion to be generated. Removing an assertion is not a
// solution because we would leak the coroutine impl. The callback
// bound to the future in fact hold a refrence to it. If the coroutine
// is exited the callback cannot be called.
void wait(int n) {
BOOST_ASSERT(!(n<0));
BOOST_ASSERT(m_exit_state < ctx_exit_signaled); //prevent infinite loop
BOOST_ASSERT(running());
BOOST_ASSERT(!(pending() < n));
if(n == 0) return;
m_wait_counter = n;
m_state = ctx_waiting;
do_yield();
BOOST_ASSERT(m_state == ctx_running);
check_exit_state();
BOOST_ASSERT(m_wait_counter == 0);
}
// Throws: exit_exception.
void yield_to(context_base& to) {
BOOST_ASSERT(m_exit_state < ctx_exit_signaled); //prevent infinite loops
BOOST_ASSERT(m_state == ctx_running);
BOOST_ASSERT(to.ready());
BOOST_ASSERT(!to.pending());
std::swap(m_caller, to.m_caller);
std::swap(m_state, to.m_state);
swap_context(*this, to, detail::yield_to_hint());
BOOST_ASSERT(m_state == ctx_running);
check_exit_state();
}
// Cause this coroutine to exit.
// Can only be called on a ready coroutine.
// Cannot be called if there are pending operations.
// It follws that cannot be called from 'this'.
// Nothrow.
void exit() throw(){
BOOST_ASSERT(!pending());
BOOST_ASSERT(ready()) ;
if(m_exit_state < ctx_exit_pending)
m_exit_state = ctx_exit_pending;
do_invoke();
BOOST_ASSERT(exited()); //at this point the coroutine MUST have exited.
}
// Always throw exit_exception.
// Never returns from standard control flow.
BOOST_COROUTINE_NORETURN(void exit_self()) {
BOOST_ASSERT(!pending());
BOOST_ASSERT(running());
m_exit_state = ctx_exit_pending;
throw exit_exception();
}
// Nothrow.
~context_base() throw() {
BOOST_ASSERT(!running());
try {
if(!exited())
exit();
BOOST_ASSERT(exited());
} catch(...) {}
}
protected:
// global coroutine state
enum context_state {
ctx_running, // context running.
ctx_ready, // context at yield point.
ctx_waiting, // context waiting for events.
ctx_exited // context is finished.
};
// exit request state
enum context_exit_state {
ctx_exit_not_requested, // exit not requested.
ctx_exit_pending, // exit requested.
ctx_exit_signaled, // exit request delivered.
};
// exit status
enum context_exit_status {
ctx_not_exited,
ctx_exited_return, // process exited by return.
ctx_exited_exit, // process exited by exit().
ctx_exited_abnormally // process exited uncleanly.
};
// Cause the coroutine to exit if
// a exit request is pending.
// Throws: exit_exception if an exit request is pending.
void check_exit_state() {
BOOST_ASSERT(running());
if(!m_exit_state) return;
throw exit_exception();
}
// Nothrow.
void do_return(context_exit_status status, std::type_info const* info) throw() {
BOOST_ASSERT(status != ctx_not_exited);
BOOST_ASSERT(m_state == ctx_running);
m_type_info = info;
m_state = ctx_exited;
m_exit_status = status;
do_yield();
}
private:
// Nothrow.
void do_yield() throw() {
swap_context(*this, m_caller, detail::yield_hint());
}
// Nothrow.
void do_invoke() throw (){
BOOST_ASSERT(ready() || waiting());
m_state = ctx_running;
swap_context(m_caller, *this, detail::invoke_hint());
}
template<typename ActualCtx>
static void deleter (const type* ctx){
delete static_cast<ActualCtx*>(const_cast<type*>(ctx));
}
typedef typename context_impl::context_impl_base ctx_type;
ctx_type m_caller;
mutable
#ifndef BOOST_COROUTINE_USE_ATOMIC_COUNT
std::size_t
#else
boost::detail::atomic_count
#endif
m_counter;
deleter_type * m_deleter;
context_state m_state;
context_exit_state m_exit_state;
context_exit_status m_exit_status;
int m_wait_counter;
int m_operation_counter;
// This is used to generate a meaningful exception trace.
std::type_info const* m_type_info;
};
} } }
#endif

View File

@@ -0,0 +1,285 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_CONTEXT_LINUX_HPP_20060601
#define BOOST_COROUTINE_CONTEXT_LINUX_HPP_20060601
#if defined(__GNUC__) && defined(__i386__) && !defined(BOOST_COROUTINE_NO_ASM)
#include <cstdlib>
#include <cstddef>
#include <boost/coroutine/detail/posix_utility.hpp>
#include <boost/coroutine/detail/swap_context.hpp>
#include <boost/assert.hpp>
/*
* Defining BOOST_COROUTINE_INLINE_ASM will enable the inlin3
* assembler verwsion of swapcontext_stack.
* The inline asm, with all required clobber flags, is usually no faster
* than the out-of-line function, and it is not yet clear if
* it is always reliable (i.e. if the compiler always saves the correct
* registers). FIXME: it is currently missing at least MMX and XMM registers in
* the clobber list.
*/
/*
* Defining BOOST_COROUTINE_NO_SEPARATE_CALL_SITES will disable separate
* invoke, yield and yield_to swap_context functions. Separate calls sites
* increase performance by 25% at least on P4 for invoke+yield back loops
* at the cost of a slightly higher instruction cache use and is thus enabled by
* default.
*/
//#define BOOST_COROUTINE_NO_SEPARATE_CALL_SITES
//#define BOOST_COROUTINE_INLINE_ASM
#ifndef BOOST_COROUTINE_INLINE_ASM
extern "C" void swapcontext_stack (void***, void**) throw() __attribute((regparm(2)));
extern "C" void swapcontext_stack2 (void***, void**) throw() __attribute((regparm(2)));
extern "C" void swapcontext_stack3 (void***, void**) throw() __attribute((regparm(2)));
#else
# if 1
void
inline
swapcontext_stack(void***from_sp, void**to_sp) throw() {
asm volatile
("\n\t pushl %%ebp"
"\n\t pushl %[from]"
"\n\t pushl %[to]"
"\n\t pushl $0f"
"\n\t movl %%esp, (%[from])"
"\n\t movl %[to], %%esp"
"\n\t popl %%ecx"
"\n\t jmp *%%ecx"
"\n0:\t popl %[to]"
"\n\t popl %[from]"
"\n\t popl %%ebp"
::
[from] "a" (from_sp),
[to] "d" (to_sp)
:
"cc",
"%ecx",
"%ebx",
"%edi",
"%esi",
"%st",
"%st(1)",
"%st(2)",
"%st(3)",
"%st(4)",
"%st(5)",
"%st(6)",
"%st(7)",
"memory"
);
}
# else
typedef void (*fun_type)(void***from_sp, void**to_sp)
__attribute((regparm(2)));
fun_type get_swapper();// __attribute__((pure));
inline
fun_type get_swapper(){
fun_type ptr;
asm volatile("mov $0f, %[result]"
"\n\t jmp 1f"
"\n0:"
//"\n\t movl 16(%%edx), %%ecx"
"\n\t pushl %%ebp"
"\n\t pushl %%ebx"
"\n\t pushl %%esi"
"\n\t pushl %%edi"
"\n\t movl %%esp, (%%eax)"
"\n\t movl %%edx, %%esp"
"\n\t popl %%edi"
"\n\t popl %%esi"
"\n\t popl %%ebx"
"\n\t popl %%ebp"
"\n\t popl %%ecx"
"\n\t jmp *%%ecx"
"\n1:"
:
[result] "=g" (ptr)
:
);
return ptr;
};
void
inline
swapcontext_stack(void***from_sp, void**to_sp) throw() {
fun_type ptr = get_swapper();
ptr(from_sp, to_sp);
}
# endif
void
inline
swapcontext_stack2(void***from_sp, void**to_sp) throw() {
swapcontext_stack(from_sp, to_sp);
}
#endif
namespace boost { namespace coroutines { namespace detail {
namespace oslinux {
template<typename T>
void trampoline(T* fun);
template<typename T>
inline
void
trampoline(T * fun) {
(*fun)();
std::abort();
}
class ia32_gcc_context_impl_base {
public:
ia32_gcc_context_impl_base() {};
void prefetch() const {
__builtin_prefetch (m_sp, 1, 3);
__builtin_prefetch (m_sp, 0, 3);
__builtin_prefetch ((void**)m_sp+64/4, 1, 3);
__builtin_prefetch ((void**)m_sp+64/4, 0, 3);
__builtin_prefetch ((void**)m_sp+32/4, 1, 3);
__builtin_prefetch ((void**)m_sp+32/4, 0, 3);
__builtin_prefetch ((void**)m_sp-32/4, 1, 3);
__builtin_prefetch ((void**)m_sp-32/4, 0, 3);
__builtin_prefetch ((void**)m_sp-64/4, 1, 3);
__builtin_prefetch ((void**)m_sp-64/4, 0, 3);
}
/**
* Free function. Saves the current context in @p from
* and restores the context in @p to.
* @note This function is found by ADL.
*/
friend
void
swap_context(ia32_gcc_context_impl_base& from,
ia32_gcc_context_impl_base const& to,
default_hint) {
to.prefetch();
swapcontext_stack(&from.m_sp, to.m_sp);
}
#ifndef BOOST_COROUTINE_NO_SEPARATE_CALL_SITES
friend
void
swap_context(ia32_gcc_context_impl_base& from,
ia32_gcc_context_impl_base const& to,
yield_hint) {
to.prefetch();
swapcontext_stack2(&from.m_sp, to.m_sp);
}
friend
void
swap_context(ia32_gcc_context_impl_base& from,
ia32_gcc_context_impl_base const& to,
yield_to_hint) {
to.prefetch();
swapcontext_stack2(&from.m_sp, to.m_sp);
}
#endif
protected:
void ** m_sp;
};
class ia32_gcc_context_impl : public ia32_gcc_context_impl_base{
public:
enum {default_stack_size = 64*1024};
typedef ia32_gcc_context_impl_base context_impl_base;
ia32_gcc_context_impl() :
m_stack(0) {}
/**
* Create a context that on restore invokes Functor on
* a new stack. The stack size can be optionally specified.
*/
template<typename Functor>
ia32_gcc_context_impl(Functor& cb, std::ptrdiff_t stack_size = -1) :
m_stack_size(stack_size == -1? default_stack_size: stack_size),
m_stack(posix::alloc_stack(m_stack_size)) {
m_sp = ((void**)m_stack + (m_stack_size/sizeof(void*))),
BOOST_ASSERT(m_stack);
typedef void fun(Functor*);
fun * funp = trampoline;
#ifndef BOOST_COROUTINE_INLINE_ASM
*--m_sp = &cb; // parm 0 of trampoline;
*--m_sp = 0; // dummy return address for trampoline
*--m_sp = (void*) funp ;// return addr (here: start addr) NOTE: the unsafe cast is safe on IA32
*--m_sp = 0; // ebp
*--m_sp = 0; // ebx
*--m_sp = 0; // esi
*--m_sp = 0; // edi
#else
*--m_sp = &cb; // parm 0 of trampoline;
*--m_sp = 0; // dummy return address for trampoline
*--m_sp = (void*) funp ;// return addr (here: start addr) NOTE: the unsafe cast is safe on IA32
#endif
}
~ia32_gcc_context_impl() {
if(m_stack)
posix::free_stack(m_stack, m_stack_size);
}
private:
std::ptrdiff_t m_stack_size;
void * m_stack;
};
typedef ia32_gcc_context_impl context_impl;
}
} } }
#elif defined(__linux)
/**
* For all other linux systems use the standard posix implementation.
*/
#include <boost/coroutine/detail/context_posix.hpp>
namespace boost { namespace coroutines { namespace detail { namespace oslinux {
typedef posix::context_impl context_impl;
} } } }
#else
#error This header can only be included when compiling for linux systems.
#endif
#endif

View File

@@ -0,0 +1,231 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_CONTEXT_POSIX_HPP_20060601
#define BOOST_COROUTINE_CONTEXT_POSIX_HPP_20060601
// NOTE (per http://lists.apple.com/archives/darwin-dev/2008/Jan/msg00232.html):
// > Why the bus error? What am I doing wrong?
// This is a known issue where getcontext(3) is writing past the end of the
// ucontext_t struct when _XOPEN_SOURCE is not defined (rdar://problem/5578699 ).
// As a workaround, define _XOPEN_SOURCE before including ucontext.h.
#if defined(__APPLE__) && ! defined(_XOPEN_SOURCE)
#define _XOPEN_SOURCE
// However, the above #define will only affect <ucontext.h> if it has not yet
// been #included by something else!
#if defined(_STRUCT_UCONTEXT)
#error You must #include coroutine headers before anything that #includes <ucontext.h>
#endif
#endif
#include <boost/config.hpp>
#include <boost/assert.hpp>
#if defined(_XOPEN_UNIX) && defined(_XOPEN_VERSION) && _XOPEN_VERSION >= 500
// OS X 10.4 -- despite passing the test above -- doesn't support
// swapcontext() et al. Use GNU Pth workalike functions.
#if defined(__APPLE__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1050)
#include "pth/pth.h"
#include <cerrno>
namespace boost { namespace coroutines { namespace detail {
namespace posix { namespace pth {
inline int check(int rc)
{
// The makecontext() functions return zero for success, nonzero for
// error. The Pth library returns TRUE for success, FALSE for error,
// with errno set to the nonzero error in the latter case. Map the Pth
// returns to ucontext style.
return rc? 0 : errno;
}
}}}}}
#define BOOST_CORO_POSIX_IMPL "Pth implementation"
#define BOOST_CORO_DECLARE_CONTEXT(name) pth_uctx_t name
#define BOOST_CORO_CREATE_CONTEXT(ctx) \
boost::coroutines::detail::posix::pth::check(pth_uctx_create(&(ctx)))
#define BOOST_CORO_MAKE_CONTEXT(ctx, stack, size, startfunc, startarg, exitto) \
/* const sigset_t* sigmask = NULL: we don't expect per-context signal masks */ \
boost::coroutines::detail::posix::pth::check(pth_uctx_make(*(ctx), static_cast<char*>(stack), (size), NULL, (startfunc), (startarg), (exitto)))
#define BOOST_CORO_SWAP_CONTEXT(from, to) \
boost::coroutines::detail::posix::pth::check(pth_uctx_switch(*(from), *(to)))
#define BOOST_CORO_DESTROY_CONTEXT(ctx) \
boost::coroutines::detail::posix::pth::check(pth_uctx_destroy(ctx))
#else // generic Posix platform (e.g. OS X >= 10.5)
/*
* makecontext based context implementation. Should be available on all
* SuSv2 compliant UNIX systems.
* NOTE: this implementation is not
* optimal as the makecontext API saves and restore the signal mask.
* This requires a system call for every context switch that really kills
* performance. Still is very portable and guaranteed to work.
* NOTE2: makecontext and friends are declared obsolescent in SuSv3, but
* it is unlikely that they will be removed any time soon.
*/
#include <ucontext.h>
#include <cstddef> // ptrdiff_t
namespace boost { namespace coroutines { namespace detail {
namespace posix { namespace ucontext {
inline int make_context(::ucontext_t* ctx, void* stack, std::ptrdiff_t size,
void (*startfunc)(void*), void* startarg, ::ucontext_t* exitto = NULL)
{
int error = ::getcontext(ctx);
if (error)
return error;
ctx->uc_stack.ss_sp = stack;
ctx->uc_stack.ss_size = size;
ctx->uc_link = exitto;
typedef void (*ctx_main)();
//makecontext can't fail.
::makecontext(ctx,
(ctx_main)(startfunc),
1,
startarg);
return 0;
}
}}}}}
#define BOOST_CORO_POSIX_IMPL "ucontext implementation"
#define BOOST_CORO_DECLARE_CONTEXT(name) ::ucontext_t name
#define BOOST_CORO_CREATE_CONTEXT(ctx) /* nop */
#define BOOST_CORO_MAKE_CONTEXT(ctx, stack, size, startfunc, startarg, exitto) \
boost::coroutines::detail::posix::ucontext::make_context(ctx, stack, size, startfunc, startarg, exitto)
#define BOOST_CORO_SWAP_CONTEXT(pfrom, pto) ::swapcontext((pfrom), (pto))
#define BOOST_CORO_DESTROY_CONTEXT(ctx) /* nop */
#endif // generic Posix platform
#include <signal.h> // SIGSTKSZ
#include <boost/noncopyable.hpp>
#include <boost/coroutine/exception.hpp>
#include <boost/coroutine/detail/posix_utility.hpp>
#include <boost/coroutine/detail/swap_context.hpp>
namespace boost { namespace coroutines { namespace detail {
namespace posix {
/*
* Posix implementation for the context_impl_base class.
* @note context_impl is not required to be consistent
* If not initialized it can only be swapped out, not in
* (at that point it will be initialized).
*
*/
class ucontext_context_impl_base {
public:
ucontext_context_impl_base()
{
BOOST_CORO_CREATE_CONTEXT(m_ctx);
}
~ucontext_context_impl_base()
{
BOOST_CORO_DESTROY_CONTEXT(m_ctx);
}
private:
/*
* Free function. Saves the current context in @p from
* and restores the context in @p to.
*/
friend
void
swap_context(ucontext_context_impl_base& from,
const ucontext_context_impl_base& to,
default_hint) {
int error = BOOST_CORO_SWAP_CONTEXT(&from.m_ctx, &to.m_ctx);
(void)error;
BOOST_ASSERT(error == 0);
}
protected:
BOOST_CORO_DECLARE_CONTEXT(m_ctx);
};
class ucontext_context_impl :
public ucontext_context_impl_base,
private boost::noncopyable {
public:
typedef ucontext_context_impl_base context_impl_base;
enum {default_stack_size = 64*1024};
/**
* Create a context that on restore invokes Functor on
* a new stack. The stack size can be optionally specified.
*/
template<typename Functor>
explicit
ucontext_context_impl(Functor& cb, std::ptrdiff_t stack_size) :
m_stack_size(stack_size == -1? default_stack_size: stack_size),
m_stack(alloc_stack(m_stack_size)) {
BOOST_ASSERT(m_stack);
typedef void cb_type(Functor*);
cb_type * cb_ptr = &trampoline<Functor>;
int error = BOOST_CORO_MAKE_CONTEXT(&m_ctx, m_stack, m_stack_size,
(void (*)(void*))(cb_ptr), &cb, NULL);
(void)error;
BOOST_ASSERT(error == 0);
}
~ucontext_context_impl() {
if(m_stack)
free_stack(m_stack, m_stack_size);
}
private:
// declare m_stack_size first so we can use it to initialize m_stack
std::ptrdiff_t m_stack_size;
void * m_stack;
};
typedef ucontext_context_impl context_impl;
}
} } }
#else
/**
* This #else clause is essentially unchanged from the original Google Summer
* of Code version of Boost.Coroutine, which comments:
* "Context swapping can be implemented on most posix systems lacking *context
* using the sigaltstack+longjmp trick."
* This is in fact what the (highly portable) Pth library does, so if you
* encounter such a system, perhaps the best approach would be to twiddle the
* #if logic in this header to use the pth.h implementation above.
*/
#error No context implementation for this POSIX system.
#endif
#endif

View File

@@ -0,0 +1,181 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_CONTEXT_WINDOWS_HPP_20060625
#define BOOST_COROUTINE_CONTEXT_WINDOWS_HPP_20060625
// This _WIN32_WINNT kludge is necessary to make winbase.h publish the Fiber API.
// 0x0400 makes CreateFiber(), etc., visible
// 0x0501 makes ConvertThreadToFiber() visible
// 0x0600 makes IsThreadAFiber() visible
// And no, I have no idea why this symbol isn't being set appropriately by
// the build environment.
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0600
// The above #define will only affect <windows.h> if it has not yet been
// #included by something else!
#if defined(WINBASEAPI)
#error You must #include coroutine headers before anything that #includes <windows.h>
#endif
#include <windows.h>
#include <winnt.h>
#include <boost/config.hpp>
#include <boost/assert.hpp>
#include <boost/noncopyable.hpp>
#include <boost/coroutine/exception.hpp>
#include <boost/coroutine/detail/swap_context.hpp>
namespace boost {namespace coroutines {namespace detail{
namespace windows {
typedef LPVOID fiber_ptr;
/*
* This number (0x1E00) has been sighted in the wild (at least on windows XP systems)
* as return value from GetCurrentFiber() on non fibrous threads. This is sowehow related
* to OS/2 where the current fiber pointer is overloaded as a version field.
* On non-NT systems, 0 is returned.
*/
const fiber_ptr fiber_magic = reinterpret_cast<fiber_ptr>(0x1E00);
/*
* Return true if current thread is a fiber.
* FIXME: on longhorn shoud use IsThreadAFiber
*/
inline
bool is_fiber() {
fiber_ptr current = GetCurrentFiber();
return current != 0 && current != fiber_magic;
}
/*
* Windows implementation for the context_impl_base class.
* @note context_impl is not required to be consistent
* If not initialized it can only be swapped out, not in
* (at that point it will be initialized).
*/
class fibers_context_impl_base {
public:
/**
* Create an empty context.
* An empty context cannot be restored from,
* but can be saved in.
*/
fibers_context_impl_base() :
m_ctx(0) {}
/*
* Free function. Saves the current context in @p from
* and restores the context in @p to. On windows the from
* parameter is ignored. The current context is saved on the
* current fiber.
* Note that if the current thread is not a fiber, it will be
* converted to fiber on the fly on call and unconverted before
* return. This is expensive. The user should convert the
* current thread to a fiber once on thread creation for better performance.
* Note that we can't leave the thread unconverted on return or else we
* will leak resources on thread destruction. Do the right thing by
* default.
*/
friend
void
swap_context(fibers_context_impl_base& from,
const fibers_context_impl_base& to,
default_hint) {
if(!is_fiber()) {
BOOST_ASSERT(from.m_ctx == 0);
from.m_ctx = ConvertThreadToFiber(0);
BOOST_ASSERT(from.m_ctx != 0);
SwitchToFiber(to.m_ctx);
BOOL result = ConvertFiberToThread();
BOOST_ASSERT(result);
(void)result;
from.m_ctx = 0;
} else {
bool call_from_main = from.m_ctx == 0;
if(call_from_main)
from.m_ctx = GetCurrentFiber();
SwitchToFiber(to.m_ctx);
if(call_from_main)
from.m_ctx = 0;
}
}
~fibers_context_impl_base() {}
protected:
explicit
fibers_context_impl_base(fiber_ptr ctx) :
m_ctx(ctx) {}
fiber_ptr m_ctx;
};
template<typename T>
inline
VOID CALLBACK
trampoline(LPVOID pv) {
T* fun = static_cast<T*>(pv);
BOOST_ASSERT(fun);
(*fun)();
}
class fibers_context_impl :
public fibers_context_impl_base,
private boost::noncopyable {
public:
typedef fibers_context_impl_base context_impl_base;
enum {default_stack_size = 64*1024};
/**
* Create a context that on restore inovkes Functor on
* a new stack. The stack size can be optionally specified.
*/
template<typename Functor>
explicit
fibers_context_impl(Functor& cb, std::ptrdiff_t stack_size) :
fibers_context_impl_base
(CreateFiber(stack_size== -1? 0 : stack_size,
static_cast<LPFIBER_START_ROUTINE>(&trampoline<Functor>),
static_cast<LPVOID>(&cb)))
{
BOOST_ASSERT(m_ctx);
}
~fibers_context_impl() {
DeleteFiber(m_ctx);
}
private:
};
typedef fibers_context_impl context_impl;
}
} } }
#endif

View File

@@ -0,0 +1,103 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_COROUTINE_ACCESSOR_HPP_20060709
#define BOOST_COROUTINE_DETAIL_COROUTINE_ACCESSOR_HPP_20060709
#include <boost/utility/in_place_factory.hpp>
namespace boost { namespace coroutines { namespace detail {
/*
* This is a private interface used for coroutine
* implementation.
*/
struct init_from_impl_tag{};
struct coroutine_accessor {
// Initialize coroutine from implementation type.
// used by the in_place_assing in place factory.
template<typename Coroutine, typename Ctx>
static
void construct(Ctx * src, void * address) {
new (address) Coroutine(src, init_from_impl_tag());
}
template<typename Coroutine>
static
void acquire(Coroutine& x) {
x.acquire();
}
template<typename Coroutine>
static
void release(Coroutine& x) {
x.release();
}
template<typename Ctx>
struct in_place_assign : boost::in_place_factory_base {
in_place_assign(Ctx * ctx) :
m_ctx(ctx) {}
template<typename Coroutine>
void apply(void * memory) const {
construct<Coroutine>(m_ctx, memory);
}
Ctx * m_ctx;
};
template<typename Ctx>
static
in_place_assign<Ctx>
in_place(Ctx * ctx) {
return in_place_assign<Ctx>(ctx);
}
template<typename Coroutine>
static
typename Coroutine::impl_ptr
get_impl(Coroutine& x) {
return x.get_impl();
}
template<typename Coroutine>
static
typename Coroutine::impl_type *
pilfer_impl(Coroutine& x) {
return x.pilfer_impl();
}
template<typename Coroutine>
static
std::size_t
count(const Coroutine& x) {
return x.count();
}
};
} } }
#endif

View File

@@ -0,0 +1,276 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_COROUTINE_IMPL_HPP_20060601
#define BOOST_COROUTINE_COROUTINE_IMPL_HPP_20060601
#if defined(_MSC_VER)
#pragma warning (push)
#pragma warning (disable: 4355) //this used in base member initializer
#endif
#include <cstddef>
#include <boost/optional.hpp>
#include <boost/coroutine/detail/argument_unpacker.hpp>
#include <boost/coroutine/detail/coroutine_accessor.hpp>
#include <boost/coroutine/detail/context_base.hpp>
namespace boost { namespace coroutines { namespace detail {
// This class augment the contest_base class with
// the coroutine signature type.
// This is mostly just a place to put
// typesafe argument and result type pointers.
template<typename CoroutineType, typename ContextImpl>
class coroutine_impl:
public context_base<ContextImpl>
{
public:
template<typename DerivedType, typename ResultType>
friend class add_result;
typedef ContextImpl context_impl;
typedef CoroutineType coroutine_type;
typedef coroutine_impl<coroutine_type, context_impl> type;
typedef context_base<context_impl> context_base;
typedef typename coroutine_type::arg_slot_type arg_slot_type;
typedef typename coroutine_type::result_type result_type;
typedef typename coroutine_type::result_slot_type result_slot_type;
typedef boost::intrusive_ptr<type> pointer;
template<typename DerivedType>
coroutine_impl(DerivedType * this_, std::ptrdiff_t stack_size) :
context_base(*this_, stack_size),
m_arg(0),
m_result(0){}
arg_slot_type * args() {
BOOST_ASSERT(m_arg);
return m_arg;
};
result_slot_type * result() {
BOOST_ASSERT(m_result);
BOOST_ASSERT(*m_result);
return *this->m_result;
}
template<typename Functor>
static inline
pointer create(Functor, std::ptrdiff_t);
void bind_args(arg_slot_type* arg) {
m_arg = arg;
}
void bind_result(result_slot_type* res) {
// This used to be unconditional. But m_result isn't always valid.
if (m_result) {
*m_result = res;
}
}
// Another level of indirecition is needed to handle
// yield_to correctly.
void bind_result_pointer(result_slot_type** resp) {
m_result = resp;
}
result_slot_type** result_pointer() {
return m_result;
}
/// This helper class packages data/logic originally found inline in
/// coroutine::call_impl() and call_impl_nothrow(), also
/// coroutine_impl::run().
class local_result_slot_ptr
{
public:
local_result_slot_ptr(pointer pimpl):
m_pimpl(pimpl),
m_ptr(NULL)
{
m_pimpl->bind_result_pointer(&m_ptr);
}
~local_result_slot_ptr()
{
// In the original use case, a coroutine could only be resumed by
// calling coroutine::operator() again, which would rebind the
// result pointer to a new valid value. But with the introduction
// of futures, it's possible to suspend a coroutine by waiting on
// a future object -- thus destroying the local result_slot_type*
// -- then resume that coroutine by calling the future's callback,
// bypassing coroutine::operator(). This used to leave an old,
// invalid result pointer in effect. Subsequent coroutine exit
// wrote through that pointer, munging a word of stack. Now we
// make a point of setting the bound result pointer NULL when the
// result_slot_type* to which it pointed vanishes, so that any
// attempt to dereference it will at least self-identify --
// instead of producing arbitrary undefined behavior.
m_pimpl->bind_result_pointer(NULL);
}
private:
pointer m_pimpl;
result_slot_type* m_ptr;
};
// This function must be called only for void
// coroutines. It wakes up the coroutine.
// Entering the wait state does not cause this
// method to throw.
void run() {
arg_slot_type void_args;
// This dummy binding is required because
// do_call expect args() and result()
// to return a non NULL result.
bind_args(&void_args);
local_result_slot_pointer(this);
this->wake_up();
}
protected:
boost::optional<result_slot_type> m_result_last;
private:
arg_slot_type * m_arg;
result_slot_type ** m_result;
};
// This type augment coroutine_impl type with the type of the stored
// functor. The type of this object is erased right after construction
// when it is assigned to a pointer to coroutine_impl. A deleter is
// passed down to make it sure that the correct derived type is deleted.
template<typename FunctorType, typename CoroutineType, typename ContextImpl>
class coroutine_impl_wrapper :
public coroutine_impl<CoroutineType, ContextImpl> {
public:
typedef coroutine_impl_wrapper<FunctorType, CoroutineType, ContextImpl>
type;
typedef CoroutineType coroutine_type;
typedef typename CoroutineType::result_type result_type;
typedef coroutine_impl<CoroutineType, ContextImpl> super_type;
typedef FunctorType functor_type;
coroutine_impl_wrapper(functor_type f, std::ptrdiff_t stack_size) :
super_type(this, stack_size),
m_fun(f){}
void operator()() {
typedef typename super_type::context_exit_status
context_exit_status;
context_exit_status status = super_type::ctx_exited_return;
std::type_info const* tinfo = 0;
try {
this->check_exit_state();
do_call<result_type>();
} catch (const exit_exception&) {
status = super_type::ctx_exited_exit;
} catch (std::exception const& e) {
status = super_type::ctx_exited_abnormally;
tinfo = &typeid(e);
} catch (...) {
status = super_type::ctx_exited_abnormally;
}
this->do_return(status, tinfo);
}
public:
//GCC workaround as per enable_if docs
template <int> struct dummy { dummy(int) {} };
/*
* Implementation for operator()
* This is for void result types.
* Can throw if m_fun throws. At least it can throw exit_exception.
*/
template<typename ResultType>
typename boost::enable_if<boost::is_void<ResultType> >::type
do_call(dummy<0> = 0) {
BOOST_ASSERT(this->count() > 0);
typedef BOOST_DEDUCED_TYPENAME
coroutine_type::self self_type;
boost::optional<self_type> self (coroutine_accessor::in_place(this));
detail::unpack_ex
(m_fun,
*self,
*this->args(),
detail::trait_tag<typename coroutine_type::arg_slot_traits>());
typedef BOOST_DEDUCED_TYPENAME coroutine_type::result_slot_type
result_slot_type;
// In this particulare case result_slot_type is guaranteed to be
// default constructible.
this->m_result_last = result_slot_type();
this->bind_result(&*this->m_result_last);
}
// Same as above, but for non void result types.
template<typename ResultType>
typename boost::disable_if<boost::is_void<ResultType> >::type
do_call(dummy<1> = 1) {
BOOST_ASSERT(this->count() > 0);
typedef BOOST_DEDUCED_TYPENAME
coroutine_type::self self_type;
boost::optional<self_type> self (coroutine_accessor::in_place(this));
typedef BOOST_DEDUCED_TYPENAME coroutine_type::arg_slot_traits traits;
typedef BOOST_DEDUCED_TYPENAME coroutine_type::result_slot_type
result_slot_type;
this->m_result_last = boost::in_place(result_slot_type(detail::unpack_ex
(m_fun,
*self,
*this->args(),
detail::trait_tag<traits>())));
this->bind_result(&*this->m_result_last);
}
FunctorType m_fun;
};
template<typename CoroutineType, typename ContextImpl>
template<typename Functor>
inline
typename
coroutine_impl<CoroutineType, ContextImpl>::pointer
coroutine_impl<CoroutineType, ContextImpl>::
create(Functor f, std::ptrdiff_t stack_size = default_stack_size) {
return new coroutine_impl_wrapper<Functor, CoroutineType, ContextImpl>
(f, stack_size);
}
} } }
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#endif

View File

@@ -0,0 +1,82 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_COROUTINE_TRAITS_HPP_20060613
#define BOOST_COROUTINE_DETAIL_COROUTINE_TRAITS_HPP_20060613
#include <boost/type_traits.hpp>
#include <boost/coroutine/tuple_traits.hpp>
#include <boost/coroutine/detail/yield_result_type.hpp>
namespace boost { namespace coroutines { namespace detail {
template<typename T>
struct as_tuple {
typedef typename T::as_tuple type;
};
// This trait class is used to compute
// all nested typedefs of coroutines given
// a signature in the form 'result_type(parm1, ... parmn)'.
template<typename Signature>
struct coroutine_traits {
private:
typedef BOOST_DEDUCED_TYPENAME boost::function_traits<Signature>::result_type
signature_result_type;
public:
typedef BOOST_DEDUCED_TYPENAME
boost::mpl::eval_if<is_tuple_traits<signature_result_type>,
as_tuple<signature_result_type>,
boost::mpl::identity<signature_result_type> >
::type result_type;
typedef BOOST_DEDUCED_TYPENAME
boost::mpl::eval_if<is_tuple_traits<signature_result_type>,
boost::mpl::identity<signature_result_type>,
boost::mpl::if_
<boost::is_same<signature_result_type, void>,
tuple_traits<>,
tuple_traits<signature_result_type> > >
::type result_slot_traits;
typedef BOOST_DEDUCED_TYPENAME result_slot_traits
::as_tuple result_slot_type;
typedef BOOST_DEDUCED_TYPENAME detail::make_tuple_traits
<typename detail::signature<Signature>::type >
::type arg_slot_traits;
typedef BOOST_DEDUCED_TYPENAME arg_slot_traits
::as_tuple arg_slot_type;
typedef BOOST_DEDUCED_TYPENAME arg_slot_traits
::as_result yield_result_type;
};
} } }
#endif

View File

@@ -0,0 +1,122 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DEFAULT_CONTEXT_IMPL_HPP_20060601
#define BOOST_COROUTINE_DEFAULT_CONTEXT_IMPL_HPP_20060601
#include <boost/config.hpp>
/*
ContextImpl concept documentation.
A ContextImpl holds a context plus its stack.
- ContextImpl must have constructor with the following signature:
template<typename Functor>
ContextImpl(Functor f, std::ptrdiff_t stack_size);
Preconditions:
f is a generic function object (support for function pointers
is not required.
stack_size is the size of the stack allocated
for the context. The stack_size is only an hint. If stack_size is -1
it should default to a sensible value.
Postconditions:
f is bound to this context in its own stack.
When the context is activated with swap_context for the first time
f is entered.
- ContextImpl destructor must properly dispose of the stack and perform
any other clean up action required.
- ContextImpl is not required to be DefaultConstructible nor Copyable.
- ContextImpl must expose the following typedef:
typedef unspecified-type context_impl_base;
ContextImpl must be convertible to context_impl_base.
context_impl_base must have conform to the ContextImplBase concept:
- DefaultConstructible. A default constructed ContextImplBase is in
an unitialized state.
A ContextImpl is an initialized ContextImplBase.
- ContextImplBase is Copyable. A copy of a ContextImplBase holds
The same informations as the original. Once a ContextImplBase
is used as an argument to swap_context, all its copies become stale.
(that is, only one copy of ContextImplBase can be used).
A ContextImpl cannot be sliced by copying it to a ContextImplBase.
- void swap_context(ContextImplBase& from,
const ContextImplBase& to)
This free function is called unqualified (via ADL).
Preconditions:
Its 'to' argument must be an initialized ContextImplBase.
Its 'from' argument may be an uninitialized ContextImplBase that
will be initialized by a swap_context.
Postconditions:
The current context is saved in the 'from' context, and the
'to' context is restored.
It is undefined behaviour if the 'to' argument is an invalid
(uninitialized) swapcontext.
A ContextImplBase is meant to be used when an empty temporary
context is needed to store the current context before
restoring a ContextImpl and no current context is
available. It could be possible to simply have ContextImpl
default constructible, but on destruciton it would need to
check if a stack has been allocated and would slow down the
fast invcation path. Also a stackful context could not be
make copiable.
*/
#if defined(__linux) || defined(linux) || defined(__linux__)
#include <boost/coroutine/detail/context_linux.hpp>
namespace boost { namespace coroutines { namespace detail {
typedef oslinux::context_impl default_context_impl;
} } }
#elif defined(_POSIX_VERSION)
#include <boost/coroutine/detail/context_posix.hpp>
namespace boost { namespace coroutines { namespace detail {
typedef posix::context_impl default_context_impl;
} } }
#elif defined(BOOST_WINDOWS)
#include <boost/coroutine/detail/context_windows.hpp>
namespace boost { namespace coroutines { namespace detail {
typedef windows::context_impl default_context_impl;
} } }
#else
#error No default_context_impl available for this system
#endif
#endif

View File

@@ -0,0 +1,61 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_FIX_RESULT_HPP_20060709
#define BOOST_COROUTINE_DETAIL_FIX_RESULT_HPP_20060709
#include <boost/utility/enable_if.hpp>
namespace boost { namespace coroutines { namespace detail {
template<typename Traits>
inline
void
fix_result(const typename Traits::as_tuple&,
typename
boost::enable_if_c<Traits::length == 0>::type * = 0){}
template<typename Traits>
inline
typename Traits::template at<0>::type
fix_result(const typename Traits::as_tuple& x,
typename
boost::enable_if_c<Traits::length == 1>::type * = 0){
using boost::get;
return get<0>(x);
}
template<typename Traits>
inline
typename Traits::as_tuple
fix_result(const typename Traits::as_tuple& x,
typename
boost::enable_if_c<(Traits::length > 1)>::type* =0){
return x;
}
} } }
#endif

View File

@@ -0,0 +1,140 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_FUTURE_IMPL_HPP_20060809
#define BOOST_COROUTINE_DETAIL_FUTURE_IMPL_HPP_20060809
#include <boost/optional.hpp>
#include <boost/assert.hpp>
#include <boost/optional.hpp>
#include <boost/noncopyable.hpp>
#include <boost/coroutine/detail/coroutine_accessor.hpp>
#include <boost/coroutine/detail/context_base.hpp>
namespace boost { namespace coroutines { namespace detail {
template<typename ValueType, typename ContextImpl>
class future_impl : boost::noncopyable {
public:
typedef ValueType value_type;
typedef
context_base<ContextImpl> *
context_weak_pointer;
typedef
BOOST_DEDUCED_TYPENAME
context_base<ContextImpl>::pointer
context_pointer;
typedef boost::optional<value_type> pointer;
template<typename CoroutineSelf>
future_impl(CoroutineSelf& self) :
m_coro_impl_weak(coroutine_accessor::get_impl(self)),
m_coro_impl(0),
m_waited(false)
{}
value_type&
value() {
return *m_optional;
}
value_type const&
value() const{
return *m_optional;
}
pointer&
get() {
return m_optional;
}
pointer const&
get() const{
return m_optional;
}
bool pending() {
return 0 != m_coro_impl.get();
}
template<typename T>
void assign(const T& val) {
BOOST_ASSERT(pending());
context_pointer p = m_coro_impl;
m_coro_impl = 0;
m_optional = val;
p->count_down();
if(waited() && p->signal())
p->wake_up();
}
void mark_pending() {
m_coro_impl = m_coro_impl_weak;
m_coro_impl ->count_up();
}
void mark_wait(bool how) {
m_waited = how;
}
bool waited() const {
return m_waited;
}
context_pointer context() {
BOOST_ASSERT(pending());
return m_coro_impl;
}
void wait(int n) {
m_coro_impl_weak->wait(n);
}
void wait() {
if(!pending()) return;
mark_wait(true);
try {
m_coro_impl->wait(1);
BOOST_ASSERT(!pending());
} catch (...) {
mark_wait(false);
throw;
}
mark_wait(false);
}
private:
context_weak_pointer m_coro_impl_weak;
context_pointer m_coro_impl;
bool m_waited;
boost::optional<value_type> m_optional;
};
} } }
#endif

View File

@@ -0,0 +1,84 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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)
// Copyright David Abrahams 2004. 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)
//
// Slightly modified for inclusion on coroutines/detail library.
#ifndef BOOST_COROUTINE_DETAIL_HAS_SWAP_HPP_20060709
#define BOOST_COROUTINE_DETAIL_HAS_SWAP_HPP_20060709
#include <boost/mpl/bool.hpp>
#include <boost/detail/workaround.hpp>
namespace boost { namespace coroutines {
namespace has_swap_
{
// any soaks up implicit conversions and makes the following
// operator++ less-preferred than any other such operator which
// might be found via ADL.
struct anything { template <class T> anything(T const&); };
struct no_swap
{
char (& operator,(char) )[2];
};
no_swap swap(anything,anything);
#if defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable: 4675) // function found through argument dependent lookup -- duh!
#endif
template <class T>
struct has_swap_impl
{
static T& x;
BOOST_STATIC_CONSTANT(bool, value = sizeof(swap(x,x),'x') == 1);
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
typedef boost::mpl::bool_<has_swap_impl<T>::value> type;
#else
typedef boost::mpl::bool_<value> type;
#endif
};
}
template <class T>
struct has_swap
: has_swap_::has_swap_impl<T>::type
{};
#if defined(BOOST_MSVC)
# pragma warning(pop)
#endif
} }
#endif // include guard

View File

@@ -0,0 +1,42 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_INDEX_HPP_20060613
#define BOOST_COROUTINE_DETAIL_INDEX_HPP_20060613
#include <boost/preprocessor/repetition.hpp>
#include <boost/coroutine/detail/arg_max.hpp>
namespace boost { namespace coroutines { namespace detail {
/*
* Workaround for BOOST_PP_ENUM_BINARY_PARAMS, where a token
* can't be createed by appending a number to a '<'.
* NOTE: we are really abusing BOOST_PP_ENUM_BINARY_PARAMS,
* Should simply use BOOST_PP_ENUM.
*/
enum {BOOST_PP_ENUM_PARAMS(BOOST_COROUTINE_ARG_MAX, index_)};
} } }
#endif

View File

@@ -0,0 +1,62 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_IS_CALLABLE_HPP_20060601
#define BOOST_COROUTINE_DETAIL_IS_CALLABLE_HPP_20060601
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>
#include <boost/mpl/logical.hpp>
#include <boost/mpl/has_xxx.hpp>
namespace boost { namespace coroutines { namespace detail {
template<typename T>
struct is_function_pointer :
boost::mpl::and_<
boost::is_pointer<T>,
boost::is_function<typename boost::remove_pointer<T>::type > > {
typedef is_function_pointer<T> type;
};
BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type);
BOOST_MPL_HAS_XXX_TRAIT_DEF(result);
template<typename T>
struct is_functor :
boost::mpl::or_<typename has_result_type<T>::type,
typename has_result<T>::type>
{
typedef is_functor<T> type;
};
template<typename T>
struct is_callable : boost::mpl::or_<
is_functor<T>,
is_function_pointer<T> >::type {
typedef is_callable<T> type;
};
} } }
#endif

View File

@@ -0,0 +1,67 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_MAKE_TUPLE_TRAITS_HPP_20060609
#define BOOST_COROUTINE_DETAIL_MAKE_TUPLE_TRAITS_HPP_20060609
#include <boost/preprocessor/repetition.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/coroutine/detail/arg_max.hpp>
#include <boost/coroutine/tuple_traits.hpp>
namespace boost { namespace coroutines { namespace detail {
/*
* Given a mpl::vector, returns a nullary metafunction
* describing a tuple of all types in the vector.
* NOTE this is just wrong because it should work for all mpl
* sequences, not just vectors. But it is in detail, so leave it
* as is. Eventually it will be replaced by Boost.Fusion.
* @p type is a tuple of all types in TypeList.
* TypeList is one of mpl::vector0, mpl::vector1, etc.
*/
template<typename TypeList>
struct make_tuple_traits;
#define BOOST_COROUTINE_MAKE_TUPLE_TRAITS_GENERATOR(z, n, unused) \
template<BOOST_PP_ENUM_PARAMS(n, class A)> \
struct make_tuple_traits<BOOST_PP_CAT(boost::mpl::vector, n) \
<BOOST_PP_ENUM_PARAMS(n, A)> >{ \
typedef tuple_traits<BOOST_PP_ENUM_PARAMS(n, A)> type; \
}; \
/**/
/**
* Generate specializations of make_tuple
* @note This could be done more elegantly with a recursive metafunction,
* but this is simpler and works well anyway.
*/
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_MAKE_TUPLE_TRAITS_GENERATOR, ~);
#undef BOOST_COROUTINE_MAKE_TUPLE_TRAITS_GENERATOR
} } }
#endif

View File

@@ -0,0 +1,68 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_NORETURN_HPP_20060812
#define BOOST_COROUTINE_DETAIL_NORETURN_HPP_20060812
/*
* The BOOST_COROUTINE_NORETURN macro provides a way to
* tell the compiler that a function will not return through
* the normal return path (it could return throgh a thrown exception).
* This not only provieds a possible optimization hint, but also
* prevents the compiler from complaining if a function that call
* a noreturn function does not call return itself.
*/
#include <boost/config.hpp>
#if defined(__GNUC__)
#if __GNUC_MAJOR__ > 3 || (__GNUC_MAJOR__ == 3 && __GNUC_MINOR__ > 3)
#define BOOST_COROUTINE_NORETURN(function) \
function __attribute__((__noreturn__)) \
/**/
#else // gcc 3.3
#define BOOST_COROUTINE_NORETURN(function) \
function
/**/
#endif // gcc 3.3
#elif defined (BOOST_MSVC)
#define BOOST_COROUTINE_NORETURN(function) \
__declspec(noreturn) function \
/**/
#else
//just for testing, remove the following error.
#error no default
#define BOOST_COROUTINE_NORETURN(function) \
function
/**/
#endif
#endif

View File

@@ -0,0 +1,161 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_POSIX_UTILITY_HPP_02012006
#define BOOST_COROUTINE_DETAIL_POSIX_UTILITY_HPP_02012006
#include <boost/config.hpp>
#if defined(_POSIX_VERSION)
/**
* Most of these utilities are really pure C++, but they are useful
* only on posix systems.
*/
#include <cerrno>
#include <cstddef>
#include <cstdlib>
#include <iostream>
#include <boost/type_traits.hpp>
#if defined(_POSIX_MAPPED_FILES) && _POSIX_MAPPED_FILES > 0
#include <sys/mman.h>
#endif
/**
* Stack allocation routines and trampolines for setcontext
*/
namespace boost { namespace coroutines { namespace detail { namespace posix {
#if defined(_POSIX_MAPPED_FILES) && _POSIX_MAPPED_FILES > 0
inline
void *
alloc_stack(std::size_t size) {
void * stack = ::mmap(NULL,
size,
PROT_EXEC|PROT_READ|PROT_WRITE,
#if defined(__APPLE__)
MAP_PRIVATE|MAP_ANON,
#else // ! __APPLE__
MAP_PRIVATE|MAP_ANONYMOUS,
#endif // ! __APPLE__
-1,
0
);
if(stack == MAP_FAILED) {
std::cerr <<strerror(errno)<<"\n";
abort();
}
return stack;
}
inline
void free_stack(void* stack, std::size_t size) {
::munmap(stack, size);
}
#else // non-mmap()
//this should be a fine default.
static const std::size_t stack_alignment = sizeof(void*) > 16? sizeof(void*): 16;
struct stack_aligner {
boost::type_with_alignment<stack_alignment>::type dummy;
};
/**
* Stack allocator and deleter functions.
* Better implementations are possible using
* mmap (might be required on some systems) and/or
* using a pooling allocator.
* NOTE: the SuSv3 documentation explictly allows
* the use of malloc to allocate stacks for makectx.
* We use free for guaranteed alignment.
*/
inline
void* alloc_stack(std::size_t size) {
return new stack_aligner[size/sizeof(stack_aligner)];
}
inline
void free_stack(void* stack, std::size_t size) {
delete [] static_cast<stack_aligner*>(stack);
}
#endif // non-mmap() implementation of alloc_stack()/free_stack()
/**
* The splitter is needed for 64 bit systems.
* @note The current implementation does NOT use
* (for debug reasons).
* Thus it is not 64 bit clean.
* Use it for 64 bits systems.
*/
template<typename T>
union splitter {
int int_[2];
T* ptr;
splitter(int first, int second) {
int_[0] = first;
int_[1] = second;
}
int first() {
return int_[0];
}
int second() {
return int_[1];
}
splitter(T* ptr) :ptr(ptr) {}
void operator()() {
(*ptr)();
}
};
template<typename T>
inline
void
trampoline_split(int first, int second) {
splitter<T> split(first, second);
split();
}
template<typename T>
inline
void
trampoline(T * fun) {
(*fun)();
}
}
} } }
#else
#error This header can only be included when compiling for posix systems.
#endif
#endif

View File

@@ -0,0 +1,274 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_SELF_HPP_20060809
#define BOOST_COROUTINE_DETAIL_SELF_HPP_20060809
#include <boost/noncopyable.hpp>
#include <boost/coroutine/detail/fix_result.hpp>
#include <boost/coroutine/detail/coroutine_accessor.hpp>
#include <boost/coroutine/detail/signal.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/coroutine/detail/noreturn.hpp>
namespace boost { namespace coroutines { namespace detail {
#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1400))
#define BOOST_COROUTINE_DEDUCED_TYPENAME_DEFAULT
#else
#define BOOST_COROUTINE_DEDUCED_TYPENAME_DEFAULT BOOST_DEDUCED_TYPENAME
#endif
#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1400))
#define BOOST_COROUTINE_VCPP80_WORKAROUND
#else
//for now, define this unconditionally for testing.
#define BOOST_COROUTINE_VCPP80_WORKAROUND
#endif
template<typename Coroutine>
class coroutine_self :boost::noncopyable {
public:
typedef Coroutine coroutine_type;
typedef coroutine_self<coroutine_type> type;
friend struct detail::coroutine_accessor;
typedef BOOST_DEDUCED_TYPENAME coroutine_type
::impl_type impl_type;
// Note, no reference counting here.
typedef impl_type * impl_ptr;
typedef BOOST_DEDUCED_TYPENAME coroutine_type
::result_type result_type;
typedef BOOST_DEDUCED_TYPENAME coroutine_type
::result_slot_type result_slot_type;
typedef BOOST_DEDUCED_TYPENAME coroutine_type
::yield_result_type yield_result_type;
typedef BOOST_DEDUCED_TYPENAME coroutine_type
::result_slot_traits result_slot_traits;
typedef BOOST_DEDUCED_TYPENAME coroutine_type
::arg_slot_type arg_slot_type;
typedef BOOST_DEDUCED_TYPENAME coroutine_type
::arg_slot_traits arg_slot_traits;
typedef BOOST_DEDUCED_TYPENAME coroutine_type
::yield_traits yield_traits;
#ifndef BOOST_COROUTINE_VCPP80_WORKAROUND
# define BOOST_COROUTINE_param_with_default(z, n, type_prefix) \
BOOST_DEDUCED_TYPENAME call_traits \
<BOOST_PP_CAT(BOOST_PP_CAT(type_prefix, n), _type)>::param_type \
BOOST_PP_CAT(arg, n) = \
BOOST_PP_CAT(BOOST_PP_CAT(type_prefix, n), _type)() \
/**/
yield_result_type yield
(BOOST_PP_ENUM
(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_param_with_default,
BOOST_DEDUCED_TYPENAME yield_traits::arg))
{
return yield_impl
(BOOST_DEDUCED_TYPENAME
coroutine_type::result_slot_type
(BOOST_PP_ENUM_PARAMS
(BOOST_COROUTINE_ARG_MAX,
arg)));
}
template<typename Target>
yield_result_type yield_to
(Target& target
BOOST_PP_ENUM_TRAILING
(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_param_with_default,
typename Target::arg))
{
typedef BOOST_DEDUCED_TYPENAME Target::arg_slot_type slot_type;
return yield_to_impl
(target, slot_type(BOOST_PP_ENUM_PARAMS
(BOOST_COROUTINE_ARG_MAX,
arg)));
}
#else
/*
* VC8.0 can't handle the call_traits meta-invocation inside
* a function parameter list (except when it does, see operator()).
* Splitting it in separate typedefs
* fixes the problem.
*/
#define BOOST_COROUTINE_param_typedef(z, n, prefix_tuple) \
typedef BOOST_DEDUCED_TYPENAME \
call_traits< \
BOOST_PP_CAT \
(BOOST_PP_CAT \
(BOOST_PP_TUPLE_ELEM(2, 0, prefix_tuple), n), \
_type) \
>::param_type \
BOOST_PP_CAT \
(BOOST_PP_CAT \
(BOOST_PP_TUPLE_ELEM(2, 1, prefix_tuple), n), \
_type) \
/**/;
/*
* Generate lines like this:
* 'typedef typename call_traits<typename coroutine_type::yield_traits::argN_type>::param_type yield_call_argN_type;'
*/
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_param_typedef,
(BOOST_DEDUCED_TYPENAME
coroutine_type::yield_traits::arg, yield_call_arg));
/*
* Generate lines like this:
* 'typedef typename call_traits<typename coroutine_type::argN_type>::param_type call_argN_type;'
*/
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_param_typedef,
(BOOST_DEDUCED_TYPENAME
coroutine_type::arg, call_arg));
#undef BOOST_COROUTINE_param_typedef
#undef BOOST_COROUTINE_param_with_default
#define BOOST_COROUTINE_param_with_default(z, n, prefix_tuple) \
BOOST_PP_CAT(BOOST_PP_CAT \
(BOOST_PP_TUPLE_ELEM(2, 0, prefix_tuple), \
n), _type) \
BOOST_PP_CAT(arg, n) = \
BOOST_PP_CAT(BOOST_PP_CAT \
(BOOST_PP_TUPLE_ELEM(2, 1, prefix_tuple), \
n), _type)() \
/**/
yield_result_type yield
(BOOST_PP_ENUM(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_param_with_default,
(yield_call_arg ,
BOOST_COROUTINE_DEDUCED_TYPENAME_DEFAULT
coroutine_type::yield_traits::arg)))
{
return yield_impl
(result_slot_type
(BOOST_PP_ENUM_PARAMS(BOOST_COROUTINE_ARG_MAX,arg)));
}
template<typename Target>
yield_result_type yield_to
(Target& target
BOOST_PP_ENUM_TRAILING
(BOOST_COROUTINE_ARG_MAX,
BOOST_COROUTINE_param_with_default,
(BOOST_DEDUCED_TYPENAME Target::self::call_arg,
BOOST_COROUTINE_DEDUCED_TYPENAME_DEFAULT Target::arg)))
{
typedef typename Target::arg_slot_type type;
return yield_to_impl
(target, type
(BOOST_PP_ENUM_PARAMS
(BOOST_COROUTINE_ARG_MAX, arg)));
}
#endif
#undef BOOST_COROUTINE_param_with_default
BOOST_COROUTINE_NORETURN(void exit()) {
m_pimpl -> exit_self();
abort();
}
yield_result_type result() {
return detail::fix_result<
BOOST_DEDUCED_TYPENAME
coroutine_type::arg_slot_traits>(*m_pimpl->args());
}
bool pending() const {
BOOST_ASSERT(m_pimpl);
return m_pimpl->pending();
}
/// @c true only if this @c self object was created by the passed @a coroutine
template <typename SomeCoroutine>
bool is_from(const SomeCoroutine& coroutine) const
{
// get_impl() only accepts non-const ref... a mistake, IMO.
return static_cast<void*>(coroutine_accessor::get_impl(const_cast<SomeCoroutine&>(coroutine)).get()) ==
static_cast<void*>(m_pimpl);
}
/// opaque token used to correlate this 'self' with its corresponding coroutine
void* get_id() const { return m_pimpl; }
private:
coroutine_self(impl_type * pimpl, detail::init_from_impl_tag) :
m_pimpl(pimpl) {}
yield_result_type yield_impl(BOOST_DEDUCED_TYPENAME
coroutine_type::result_slot_type result) {
typedef BOOST_DEDUCED_TYPENAME
coroutine_type::result_slot_type slot_type;
BOOST_ASSERT(m_pimpl);
this->m_pimpl->bind_result(&result);
this->m_pimpl->yield();
return detail::fix_result<
BOOST_DEDUCED_TYPENAME
coroutine_type::arg_slot_traits>(*m_pimpl->args());
}
template<typename TargetCoroutine>
yield_result_type yield_to_impl(TargetCoroutine& target,
BOOST_DEDUCED_TYPENAME TargetCoroutine
::arg_slot_type args) {
BOOST_ASSERT(m_pimpl);
coroutine_accessor::get_impl(target)->bind_args(&args);
coroutine_accessor::get_impl(target)->bind_result_pointer(m_pimpl->result_pointer());
this->m_pimpl->yield_to(*coroutine_accessor::get_impl(target));
return detail::fix_result<
BOOST_DEDUCED_TYPENAME
coroutine_type::arg_slot_traits>(*m_pimpl->args());
}
impl_ptr get_impl() {
return m_pimpl;
}
impl_ptr m_pimpl;
};
} } }
#endif

View File

@@ -0,0 +1,67 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_SIGNAL_HPP_20060728
#define BOOST_COROUTINE_DETAIL_SIGNAL_HPP_20060728
#include <boost/coroutine/detail/future_impl.hpp>
namespace boost { namespace coroutines { namespace detail {
/*
* Private interface for coroutine signaling/waiting.
* These class is friend of future_impl and
* its static members are invoked by asynchronous callback functions.
*/
struct wait_gateway {
template<typename Future>
static void wait(Future& f, int n) {
f.wait(n);
}
template<typename Future>
static
bool waited(const Future& f) {
return f.waited();
}
template<typename Future>
static
void mark_wait(Future& f, bool how) {
f.mark_wait(how);
}
template<typename Future>
static
BOOST_DEDUCED_TYPENAME
Future::impl_pointer
get_impl(Future& f) {
return f.m_ptr;
}
};
} } }
#endif

View File

@@ -0,0 +1,56 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_SIGNATURE_HPP_20060609
#define BOOST_COROUTINE_DETAIL_SIGNATURE_HPP_20060609
#include <boost/preprocessor/repetition.hpp>
#include <boost/coroutine/detail/arg_max.hpp>
namespace boost{ namespace coroutines{ namespace detail{
/*
* Derived from an mpl::vector describing
* 'Function' arguments types.
*/
template<typename Function>
struct signature;
/*
* Generate specializations for the signature trait class.
*/
#define BOOST_COROUTINE_SIGNATURE_GENERATOR(z, n, unused) \
template <class R BOOST_PP_ENUM_TRAILING_PARAMS(n, class A)> \
struct signature<R( BOOST_PP_ENUM_PARAMS(n,A) ) > \
: boost::mpl::BOOST_PP_CAT(vector,n)< \
BOOST_PP_ENUM_PARAMS(n,A) \
> {}; \
/**/
BOOST_PP_REPEAT(BOOST_COROUTINE_ARG_MAX, BOOST_COROUTINE_SIGNATURE_GENERATOR, ~);
#undef BOOST_COROUTINE_SIGNATURE_GENERATOR
} } }
#endif

View File

@@ -0,0 +1,38 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_SWAP_CONTEXT_HPP_20060611
#define BOOST_COROUTINE_SWAP_CONTEXT_HPP_20060611
namespace boost{ namespace coroutines { namespace detail {
class default_hint {};
class yield_hint: public default_hint {};
class yield_to_hint: public default_hint {};
class invoke_hint: public default_hint {};
} } }
#endif

View File

@@ -0,0 +1,102 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_WAIT_IMPL_HPP_20060728
#define BOOST_COROUTINE_DETAIL_WAIT_IMPL_HPP_20060728
#include <boost/tuple/tuple.hpp>
#include <boost/coroutine/detail/signal.hpp>
namespace boost { namespace coroutines { namespace detail {
/*
* Inokes mark_wait('how') on the 'Idx'th element of 't'
* then calls marker::wait<Idx-1> with the same arguments.
* returns the result of marker::wait<Idx-1>(...) plus 1 if
* the 'Idx'th.pending() is true or plus 0 otherwise.
*
*/
template<int Idx>
struct marker {
template<typename Tuple>
static int mark(Tuple& t, bool how) {
wait_gateway::mark_wait(t.template get<Idx-1>(), how);
return marker<Idx -1>::mark(t, how) + (t.template get<Idx-1>().pending()? 1:0);
}
};
/* Recursion terminator */
template<>
struct marker<0> {
template<typename Tuple>
static int mark(Tuple&, bool) { return 0;}
};
template<typename Tuple>
void wait_n(const Tuple& t, int n) {
BOOST_STATIC_ASSERT(boost::tuples::length<Tuple>::value);
wait_gateway::wait(t.get<0>(), n);
}
/*
* Wait for at least one future in 'wt' tuple to be signaled.
* If at least one future has been already signaled do not
* block but returns immediatley (prevents deadlocks).
*/
template<typename Tuple>
void wait_impl(Tuple wt) {
try {
if(marker<boost::tuples::length<Tuple>::value>::mark(wt, true) > 0)
wait_n(wt, 1);
} catch (...) {
marker<boost::tuples::length<Tuple>::value>::mark(wt, false);
throw;
}
int res = marker<boost::tuples::length<Tuple>::value>::mark(wt, false);
BOOST_ASSERT(res < boost::tuples::length<Tuple>::value);
(void)res;
}
/*
* Wait for all futures in 'wt' tuple to be signaled.
*/
template<typename Tuple>
void wait_all_impl(Tuple wt) {
int res = marker<boost::tuples::length<Tuple>::value>::mark(wt, true);
try {
wait_n(wt, res);
} catch (...) {
marker<boost::tuples::length<Tuple>::value>::mark(wt, false);
throw;
}
res = marker<boost::tuples::length<Tuple>::value>::mark(wt, false);
BOOST_ASSERT(res == 0);
}
} } }
#endif

View File

@@ -0,0 +1,54 @@
// Copyright (c) 2006, Giovanni P. Deretta
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_COROUTINE_DETAIL_YIELD_RESULT_TYPE_HPP_20060609
#define BOOST_COROUTINE_DETAIL_YIELD_RESULT_TYPE_HPP_20060609
#include <boost/coroutine/detail/make_tuple_traits.hpp>
#include <boost/mpl/vector.hpp>
namespace boost{ namespace coroutines { namespace detail {
/**
* Same as make_tuple_traits, but if
* @p TypeList is singular, @p type is the single element, and
* if TypeList is empty, @p type is @p void.
*/
template<typename TypeList>
struct yield_result_type {
typedef typename make_tuple_traits<TypeList>::type type;
};
template<typename T>
struct yield_result_type <boost::mpl::vector1<T> >{
typedef T type;
};
template<>
struct yield_result_type <boost::mpl::vector0<> >{
typedef void type;
};
} } }
#endif