diff --git a/example/Jamfile.v2 b/example/Jamfile.v2
index 3393bf4..9aa27af 100644
--- a/example/Jamfile.v2
+++ b/example/Jamfile.v2
@@ -69,18 +69,18 @@ exe same_fringe
     : same_fringe.cpp
     ;
 
-exe asio/stream_client
-    : asio/stream_client.cpp
-    ;
+#exe asio/stream_client
+#    : asio/stream_client.cpp
+#    ;
+#
+#exe asio/stream_server
+#    : asio/stream_server.cpp
+#    ;
 
-exe asio/stream_server
-    : asio/stream_server.cpp
-    ;
-
-#exe same_fringe
+#exe same_fringe11
 #    : c++11/same_fringe.cpp
 #    ;
 #
-#exe fibonacci
+#exe fibonacci11
 #    : c++11/fibonacci.cpp
 #    ;
diff --git a/example/c++11/fibonacci.cpp b/example/c++11/fibonacci.cpp
index 8c7a1e9..a8c20f4 100644
--- a/example/c++11/fibonacci.cpp
+++ b/example/c++11/fibonacci.cpp
@@ -9,6 +9,29 @@
 
 #include <boost/coroutine/all.hpp>
 
+#ifdef BOOST_COROUTINES_V2
+int main()
+{
+    boost::coroutines::pull_coroutine< int > c(
+        [&]( boost::coroutines::push_coroutine< int > & c) {
+            int first = 1, second = 1;
+            for ( int i = 0; i < 10; ++i)
+            {
+                int third = first + second;
+                first = second;
+                second = third;
+                c( third);
+            }
+        });
+
+    for ( auto i : c)
+        std::cout << i <<  " ";
+
+    std::cout << "\nDone" << std::endl;
+
+    return EXIT_SUCCESS;
+}
+#else
 int main()
 {
     boost::coroutines::coroutine< int() > c(
@@ -30,3 +53,4 @@ int main()
 
     return EXIT_SUCCESS;
 }
+#endif
diff --git a/example/c++11/same_fringe.cpp b/example/c++11/same_fringe.cpp
index a0c9908..47cd5e4 100644
--- a/example/c++11/same_fringe.cpp
+++ b/example/c++11/same_fringe.cpp
@@ -10,6 +10,71 @@
 
 #include "tree.h"
 
+node::ptr_t create_tree1()
+{
+    return branch::create(
+        leaf::create( "A"),
+        branch::create(
+            leaf::create( "B"),
+            leaf::create( "C") ) );
+}
+
+node::ptr_t create_tree2()
+{
+    return branch::create(
+        branch::create(
+            leaf::create( "A"),
+            leaf::create( "B") ),
+        leaf::create( "C") );
+}
+
+#ifdef BOOST_COROUTINES_V2
+class coro_visitor : public visitor
+{
+private:
+    boost::coroutines::push_coroutine< leaf& >   &   c_;
+
+public:
+    coro_visitor( boost::coroutines::push_coroutine< leaf& > & c) :
+        c_( c)
+    {}
+
+    void visit( branch & b)
+    {
+        if ( b.left) b.left->accept( * this);
+        if ( b.right) b.right->accept( * this);
+    }
+
+    void visit( leaf & l)
+    { c_( l); }
+};
+
+int main()
+{
+    node::ptr_t t1 = create_tree1();
+    boost::coroutines::pull_coroutine< leaf& > c1(
+        [&]( boost::coroutines::push_coroutine< leaf & > & c) {
+            coro_visitor v( c);
+            t1->accept( v);
+        });
+
+    node::ptr_t t2 = create_tree2();
+    boost::coroutines::pull_coroutine< leaf& > c2(
+        [&]( boost::coroutines::push_coroutine< leaf & > & c) {
+            coro_visitor v( c);
+            t2->accept( v);
+        });
+
+    bool result = std::equal(
+            boost::begin( c1),
+            boost::end( c1),
+            boost::begin( c2) );
+
+    std::cout << std::boolalpha << "same fringe == " << result << "\nDone" << std::endl;
+
+    return EXIT_SUCCESS;
+}
+#else
 class coro_visitor : public visitor
 {
 private:
@@ -30,24 +95,6 @@ public:
     { c_( l); }
 };
 
-node::ptr_t create_tree1()
-{
-    return branch::create(
-        leaf::create( "A"),
-        branch::create(
-            leaf::create( "B"),
-            leaf::create( "C") ) );
-}
-
-node::ptr_t create_tree2()
-{
-    return branch::create(
-        branch::create(
-            leaf::create( "A"),
-            leaf::create( "B") ),
-        leaf::create( "C") );
-}
-
 int main()
 {
     node::ptr_t t1 = create_tree1();
@@ -73,3 +120,4 @@ int main()
 
     return EXIT_SUCCESS;
 }
+#endif
diff --git a/example/echo.cpp b/example/echo.cpp
index 92b7b5e..1c48679 100644
--- a/example/echo.cpp
+++ b/example/echo.cpp
@@ -10,6 +10,43 @@
 #include <boost/bind.hpp>
 #include <boost/coroutine/all.hpp>
 
+#ifdef BOOST_COROUTINES_V2
+typedef boost::coroutines::pull_coroutine< void > pull_coro_t;
+typedef boost::coroutines::push_coroutine< void > push_coro_t;
+
+void echo( pull_coro_t & c, int i)
+{
+    std::cout << i;
+    c();
+}
+
+void runit( push_coro_t & ca)
+{
+    std::cout << "started! ";
+    for ( int i = 0; i < 10; ++i)
+    {
+        push_coro_t c( boost::bind( echo, _1, i) );
+        while ( c)
+            c();
+        ca();
+    }
+}
+
+int main( int argc, char * argv[])
+{
+    {
+        pull_coro_t c( runit);
+        while ( c) {
+            std::cout << "-";
+            c();
+        }
+    }
+
+    std::cout << "\nDone" << std::endl;
+
+    return EXIT_SUCCESS;
+}
+#else
 typedef boost::coroutines::coroutine< void() >   coro_t;
 
 void echo( coro_t & ca, int i)
@@ -44,3 +81,4 @@ int main( int argc, char * argv[])
 
     return EXIT_SUCCESS;
 }
+#endif
diff --git a/example/fibonacci.cpp b/example/fibonacci.cpp
index 41dff61..aad0c5a 100644
--- a/example/fibonacci.cpp
+++ b/example/fibonacci.cpp
@@ -10,7 +10,8 @@
 #include <boost/range.hpp>
 #include <boost/coroutine/all.hpp>
 
-void fibonacci( boost::coroutines::coroutine< void( int) > & c)
+#ifdef BOOST_COROUTINES_V2
+void fibonacci( boost::coroutines::push_coroutine< int > & c)
 {
     int first = 1, second = 1;
     while ( true)
@@ -22,6 +23,35 @@ void fibonacci( boost::coroutines::coroutine< void( int) > & c)
     }
 }
 
+int main()
+{
+    boost::coroutines::pull_coroutine< int > c( fibonacci);
+    boost::range_iterator<
+       boost::coroutines::pull_coroutine< int >
+    >::type   it( boost::begin( c) );
+    for ( int i = 0; i < 10; ++i)
+    {
+        std::cout << * it <<  " ";
+        ++it;
+    }
+
+    std::cout << "\nDone" << std::endl;
+
+    return EXIT_SUCCESS;
+}
+#else
+void fibonacci( boost::coroutines::coroutine< void( int) > & c)
+{
+    int first = 1, second = 1;
+    while ( true)
+    {
+        int third = first + second;
+        first = second;
+        second = third;
+        c( third);
+    }
+}
+
 int main()
 {
     boost::coroutines::coroutine< int() > c( fibonacci);
@@ -38,35 +68,4 @@ int main()
 
     return EXIT_SUCCESS;
 }
-
-// C++11
-#if 0
-int main()
-{
-    boost::coroutines::coroutine< int() > c(
-        [&]( boost::coroutines::coroutine< void( int) > & c) {
-            int first = 1, second = 1;
-            while ( true)
-            {
-                int third = first + second;
-                first = second;
-                second = third;
-                c( third);
-            }
-        });
-
-    boost::range_iterator<
-       boost::coroutines::coroutine< int() >
-    >::type   it( boost::begin( c) );
-
-    for ( int i = 0; i < 10; ++i)
-    {
-        std::cout << * it <<  " ";
-        ++it;
-    }
-
-    std::cout << "\nDone" << std::endl;
-
-    return EXIT_SUCCESS;
-}
 #endif
diff --git a/example/parallel.cpp b/example/parallel.cpp
index 1c1f683..5523940 100644
--- a/example/parallel.cpp
+++ b/example/parallel.cpp
@@ -10,6 +10,45 @@
 #include <boost/bind.hpp>
 #include <boost/coroutine/all.hpp>
 
+#ifdef BOOST_COROUTINES_V2
+void first( boost::coroutines::push_coroutine< void > & c)
+{
+    std::cout << "started first! ";
+    for ( int i = 0; i < 10; ++i)
+    {
+        c();
+        std::cout << "a" << i;
+    }
+}
+
+void second( boost::coroutines::push_coroutine< void > & c)
+{
+    std::cout << "started second! ";
+    for ( int i = 0; i < 10; ++i)
+    {
+        c();
+        std::cout << "b" << i;
+    }
+}
+
+int main( int argc, char * argv[])
+{
+    {
+        boost::coroutines::pull_coroutine< void > c1( boost::bind( first, _1) );
+        boost::coroutines::pull_coroutine< void > c2( boost::bind( second, _1) );
+        while ( c1 && c2) {
+            c1();
+            std::cout << " ";
+            c2();
+            std::cout << " ";
+        }
+    }
+
+    std::cout << "\nDone" << std::endl;
+
+    return EXIT_SUCCESS;
+}
+#else
 typedef boost::coroutines::coroutine< void() > coroutine_t;
 
 void first( coroutine_t::caller_type & self)
@@ -49,3 +88,4 @@ int main( int argc, char * argv[])
 
     return EXIT_SUCCESS;
 }
+#endif
diff --git a/example/power.cpp b/example/power.cpp
index 9800e64..dc495d5 100644
--- a/example/power.cpp
+++ b/example/power.cpp
@@ -12,6 +12,41 @@
 #include <boost/range.hpp>
 #include <boost/coroutine/all.hpp>
 
+#ifdef BOOST_COROUTINES_V2
+void power( boost::coroutines::push_coroutine< int > & c, int number, int exponent)
+{
+    int counter = 0;
+    int result = 1;
+    while ( counter++ < exponent)
+    {
+            result = result * number;
+            c( result);
+    }
+}
+
+int main()
+{
+    {
+        std::cout << "using range functions" << std::endl;
+        boost::coroutines::pull_coroutine< int > c( boost::bind( power, _1, 2, 8) );
+        boost::coroutines::pull_coroutine< int >::iterator e( boost::end( c) );
+        for ( boost::coroutines::pull_coroutine< int >::iterator i( boost::begin( c) );
+              i != e; ++i)
+            std::cout << * i <<  " ";
+    }
+
+    {
+        std::cout << "\nusing BOOST_FOREACH" << std::endl;
+        boost::coroutines::pull_coroutine< int > c( boost::bind( power, _1, 2, 8) );
+        BOOST_FOREACH( int i, c)
+        { std::cout << i <<  " "; }
+    }
+
+    std::cout << "\nDone" << std::endl;
+
+    return EXIT_SUCCESS;
+}
+#else
 typedef boost::coroutines::coroutine< int() >       coro1_t;
 typedef boost::coroutines::coroutine< void( int) >  coro2_t;
 typedef boost::range_iterator< coro1_t >::type      iterator_t;
@@ -48,45 +83,4 @@ int main()
 
     return EXIT_SUCCESS;
 }
-#if 0
-int main()
-{
-    {
-        std::cout << "using range functions" << std::endl;
-        boost::coroutines::coroutine< int() > c(
-            [&]( boost::coroutines::coroutine< void( int) > &c) {
-                int counter = 0;
-                int result = 1;
-                while ( counter++ < 8)
-                {
-                    result = result * 2;
-                    c( result);
-                }
-            });
-        iterator_t e( boost::end( c) );
-        for ( iterator_t i( boost::begin( c) ); i != e; ++i)
-            std::cout << * i <<  " ";
-    }
-
-    {
-        std::cout << "\nusing BOOST_FOREACH" << std::endl;
-        boost::coroutines::coroutine< int() > c(
-            [&]( boost::coroutines::coroutine< void( int) > &c) {
-                int counter = 0;
-                int result = 1;
-                while ( counter++ < 8)
-                {
-                    result = result * 2;
-                    c( result);
-                }
-            });
-        for ( int i : c) {
-            std::cout << i <<  " ";
-        }
-    }
-
-    std::cout << "\nDone" << std::endl;
-
-    return EXIT_SUCCESS;
-}
 #endif
diff --git a/example/same_fringe.cpp b/example/same_fringe.cpp
index 99172d4..0150a9c 100644
--- a/example/same_fringe.cpp
+++ b/example/same_fringe.cpp
@@ -15,15 +15,6 @@
 
 #include "tree.h"
 
-bool match_trees( coro_t & c1, coro_t & c2)
-{
-    typedef boost::range_iterator< coro_t >::type iterator_t;
-    iterator_t i1( boost::begin( c1) );
-    iterator_t e1( boost::end( c1) );
-    iterator_t i2( boost::begin( c2) );
-    return std::equal( i1, e1, i2);
-}
-
 std::pair< node::ptr_t, node::ptr_t > create_eq_trees()
 {
     branch::ptr_t tree1 = branch::create(
@@ -58,6 +49,48 @@ std::pair< node::ptr_t, node::ptr_t > create_diff_trees()
     return std::make_pair( tree1, tree2);
 }
 
+#ifdef BOOST_COROUTINES_V2
+bool match_trees( boost::coroutines::pull_coroutine< leaf & > & c1,
+                  boost::coroutines::pull_coroutine< leaf & > & c2)
+{
+    typedef boost::range_iterator< boost::coroutines::pull_coroutine< leaf & > >::type iterator_t;
+    iterator_t i1( boost::begin( c1) );
+    iterator_t e1( boost::end( c1) );
+    iterator_t i2( boost::begin( c2) );
+    return std::equal( i1, e1, i2);
+}
+
+int main()
+{
+    {
+        std::pair< node::ptr_t, node::ptr_t > pt = create_eq_trees();
+        boost::coroutines::pull_coroutine< leaf & > te1( boost::bind( enumerate_leafs, _1, pt.first) );
+        boost::coroutines::pull_coroutine< leaf & > te2( boost::bind( enumerate_leafs, _1, pt.second) );
+        bool result = match_trees( te1, te2);
+        std::cout << std::boolalpha << "eq. trees matched == " << result << std::endl;
+    }
+    {
+        std::pair< node::ptr_t, node::ptr_t > pt = create_diff_trees();
+        boost::coroutines::pull_coroutine< leaf & > te1( boost::bind( enumerate_leafs, _1, pt.first) );
+        boost::coroutines::pull_coroutine< leaf & > te2( boost::bind( enumerate_leafs, _1, pt.second) );
+        bool result = match_trees( te1, te2);
+        std::cout << std::boolalpha << "diff. trees matched == " << result << std::endl;
+    }
+
+    std::cout << "Done" << std::endl;
+
+    return EXIT_SUCCESS;
+}
+#else
+bool match_trees( coro_t & c1, coro_t & c2)
+{
+    typedef boost::range_iterator< coro_t >::type iterator_t;
+    iterator_t i1( boost::begin( c1) );
+    iterator_t e1( boost::end( c1) );
+    iterator_t i2( boost::begin( c2) );
+    return std::equal( i1, e1, i2);
+}
+
 int main()
 {
     {
@@ -79,3 +112,4 @@ int main()
 
     return EXIT_SUCCESS;
 }
+#endif
diff --git a/example/segmented_stack.cpp b/example/segmented_stack.cpp
index 4a3859a..6fc9af8 100644
--- a/example/segmented_stack.cpp
+++ b/example/segmented_stack.cpp
@@ -10,8 +10,6 @@
 #include <boost/coroutine/all.hpp>
 #include <boost/thread.hpp>
 
-typedef boost::coroutines::coroutine< void() >   coro_t;
-
 int count = 20;
 
 void access( char *buf) __attribute__ ((noinline));
@@ -19,6 +17,7 @@ void access( char *buf)
 {
   buf[0] = '\0';
 }
+
 void bar( int i)
 {
     char buf[4 * 1024];
@@ -31,6 +30,23 @@ void bar( int i)
     }
 }
 
+#ifdef BOOST_COROUTINES_V2
+void foo( boost::coroutines::pull_coroutine< void > & c)
+{
+    bar( count);
+    c();
+}
+
+void thread_fn()
+{
+    {
+        boost::coroutines::push_coroutine< void > c( foo);
+        c();
+    }
+}
+#else
+typedef boost::coroutines::coroutine< void() >   coro_t;
+
 void foo( coro_t & c)
 {
     bar( count);
@@ -42,9 +58,9 @@ void thread_fn()
     {
         coro_t c( foo);
         c();
-        int i = 7;
     }
 }
+#endif
 
 int main( int argc, char * argv[])
 {
diff --git a/example/tree.h b/example/tree.h
index f0c2187..39bb3c8 100644
--- a/example/tree.h
+++ b/example/tree.h
@@ -91,6 +91,33 @@ inline
 bool operator!=( leaf const& l, leaf  const& r)
 { return l.value != r.value; }
 
+#ifdef BOOST_COROUTINES_V2
+class tree_visitor : public visitor
+{
+private:
+    boost::coroutines::push_coroutine< leaf & >  &   c_;
+
+public:
+    tree_visitor( boost::coroutines::push_coroutine< leaf & > & c) :
+        c_( c)
+    {}
+
+    void visit( branch & b)
+    {
+        if ( b.left) b.left->accept( * this);
+        if ( b.right) b.right->accept( * this);
+    }
+
+    void visit( leaf & l)
+    { c_( l); }
+};
+
+void enumerate_leafs( boost::coroutines::push_coroutine< leaf & > & c, node::ptr_t root)
+{
+    tree_visitor v( c);
+    root->accept( v);
+}
+#else
 typedef boost::coroutines::coroutine< leaf&() > coro_t;
 
 class tree_visitor : public visitor
@@ -118,6 +145,7 @@ void enumerate_leafs( coro_t::caller_type & c, node::ptr_t root)
     tree_visitor v( c);
     root->accept( v);
 }
+#endif
 
 # if defined(BOOST_MSVC)
 # pragma warning(pop)
diff --git a/example/unwind.cpp b/example/unwind.cpp
index 32df2ab..4bcaa1d 100644
--- a/example/unwind.cpp
+++ b/example/unwind.cpp
@@ -10,6 +10,40 @@
 #include <boost/bind.hpp>
 #include <boost/coroutine/all.hpp>
 
+#ifdef BOOST_COROUTINES_V2
+struct X : private boost::noncopyable
+{
+    X() { std::cout << "X()" << std::endl; }
+    ~X() { std::cout << "~X()" << std::endl; }
+};
+
+void fn( boost::coroutines::push_coroutine< void > & c)
+{
+    X x;
+    int i = 0;
+    while ( true)
+    {
+        std::cout << "fn() : " << ++i << std::endl;
+        c();
+    }
+}
+
+int main( int argc, char * argv[])
+{
+    {
+        boost::coroutines::pull_coroutine< void > c( fn);
+        for ( int k = 0; k < 3; ++k)
+        {
+            c();
+        }
+        std::cout << "destroying coroutine and unwinding stack" << std::endl;
+    }
+
+    std::cout << "\nDone" << std::endl;
+
+    return EXIT_SUCCESS;
+}
+#else
 typedef boost::coroutines::coroutine< void() >   coro_t;
 
 struct X : private boost::noncopyable
@@ -44,3 +78,4 @@ int main( int argc, char * argv[])
 
     return EXIT_SUCCESS;
 }
+#endif
diff --git a/include/boost/coroutine/detail/config.hpp b/include/boost/coroutine/detail/config.hpp
index 0452730..6d6860a 100644
--- a/include/boost/coroutine/detail/config.hpp
+++ b/include/boost/coroutine/detail/config.hpp
@@ -46,8 +46,8 @@
 # define BOOST_COROUTINES_SEGMENTS 10
 #endif
 
-//#ifndef BOOST_COROUTINES_V1
-//# define BOOST_COROUTINES_V2
-//#endif
+#ifndef BOOST_COROUTINES_V1
+# define BOOST_COROUTINES_V2
+#endif
 
 #endif // BOOST_COROUTINES_DETAIL_CONFIG_H
diff --git a/include/boost/coroutine/detail/exceptions.hpp b/include/boost/coroutine/detail/exceptions.hpp
index 39f3854..4b92872 100644
--- a/include/boost/coroutine/detail/exceptions.hpp
+++ b/include/boost/coroutine/detail/exceptions.hpp
@@ -4,8 +4,8 @@
 //    (See accompanying file LICENSE_1_0.txt or copy at
 //          http://www.boost.org/LICENSE_1_0.txt)
 
-#ifndef BOOST_COROUTINES_DETAIL_EXCEPTIONs_H
-#define BOOST_COROUTINES_DETAIL_EXCEPTIONs_H
+#ifndef BOOST_COROUTINES_DETAIL_EXCEPTIONS_H
+#define BOOST_COROUTINES_DETAIL_EXCEPTIONS_H
 
 #include <boost/config.hpp>
 
@@ -25,4 +25,4 @@ struct forced_unwind {};
 #  include BOOST_ABI_SUFFIX
 #endif
 
-#endif // BOOST_COROUTINES_DETAIL_EXCEPTIONs_H
+#endif // BOOST_COROUTINES_DETAIL_EXCEPTIONS_H
diff --git a/include/boost/coroutine/detail/stack_tuple.hpp b/include/boost/coroutine/detail/stack_tuple.hpp
new file mode 100644
index 0000000..80935cb
--- /dev/null
+++ b/include/boost/coroutine/detail/stack_tuple.hpp
@@ -0,0 +1,47 @@
+
+//          Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_DETAIL_STACK_TUPLE_H
+#define BOOST_COROUTINES_DETAIL_STACK_TUPLE_H
+
+#include <cstddef>
+
+#include <boost/config.hpp>
+
+#include <boost/coroutine/detail/config.hpp>
+#include <boost/coroutine/stack_context.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+template< typename StackAllocator >
+struct stack_tuple
+{
+    coroutines::stack_context   stack_ctx;
+    StackAllocator              stack_alloc;
+
+    stack_tuple( StackAllocator const& stack_alloc_, std::size_t size) :
+        stack_ctx(),
+        stack_alloc( stack_alloc_)
+    { stack_alloc.allocate( stack_ctx, size); }
+
+    ~stack_tuple()
+    { stack_alloc.deallocate( stack_ctx); }
+};
+
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_DETAIL_STACK_TUPLE_H
diff --git a/include/boost/coroutine/detail/trampoline.hpp b/include/boost/coroutine/detail/trampoline.hpp
new file mode 100644
index 0000000..2c8088f
--- /dev/null
+++ b/include/boost/coroutine/detail/trampoline.hpp
@@ -0,0 +1,52 @@
+
+//          Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_DETAIL_TRAMPOLINE_H
+#define BOOST_COROUTINES_DETAIL_TRAMPOLINE_H
+
+#include <cstddef>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/tuple/tuple.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+template< typename Coroutine >
+void trampoline1( intptr_t vp)
+{
+    BOOST_ASSERT( vp);
+
+    reinterpret_cast< Coroutine * >( vp)->run();
+}
+
+template< typename Coroutine, typename Arg >
+void trampoline2( intptr_t vp)
+{
+    BOOST_ASSERT( vp);
+
+    tuple< Coroutine *, Arg > * tpl(
+        reinterpret_cast< tuple< Coroutine *, Arg > * >( vp) );
+    Coroutine * coro( get< 0 >( * tpl) );
+    Arg arg( get< 1 >( * tpl) );
+
+    coro->run( arg);
+}
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_DETAIL_TRAMPOLINE_H
diff --git a/include/boost/coroutine/v1/detail/coroutine_object.hpp b/include/boost/coroutine/v1/detail/coroutine_object.hpp
index 6e8978a..17ef4d4 100644
--- a/include/boost/coroutine/v1/detail/coroutine_object.hpp
+++ b/include/boost/coroutine/v1/detail/coroutine_object.hpp
@@ -25,8 +25,11 @@
 #include <boost/coroutine/detail/flags.hpp>
 #include <boost/coroutine/detail/holder.hpp>
 #include <boost/coroutine/detail/param.hpp>
+#include <boost/coroutine/detail/stack_tuple.hpp>
+#include <boost/coroutine/detail/trampoline.hpp>
 #include <boost/coroutine/flags.hpp>
 #include <boost/coroutine/stack_context.hpp>
+#include <boost/coroutine/stack_context.hpp>
 #include <boost/coroutine/v1/detail/arg.hpp>
 #include <boost/coroutine/v1/detail/coroutine_base.hpp>
 
@@ -43,46 +46,6 @@ namespace boost {
 namespace coroutines {
 namespace detail {
 
-template< typename Coroutine >
-void trampoline1( intptr_t vp)
-{
-    BOOST_ASSERT( vp);
-
-    reinterpret_cast< Coroutine * >( vp)->run();
-}
-
-template< typename Coroutine, typename Arg >
-void trampoline2( intptr_t vp)
-{
-    BOOST_ASSERT( vp);
-
-    tuple< Coroutine *, Arg > * tpl(
-        reinterpret_cast< tuple< Coroutine *, Arg > * >( vp) );
-    Coroutine * coro( get< 0 >( * tpl) );
-    Arg arg( get< 1 >( * tpl) );
-
-    coro->run( arg);
-}
-
-template< typename StackAllocator >
-struct stack_tuple
-{
-    coroutines::stack_context   stack_ctx;
-    StackAllocator              stack_alloc;
-
-    stack_tuple( StackAllocator const& stack_alloc_, std::size_t size) :
-        stack_ctx(),
-        stack_alloc( stack_alloc_)
-    {
-        stack_alloc.allocate( stack_ctx, size);
-    }
-
-    ~stack_tuple()
-    {
-        stack_alloc.deallocate( stack_ctx);
-    }
-};
-
 template<
     typename Signature,
     typename Fn, typename StackAllocator, typename Allocator,
diff --git a/include/boost/coroutine/v2/coroutine.hpp b/include/boost/coroutine/v2/coroutine.hpp
new file mode 100644
index 0000000..691f927
--- /dev/null
+++ b/include/boost/coroutine/v2/coroutine.hpp
@@ -0,0 +1,2428 @@
+
+//          Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_V2_COROUTINE_H
+#define BOOST_COROUTINES_V2_COROUTINE_H
+
+#include <cstddef>
+#include <iterator>
+#include <memory>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/move/move.hpp>
+#include <boost/optional.hpp>
+#include <boost/range.hpp>
+#include <boost/type_traits/decay.hpp>
+#include <boost/type_traits/function_traits.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/utility/enable_if.hpp>
+
+#include <boost/coroutine/attributes.hpp>
+#include <boost/coroutine/detail/config.hpp>
+#include <boost/coroutine/detail/coroutine_context.hpp>
+#include <boost/coroutine/detail/param.hpp>
+#include <boost/coroutine/stack_allocator.hpp>
+#include <boost/coroutine/v2/detail/pull_coroutine_base.hpp>
+#include <boost/coroutine/v2/detail/pull_coroutine_caller.hpp>
+#include <boost/coroutine/v2/detail/pull_coroutine_object.hpp>
+#include <boost/coroutine/v2/detail/push_coroutine_base.hpp>
+#include <boost/coroutine/v2/detail/push_coroutine_caller.hpp>
+#include <boost/coroutine/v2/detail/push_coroutine_object.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+
+template< typename Arg >
+class push_coroutine
+{
+private:
+    template<
+        typename X, typename Y, typename Z, typename V, typename W
+    >
+    friend class detail::pull_coroutine_object;
+
+    typedef detail::push_coroutine_base< Arg >  base_t;
+    typedef typename base_t::ptr_t              ptr_t;
+
+    struct dummy
+    { void nonnull() {} };
+
+    typedef void ( dummy::*safe_bool)();
+
+    ptr_t  impl_;
+
+    BOOST_MOVABLE_BUT_NOT_COPYABLE( push_coroutine)
+
+    template< typename Allocator >
+    push_coroutine( detail::coroutine_context const& callee,
+                    bool unwind, bool preserve_fpu,
+                    Allocator const& alloc) :
+        impl_()
+    {
+        typedef detail::push_coroutine_caller<
+                Arg, Allocator
+        >                               caller_t;
+        typename caller_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) caller_t(
+                callee, unwind, preserve_fpu, a) );
+    }
+
+public:
+    push_coroutine() BOOST_NOEXCEPT :
+        impl_()
+    {}
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+    template< typename Fn >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+#else
+    template< typename Fn >
+    explicit push_coroutine( Fn fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator >
+    explicit push_coroutine( Fn fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit push_coroutine( Fn fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+#endif
+
+    push_coroutine( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT :
+        impl_()
+    { swap( other); }
+
+    push_coroutine & operator=( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT
+    {
+        push_coroutine tmp( boost::move( other) );
+        swap( tmp);
+        return * this;
+    }
+
+    bool empty() const BOOST_NOEXCEPT
+    { return ! impl_; }
+
+    operator safe_bool() const BOOST_NOEXCEPT
+    { return ( empty() || impl_->is_complete() ) ? 0 : & dummy::nonnull; }
+
+    bool operator!() const BOOST_NOEXCEPT
+    { return empty() || impl_->is_complete(); }
+
+    void swap( push_coroutine & other) BOOST_NOEXCEPT
+    { impl_.swap( other.impl_); }
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+    push_coroutine & operator()( Arg const& arg)
+    {
+        BOOST_ASSERT( * this);
+
+        impl_->push( arg);
+        return * this;
+    }
+
+    push_coroutine & operator()( Arg && arg) {
+        BOOST_ASSERT( * this);
+
+        impl_->push( arg);
+        return * this;
+    }
+#else
+    push_coroutine & operator()( Arg arg)
+    {
+        BOOST_ASSERT( * this);
+
+        impl_->push( forward< Arg >( arg) );
+        return * this;
+    }
+
+    push_coroutine & operator()( BOOST_RV_REF( Arg) arg)
+    {
+        BOOST_ASSERT( * this);
+
+        impl_->push( forward< Arg >( arg) );
+        return * this;
+    }
+#endif
+
+    class iterator : public std::iterator< std::output_iterator_tag, void, void, void, void >
+    {
+    private:
+       push_coroutine< Arg >    *   c_;
+
+    public:
+        iterator() :
+           c_( 0)
+        {}
+
+        explicit iterator( push_coroutine< Arg > * c) :
+            c_( c)
+        {}
+
+        iterator & operator=( Arg a)
+        {
+            BOOST_ASSERT( c_);
+            if ( ! ( * c_)( a) ) c_ = 0;
+            return * this;
+        }
+
+        bool operator==( iterator const& other)
+        { return other.c_ == c_; }
+
+        bool operator!=( iterator const& other)
+        { return other.c_ != c_; }
+
+        iterator & operator*()
+        { return * this; }
+
+        iterator & operator++()
+        { return * this; }
+    };
+
+    struct const_iterator;
+};
+
+template< typename Arg >
+class push_coroutine< Arg & >
+{
+private:
+    template<
+        typename X, typename Y, typename Z, typename V, typename W
+    >
+    friend class detail::pull_coroutine_object;
+
+    typedef detail::push_coroutine_base< Arg & >    base_t;
+    typedef typename base_t::ptr_t                  ptr_t;
+
+    struct dummy
+    { void nonnull() {} };
+
+    typedef void ( dummy::*safe_bool)();
+
+    ptr_t  impl_;
+
+    BOOST_MOVABLE_BUT_NOT_COPYABLE( push_coroutine)
+
+    template< typename Allocator >
+    push_coroutine( detail::coroutine_context const& callee,
+                    bool unwind, bool preserve_fpu,
+                    Allocator const& alloc) :
+        impl_()
+    {
+        typedef detail::push_coroutine_caller<
+                Arg &, Allocator
+        >                               caller_t;
+        typename caller_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) caller_t(
+                callee, unwind, preserve_fpu, a) );
+    }
+
+public:
+    push_coroutine() BOOST_NOEXCEPT :
+        impl_()
+    {}
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+    template< typename Fn >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+#else
+    template< typename Fn >
+    explicit push_coroutine( Fn fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator >
+    explicit push_coroutine( Fn fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit push_coroutine( Fn fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+#endif
+
+    push_coroutine( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT :
+        impl_()
+    { swap( other); }
+
+    push_coroutine & operator=( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT
+    {
+        push_coroutine tmp( boost::move( other) );
+        swap( tmp);
+        return * this;
+    }
+
+    bool empty() const BOOST_NOEXCEPT
+    { return ! impl_; }
+
+    operator safe_bool() const BOOST_NOEXCEPT
+    { return ( empty() || impl_->is_complete() ) ? 0 : & dummy::nonnull; }
+
+    bool operator!() const BOOST_NOEXCEPT
+    { return empty() || impl_->is_complete(); }
+
+    void swap( push_coroutine & other) BOOST_NOEXCEPT
+    { impl_.swap( other.impl_); }
+
+    push_coroutine & operator()( Arg & arg)
+    {
+        BOOST_ASSERT( * this);
+
+        impl_->push( forward< Arg & >( arg) );
+        return * this;
+    }
+
+    class iterator : public std::iterator< std::output_iterator_tag, void, void, void, void >
+    {
+    private:
+       push_coroutine< Arg & >    *   c_;
+
+    public:
+        iterator() :
+           c_( 0)
+        {}
+
+        explicit iterator( push_coroutine< Arg & > * c) :
+            c_( c)
+        {}
+
+        iterator & operator=( Arg & a)
+        {
+            BOOST_ASSERT( c_);
+            if ( ! ( * c_)( a) ) c_ = 0;
+            return * this;
+        }
+
+        bool operator==( iterator const& other)
+        { return other.c_ == c_; }
+
+        bool operator!=( iterator const& other)
+        { return other.c_ != c_; }
+
+        iterator & operator*()
+        { return * this; }
+
+        iterator & operator++()
+        { return * this; }
+    };
+
+    struct const_iterator;
+};
+
+template< typename Arg >
+class push_coroutine< Arg const& >
+{
+private:
+    template<
+        typename X, typename Y, typename Z, typename V, typename W
+    >
+    friend class detail::pull_coroutine_object;
+
+    typedef detail::push_coroutine_base< Arg const& >    base_t;
+    typedef typename base_t::ptr_t                  ptr_t;
+
+    struct dummy
+    { void nonnull() {} };
+
+    typedef void ( dummy::*safe_bool)();
+
+    ptr_t  impl_;
+
+    BOOST_MOVABLE_BUT_NOT_COPYABLE( push_coroutine)
+
+    template< typename Allocator >
+    push_coroutine( detail::coroutine_context const& callee,
+                    bool unwind, bool preserve_fpu,
+                    Allocator const& alloc) :
+        impl_()
+    {
+        typedef detail::push_coroutine_caller<
+                Arg const&, Allocator
+        >                               caller_t;
+        typename caller_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) caller_t(
+                callee, unwind, preserve_fpu, a) );
+    }
+
+public:
+    push_coroutine() BOOST_NOEXCEPT :
+        impl_()
+    {}
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+    template< typename Fn >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+#else
+    template< typename Fn >
+    explicit push_coroutine( Fn fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator >
+    explicit push_coroutine( Fn fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit push_coroutine( Fn fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+#endif
+
+    push_coroutine( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT :
+        impl_()
+    { swap( other); }
+
+    push_coroutine & operator=( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT
+    {
+        push_coroutine tmp( boost::move( other) );
+        swap( tmp);
+        return * this;
+    }
+
+    bool empty() const BOOST_NOEXCEPT
+    { return ! impl_; }
+
+    operator safe_bool() const BOOST_NOEXCEPT
+    { return ( empty() || impl_->is_complete() ) ? 0 : & dummy::nonnull; }
+
+    bool operator!() const BOOST_NOEXCEPT
+    { return empty() || impl_->is_complete(); }
+
+    void swap( push_coroutine & other) BOOST_NOEXCEPT
+    { impl_.swap( other.impl_); }
+
+    push_coroutine & operator()( Arg const& arg)
+    {
+        BOOST_ASSERT( * this);
+
+        impl_->push( forward< Arg const& >( arg) );
+        return * this;
+    }
+
+    class iterator : public std::iterator< std::output_iterator_tag, void, void, void, void >
+    {
+    private:
+       push_coroutine< Arg const& >    *   c_;
+
+    public:
+        iterator() :
+           c_( 0)
+        {}
+
+        explicit iterator( push_coroutine< Arg const& > * c) :
+            c_( c)
+        {}
+
+        iterator & operator=( Arg const& a)
+        {
+            BOOST_ASSERT( c_);
+            if ( ! ( * c_)( a) ) c_ = 0;
+            return * this;
+        }
+
+        bool operator==( iterator const& other)
+        { return other.c_ == c_; }
+
+        bool operator!=( iterator const& other)
+        { return other.c_ != c_; }
+
+        iterator & operator*()
+        { return * this; }
+
+        iterator & operator++()
+        { return * this; }
+    };
+
+    struct const_iterator;
+};
+
+template<>
+class push_coroutine< void >
+{
+private:
+    template<
+        typename X, typename Y, typename Z, typename V, typename W
+    >
+    friend class detail::pull_coroutine_object;
+
+    typedef detail::push_coroutine_base< void >  base_t;
+    typedef typename base_t::ptr_t              ptr_t;
+
+    struct dummy
+    { void nonnull() {} };
+
+    typedef void ( dummy::*safe_bool)();
+
+    ptr_t  impl_;
+
+    BOOST_MOVABLE_BUT_NOT_COPYABLE( push_coroutine)
+
+    template< typename Allocator >
+    push_coroutine( detail::coroutine_context const& callee,
+                    bool unwind, bool preserve_fpu,
+                    Allocator const& alloc) :
+        impl_()
+    {
+        typedef detail::push_coroutine_caller<
+                void, Allocator
+        >                               caller_t;
+        typename caller_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) caller_t(
+                callee, unwind, preserve_fpu, a) );
+    }
+
+public:
+    push_coroutine() BOOST_NOEXCEPT :
+        impl_()
+    {}
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+    template< typename Fn >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+#else
+    template< typename Fn >
+    explicit push_coroutine( Fn fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator >
+    explicit push_coroutine( Fn fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit push_coroutine( Fn fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< push_coroutine > const& alloc =
+                    std::allocator< push_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, push_coroutine >,
+                   dummy *
+               >::type = 0);
+#endif
+
+    push_coroutine( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT :
+        impl_()
+    { swap( other); }
+
+    push_coroutine & operator=( BOOST_RV_REF( push_coroutine) other) BOOST_NOEXCEPT
+    {
+        push_coroutine tmp( boost::move( other) );
+        swap( tmp);
+        return * this;
+    }
+
+    bool empty() const BOOST_NOEXCEPT
+    { return ! impl_; }
+
+    operator safe_bool() const BOOST_NOEXCEPT
+    { return ( empty() || impl_->is_complete() ) ? 0 : & dummy::nonnull; }
+
+    bool operator!() const BOOST_NOEXCEPT
+    { return empty() || impl_->is_complete(); }
+
+    void swap( push_coroutine & other) BOOST_NOEXCEPT
+    { impl_.swap( other.impl_); }
+
+    push_coroutine & operator()()
+    {
+        BOOST_ASSERT( * this);
+
+        impl_->push();
+        return * this;
+    }
+
+    struct iterator;
+    struct const_iterator;
+};
+
+
+
+template< typename R >
+class pull_coroutine
+{
+private:
+    template<
+        typename X, typename Y, typename Z, typename V, typename W
+    >
+    friend class detail::push_coroutine_object;
+
+    typedef detail::pull_coroutine_base< R >    base_t;
+    typedef typename base_t::ptr_t              ptr_t;
+
+    struct dummy
+    { void nonnull() {} };
+
+    typedef void ( dummy::*safe_bool)();
+
+    ptr_t  impl_;
+
+    BOOST_MOVABLE_BUT_NOT_COPYABLE( pull_coroutine)
+
+    template< typename Allocator >
+    pull_coroutine( detail::coroutine_context const& callee,
+                    bool unwind, bool preserve_fpu,
+                    Allocator const& alloc,
+                    optional< R > const& result) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_caller<
+                R, Allocator
+        >                               caller_t;
+        typename caller_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) caller_t(
+                callee, unwind, preserve_fpu, a, result) );
+    }
+
+public:
+    pull_coroutine() BOOST_NOEXCEPT :
+        impl_()
+    {}
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+    template< typename Fn >
+    explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< pull_coroutine > const& alloc =
+                    std::allocator< pull_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, pull_coroutine >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                R, Fn, stack_allocator, std::allocator< pull_coroutine >,
+                push_coroutine< R >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+    }
+
+    template< typename Fn, typename StackAllocator >
+    explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< pull_coroutine > const& alloc =
+                    std::allocator< pull_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, pull_coroutine >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                R, Fn, StackAllocator, std::allocator< pull_coroutine >,
+                push_coroutine< R >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+    }
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, pull_coroutine >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                R, Fn, StackAllocator, Allocator,
+                push_coroutine< R >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+    }
+#else
+    template< typename Fn >
+    explicit pull_coroutine( Fn fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< pull_coroutine > const& alloc =
+                    std::allocator< pull_coroutine >(),
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                R, Fn, stack_allocator, std::allocator< pull_coroutine >,
+                push_coroutine< R >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+    }
+
+    template< typename Fn, typename StackAllocator >
+    explicit pull_coroutine( Fn fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< pull_coroutine > const& alloc =
+                    std::allocator< pull_coroutine >(),
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                R, Fn, StackAllocator, std::allocator< pull_coroutine >,
+                push_coroutine< R >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+    }
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit pull_coroutine( Fn fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                R, Fn, StackAllocator, Allocator,
+                push_coroutine< R >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+    }
+
+    template< typename Fn >
+    explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< pull_coroutine > const& alloc =
+                    std::allocator< pull_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, pull_coroutine >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                R, Fn, stack_allocator, std::allocator< pull_coroutine >,
+                push_coroutine< R >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+    }
+
+    template< typename Fn, typename StackAllocator >
+    explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< pull_coroutine > const& alloc =
+                    std::allocator< pull_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, pull_coroutine >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                R, Fn, StackAllocator, std::allocator< pull_coroutine >,
+                push_coroutine< R >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+    }
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, pull_coroutine >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                R, Fn, StackAllocator, Allocator,
+                push_coroutine< R >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+    }
+#endif
+
+    pull_coroutine( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT :
+        impl_()
+    { swap( other); }
+
+    pull_coroutine & operator=( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT
+    {
+        pull_coroutine tmp( boost::move( other) );
+        swap( tmp);
+        return * this;
+    }
+
+    bool empty() const BOOST_NOEXCEPT
+    { return ! impl_; }
+
+    operator safe_bool() const BOOST_NOEXCEPT
+    { return ( empty() || impl_->is_complete() ) ? 0 : & dummy::nonnull; }
+
+    bool operator!() const BOOST_NOEXCEPT
+    { return empty() || impl_->is_complete(); }
+
+    void swap( pull_coroutine & other) BOOST_NOEXCEPT
+    { impl_.swap( other.impl_); }
+
+    pull_coroutine & operator()()
+    {
+        BOOST_ASSERT( * this);
+
+        impl_->pull();
+        return * this;
+    }
+
+    bool has_result() const
+    {
+        BOOST_ASSERT( ! empty() );
+
+        return impl_->has_result();
+    }
+
+    R get() const
+    {
+        BOOST_ASSERT( has_result() );
+
+        return impl_->get();
+    }
+
+    class iterator : public std::iterator< std::input_iterator_tag, typename remove_reference< R >::type >
+    {
+    private:
+        pull_coroutine< R > *   c_;
+        optional< R >           val_;
+
+        void fetch_()
+        {
+            BOOST_ASSERT( c_);
+
+            if ( ! c_->has_result() )
+            {
+                c_ = 0;
+                val_ = none;
+                return;
+            }
+            val_ = c_->get();
+        }
+
+        void increment_()
+        {
+            BOOST_ASSERT( c_);
+            BOOST_ASSERT( * c_);
+
+            ( * c_)();
+            fetch_();
+        }
+
+    public:
+        typedef typename iterator::pointer      pointer_t;
+        typedef typename iterator::reference    reference_t;
+
+        iterator() :
+            c_( 0), val_()
+        {}
+
+        explicit iterator( pull_coroutine< R > * c) :
+            c_( c), val_()
+        { fetch_(); }
+
+        iterator( iterator const& other) :
+            c_( other.c_), val_( other.val_)
+        {}
+
+        iterator & operator=( iterator const& other)
+        {
+            if ( this == & other) return * this;
+            c_ = other.c_;
+            val_ = other.val_;
+            return * this;
+        }
+
+        bool operator==( iterator const& other)
+        { return other.c_ == c_ && other.val_ == val_; }
+
+        bool operator!=( iterator const& other)
+        { return other.c_ != c_ || other.val_ != val_; }
+
+        iterator & operator++()
+        {
+            increment_();
+            return * this;
+        }
+
+        iterator operator++( int)
+        {
+            iterator tmp( * this);
+            ++*this;
+            return tmp;
+        }
+
+        reference_t operator*() const
+        { return const_cast< optional< R > & >( val_).get(); }
+
+        pointer_t operator->() const
+        { return const_cast< optional< R > & >( val_).get_ptr(); }
+    };
+
+    class const_iterator : public std::iterator< std::input_iterator_tag, const typename remove_reference< R >::type >
+    {
+    private:
+        pull_coroutine< R > *   c_;
+        optional< R >      val_;
+
+        void fetch_()
+        {
+            BOOST_ASSERT( c_);
+
+            if ( ! c_->has_result() )
+            {
+                c_ = 0;
+                val_ = none;
+                return;
+            }
+            val_ = c_->get();
+        }
+
+        void increment_()
+        {
+            BOOST_ASSERT( c_);
+            BOOST_ASSERT( * c_);
+
+            ( * c_)();
+            fetch_();
+        }
+
+    public:
+        typedef typename const_iterator::pointer      pointer_t;
+        typedef typename const_iterator::reference    reference_t;
+
+        const_iterator() :
+            c_( 0), val_()
+        {}
+
+        explicit const_iterator( pull_coroutine< R > const* c) :
+            c_( const_cast< pull_coroutine< R > * >( c) ), val_()
+        { fetch_(); }
+
+        const_iterator( const_iterator const& other) :
+            c_( other.c_), val_( other.val_)
+        {}
+
+        const_iterator & operator=( const_iterator const& other)
+        {
+            if ( this == & other) return * this;
+            c_ = other.c_;
+            val_ = other.val_;
+            return * this;
+        }
+
+        bool operator==( const_iterator const& other)
+        { return other.c_ == c_ && other.val_ == val_; }
+
+        bool operator!=( const_iterator const& other)
+        { return other.c_ != c_ || other.val_ != val_; }
+
+        const_iterator & operator++()
+        {
+            increment_();
+            return * this;
+        }
+
+        const_iterator operator++( int)
+        {
+            const_iterator tmp( * this);
+            ++*this;
+            return tmp;
+        }
+
+        reference_t operator*() const
+        { return val_.get(); }
+
+        pointer_t operator->() const
+        { return val_.get_ptr(); }
+    };
+};
+
+template<>
+class pull_coroutine< void >
+{
+private:
+    template<
+        typename X, typename Y, typename Z, typename V, typename W
+    >
+    friend class detail::push_coroutine_object;
+
+    typedef detail::pull_coroutine_base< void > base_t;
+    typedef typename base_t::ptr_t              ptr_t;
+
+    struct dummy
+    { void nonnull() {} };
+
+    typedef void ( dummy::*safe_bool)();
+
+    ptr_t  impl_;
+
+    BOOST_MOVABLE_BUT_NOT_COPYABLE( pull_coroutine)
+
+    template< typename Allocator >
+    pull_coroutine( detail::coroutine_context const& callee,
+                    bool unwind, bool preserve_fpu,
+                    Allocator const& alloc) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_caller<
+                void, Allocator
+        >                               caller_t;
+        typename caller_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) caller_t(
+                callee, unwind, preserve_fpu, a) );
+    }
+
+public:
+    pull_coroutine() BOOST_NOEXCEPT :
+        impl_()
+    {}
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+    template< typename Fn >
+    explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< pull_coroutine > const& alloc =
+                    std::allocator< pull_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, pull_coroutine >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                void, Fn, stack_allocator, std::allocator< pull_coroutine >,
+                push_coroutine< void >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+    }
+
+    template< typename Fn, typename StackAllocator >
+    explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< pull_coroutine > const& alloc =
+                    std::allocator< pull_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, pull_coroutine >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                void, Fn, StackAllocator, std::allocator< pull_coroutine >,
+                push_coroutine< void >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+    }
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, pull_coroutine >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                void, Fn, StackAllocator, Allocator,
+                push_coroutine< void >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+    }
+#else
+    template< typename Fn >
+    explicit pull_coroutine( Fn fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< pull_coroutine > const& alloc =
+                    std::allocator< pull_coroutine >(),
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                void, Fn, stack_allocator, std::allocator< pull_coroutine >,
+                push_coroutine< void >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+    }
+
+    template< typename Fn, typename StackAllocator >
+    explicit pull_coroutine( Fn fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< pull_coroutine > const& alloc =
+                    std::allocator< pull_coroutine >(),
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                void, Fn, StackAllocator, std::allocator< pull_coroutine >,
+                push_coroutine< void >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+    }
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit pull_coroutine( Fn fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                void, Fn, StackAllocator, Allocator,
+                push_coroutine< void >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+    }
+
+    template< typename Fn >
+    explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr = attributes(),
+               stack_allocator const& stack_alloc =
+                    stack_allocator(),
+               std::allocator< pull_coroutine > const& alloc =
+                    std::allocator< pull_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, pull_coroutine >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                void, Fn, stack_allocator, std::allocator< pull_coroutine >,
+                push_coroutine< void >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+    }
+
+    template< typename Fn, typename StackAllocator >
+    explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               std::allocator< pull_coroutine > const& alloc =
+                    std::allocator< pull_coroutine >(),
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, pull_coroutine >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                void, Fn, StackAllocator, std::allocator< pull_coroutine >,
+                push_coroutine< void >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+    }
+
+    template< typename Fn, typename StackAllocator, typename Allocator >
+    explicit pull_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+               StackAllocator const& stack_alloc,
+               Allocator const& alloc,
+               typename disable_if<
+                   is_same< typename decay< Fn >::type, pull_coroutine >,
+                   dummy *
+               >::type = 0) :
+        impl_()
+    {
+        typedef detail::pull_coroutine_object<
+                void, Fn, StackAllocator, Allocator,
+                push_coroutine< void >
+            >                               object_t;
+        typename object_t::allocator_t a( alloc);
+        impl_ = ptr_t(
+            // placement new
+            ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+    }
+#endif
+
+    pull_coroutine( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT :
+        impl_()
+    { swap( other); }
+
+    pull_coroutine & operator=( BOOST_RV_REF( pull_coroutine) other) BOOST_NOEXCEPT
+    {
+        pull_coroutine tmp( boost::move( other) );
+        swap( tmp);
+        return * this;
+    }
+
+    bool empty() const BOOST_NOEXCEPT
+    { return ! impl_; }
+
+    operator safe_bool() const BOOST_NOEXCEPT
+    { return ( empty() || impl_->is_complete() ) ? 0 : & dummy::nonnull; }
+
+    bool operator!() const BOOST_NOEXCEPT
+    { return empty() || impl_->is_complete(); }
+
+    void swap( pull_coroutine & other) BOOST_NOEXCEPT
+    { impl_.swap( other.impl_); }
+
+    pull_coroutine & operator()()
+    {
+        BOOST_ASSERT( * this);
+
+        impl_->pull();
+        return * this;
+    }
+
+    struct iterator;
+    struct const_iterator;
+};
+
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+template< typename Arg >
+template< typename Fn >
+push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           stack_allocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg, Fn, stack_allocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator >
+push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg, Fn, StackAllocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator, typename Allocator >
+push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           Allocator const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg, Fn, StackAllocator, Allocator,
+            pull_coroutine< Arg >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn >
+push_coroutine< Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           stack_allocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg &, Fn, stack_allocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg & >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator >
+push_coroutine< Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg &, Fn, StackAllocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg & >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator, typename Allocator >
+push_coroutine< Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           Allocator const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg &, Fn, StackAllocator, Allocator,
+            pull_coroutine< Arg & >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn >
+push_coroutine< Arg const& >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           stack_allocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg const&, Fn, stack_allocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg const& >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator >
+push_coroutine< Arg const& >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg const&, Fn, StackAllocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg const& >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator, typename Allocator >
+push_coroutine< Arg const& >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           Allocator const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg const&, Fn, StackAllocator, Allocator,
+            pull_coroutine< Arg const& >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+}
+
+template< typename Fn >
+push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           stack_allocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            void, Fn, stack_allocator, std::allocator< push_coroutine >,
+            pull_coroutine< void >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+}
+
+template< typename Fn, typename StackAllocator >
+push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            void, Fn, StackAllocator, std::allocator< push_coroutine >,
+            pull_coroutine< void >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+}
+
+template< typename Fn, typename StackAllocator, typename Allocator >
+push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           Allocator const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            void, Fn, StackAllocator, Allocator,
+            pull_coroutine< void >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( forward< Fn >( fn), attr, stack_alloc, a) );
+}
+#else
+template< typename Arg >
+template< typename Fn >
+push_coroutine< Arg >::push_coroutine( Fn fn, attributes const& attr,
+           stack_allocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg, Fn, stack_allocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator >
+push_coroutine< Arg >::push_coroutine( Fn fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg, Fn, StackAllocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator, typename Allocator >
+push_coroutine< Arg >::push_coroutine( Fn fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           Allocator const& alloc,
+           typename disable_if<
+               is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg, Fn, StackAllocator, Allocator,
+            pull_coroutine< Arg >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn >
+push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           stack_allocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg, Fn, stack_allocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator >
+push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg, Fn, StackAllocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator, typename Allocator >
+push_coroutine< Arg >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           Allocator const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg, Fn, StackAllocator, Allocator,
+            pull_coroutine< Arg >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn >
+push_coroutine< Arg & >::push_coroutine( Fn fn, attributes const& attr,
+           stack_allocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg &, Fn, stack_allocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg & >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator >
+push_coroutine< Arg & >::push_coroutine( Fn fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg &, Fn, StackAllocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg & >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator, typename Allocator >
+push_coroutine< Arg & >::push_coroutine( Fn fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           Allocator const& alloc,
+           typename disable_if<
+               is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg &, Fn, StackAllocator, Allocator,
+            pull_coroutine< Arg & >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn >
+push_coroutine< Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           stack_allocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg &, Fn, stack_allocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg & >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator >
+push_coroutine< Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+           Arg &, Fn, StackAllocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg & >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator, typename Allocator >
+push_coroutine<Arg & >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           Allocator const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg &, Fn, StackAllocator, Allocator,
+            pull_coroutine< Arg & >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn >
+push_coroutine< Arg const& >::push_coroutine( Fn fn, attributes const& attr,
+           stack_allocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg const&, Fn, stack_allocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg const& >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator >
+push_coroutine< Arg const& >::push_coroutine( Fn fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg const&, Fn, StackAllocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg const& >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator, typename Allocator >
+push_coroutine< Arg const& >::push_coroutine( Fn fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           Allocator const& alloc,
+           typename disable_if<
+               is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg const&, Fn, StackAllocator, Allocator,
+            pull_coroutine< Arg const& >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn >
+push_coroutine< Arg const& >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           stack_allocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg const&, Fn, stack_allocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg const& >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator >
+push_coroutine< Arg const& >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg const&, Fn, StackAllocator, std::allocator< push_coroutine >,
+            pull_coroutine< Arg const& >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Arg >
+template< typename Fn, typename StackAllocator, typename Allocator >
+push_coroutine< Arg const& >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           Allocator const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            Arg const&, Fn, StackAllocator, Allocator,
+            pull_coroutine< Arg const& >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Fn >
+push_coroutine< void >::push_coroutine( Fn fn, attributes const& attr,
+           stack_allocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            void, Fn, stack_allocator, std::allocator< push_coroutine >,
+            pull_coroutine< void >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Fn, typename StackAllocator >
+push_coroutine< void >::push_coroutine( Fn fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            void, Fn, StackAllocator, std::allocator< push_coroutine >,
+            pull_coroutine< void >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Fn, typename StackAllocator, typename Allocator >
+push_coroutine< void >::push_coroutine( Fn fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           Allocator const& alloc,
+           typename disable_if<
+               is_convertible< Fn &, BOOST_RV_REF( Fn) >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            void, Fn, StackAllocator, Allocator,
+            pull_coroutine< void >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Fn >
+push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           stack_allocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            void, Fn, stack_allocator, std::allocator< push_coroutine >,
+            pull_coroutine< void >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Fn, typename StackAllocator >
+push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           std::allocator< push_coroutine > const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            void, Fn, StackAllocator, std::allocator< push_coroutine >,
+            pull_coroutine< void >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+
+template< typename Fn, typename StackAllocator, typename Allocator >
+push_coroutine< void >::push_coroutine( BOOST_RV_REF( Fn) fn, attributes const& attr,
+           StackAllocator const& stack_alloc,
+           Allocator const& alloc,
+           typename disable_if<
+               is_same< typename decay< Fn >::type, push_coroutine >,
+               dummy *
+           >::type) :
+    impl_()
+{
+    typedef detail::push_coroutine_object<
+            void, Fn, StackAllocator, Allocator,
+            pull_coroutine< void >
+        >                               object_t;
+    typename object_t::allocator_t a( alloc);
+    impl_ = ptr_t(
+        // placement new
+        ::new( a.allocate( 1) ) object_t( fn, attr, stack_alloc, a) );
+}
+#endif
+
+template< typename R >
+void swap( pull_coroutine< R > & l, pull_coroutine< R > & r) BOOST_NOEXCEPT
+{ l.swap( r); }
+
+template< typename Arg >
+void swap( push_coroutine< Arg > & l, push_coroutine< Arg > & r) BOOST_NOEXCEPT
+{ l.swap( r); }
+
+template< typename R >
+inline
+typename pull_coroutine< R >::iterator
+range_begin( pull_coroutine< R > & c)
+{ return typename pull_coroutine< R >::iterator( & c); }
+
+template< typename R >
+inline
+typename pull_coroutine< R >::const_iterator
+range_begin( pull_coroutine< R > const& c)
+{ return typename pull_coroutine< R >::const_iterator( & c); }
+
+template< typename R >
+inline
+typename pull_coroutine< R >::iterator
+range_end( pull_coroutine< R > &)
+{ return typename pull_coroutine< R >::iterator(); }
+
+template< typename R >
+inline
+typename pull_coroutine< R >::const_iterator
+range_end( pull_coroutine< R > const&)
+{ return typename pull_coroutine< R >::const_iterator(); }
+
+template< typename R >
+inline
+typename pull_coroutine< R >::iterator
+begin( pull_coroutine< R > & c)
+{ return boost::begin( c); }
+
+template< typename R >
+inline
+typename pull_coroutine< R >::iterator
+end( pull_coroutine< R > & c)
+{ return boost::end( c); }
+
+template< typename R >
+inline
+typename pull_coroutine< R >::const_iterator
+begin( pull_coroutine< R > const& c)
+{ return boost::const_begin( c); }
+
+template< typename R >
+inline
+typename pull_coroutine< R >::const_iterator
+end( pull_coroutine< R > const& c)
+{ return boost::const_end( c); }
+
+template< typename Arg >
+inline
+typename push_coroutine< Arg >::iterator
+range_begin( push_coroutine< Arg > & c)
+{ return typename push_coroutine< Arg >::iterator( & c); }
+
+template< typename Arg >
+inline
+typename push_coroutine< Arg >::const_iterator
+range_begin( push_coroutine< Arg > const& c)
+{ return typename push_coroutine< Arg >::const_iterator( & c); }
+
+template< typename Arg >
+inline
+typename push_coroutine< Arg >::iterator
+range_end( push_coroutine< Arg > &)
+{ return typename push_coroutine< Arg >::iterator(); }
+
+template< typename Arg >
+inline
+typename push_coroutine< Arg >::const_iterator
+range_end( push_coroutine< Arg > const&)
+{ return typename push_coroutine< Arg >::const_iterator(); }
+
+template< typename Arg >
+inline
+typename push_coroutine< Arg >::iterator
+begin( push_coroutine< Arg > & c)
+{ return boost::begin( c); }
+
+template< typename Arg >
+inline
+typename push_coroutine< Arg >::iterator
+end( push_coroutine< Arg > & c)
+{ return boost::end( c); }
+
+template< typename Arg >
+inline
+typename push_coroutine< Arg >::const_iterator
+begin( push_coroutine< Arg > const& c)
+{ return boost::const_begin( c); }
+
+template< typename Arg >
+inline
+typename push_coroutine< Arg >::const_iterator
+end( push_coroutine< Arg > const& c)
+{ return boost::const_end( c); }
+
+}
+
+template< typename Arg >
+struct range_mutable_iterator< coroutines::push_coroutine< Arg > >
+{ typedef typename coroutines::push_coroutine< Arg >::iterator type; };
+
+template< typename Arg >
+struct range_const_iterator< coroutines::push_coroutine< Arg > >
+{ typedef typename coroutines::push_coroutine< Arg >::const_iterator type; };
+
+template< typename R >
+struct range_mutable_iterator< coroutines::pull_coroutine< R > >
+{ typedef typename coroutines::pull_coroutine< R >::iterator type; };
+
+template< typename R >
+struct range_const_iterator< coroutines::pull_coroutine< R > >
+{ typedef typename coroutines::pull_coroutine< R >::const_iterator type; };
+
+}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_V2_COROUTINE_H
diff --git a/include/boost/coroutine/v2/detail/pull_coroutine_base.hpp b/include/boost/coroutine/v2/detail/pull_coroutine_base.hpp
new file mode 100644
index 0000000..f3398fc
--- /dev/null
+++ b/include/boost/coroutine/v2/detail/pull_coroutine_base.hpp
@@ -0,0 +1,232 @@
+
+//          Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_V2_DETAIL_PULL_COROUTINE_BASE_H
+#define BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_BASE_H
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/context/fcontext.hpp>
+#include <boost/exception_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/optional.hpp>
+#include <boost/type_traits/function_traits.hpp>
+#include <boost/utility.hpp>
+
+#include <boost/coroutine/detail/config.hpp>
+#include <boost/coroutine/detail/coroutine_context.hpp>
+#include <boost/coroutine/detail/flags.hpp>
+#include <boost/coroutine/detail/holder.hpp>
+#include <boost/coroutine/detail/param.hpp>
+#include <boost/coroutine/detail/exceptions.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+
+struct stack_context;
+
+namespace detail {
+
+template< typename R >
+class pull_coroutine_base : private noncopyable
+{
+public:
+    typedef intrusive_ptr< pull_coroutine_base >     ptr_t;
+
+private:
+    template<
+        typename X, typename Y, typename Z, typename V, typename W
+    >
+    friend class push_coroutine_object;
+
+    unsigned int        use_count_;
+
+protected:
+    int                 flags_;
+    exception_ptr       except_;
+    coroutine_context   caller_;
+    coroutine_context   callee_;
+    optional< R >       result_;
+
+    virtual void deallocate_object() = 0;
+
+public:
+    pull_coroutine_base( coroutine_context::ctx_fn fn,
+                         stack_context * stack_ctx,
+                         bool unwind, bool preserve_fpu) :
+        use_count_( 0),
+        flags_( 0),
+        except_(),
+        caller_(),
+        callee_( fn, stack_ctx),
+        result_()
+    {
+        if ( unwind) flags_ |= flag_force_unwind;
+        if ( preserve_fpu) flags_ |= flag_preserve_fpu;
+    }
+
+    pull_coroutine_base( coroutine_context const& callee,
+                         bool unwind, bool preserve_fpu,
+                         optional< R > const& result) :
+        use_count_( 0),
+        flags_( 0),
+        except_(),
+        caller_(),
+        callee_( callee),
+        result_( result)
+    {
+        if ( unwind) flags_ |= flag_force_unwind;
+        if ( preserve_fpu) flags_ |= flag_preserve_fpu;
+    }
+
+    virtual ~pull_coroutine_base()
+    {}
+
+    bool force_unwind() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_force_unwind); }
+
+    bool unwind_requested() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_unwind_stack); }
+
+    bool preserve_fpu() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_preserve_fpu); }
+
+    bool is_complete() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_complete); }
+
+    friend inline void intrusive_ptr_add_ref( pull_coroutine_base * p) BOOST_NOEXCEPT
+    { ++p->use_count_; }
+
+    friend inline void intrusive_ptr_release( pull_coroutine_base * p) BOOST_NOEXCEPT
+    { if ( --p->use_count_ == 0) p->deallocate_object(); }
+
+    void pull()
+    {
+        BOOST_ASSERT( ! is_complete() );
+
+        holder< R > hldr_to( & caller_);
+        holder< R > * hldr_from(
+            reinterpret_cast< holder< R > * >(
+                hldr_to.ctx->jump(
+                    callee_,
+                    reinterpret_cast< intptr_t >( & hldr_to),
+                    preserve_fpu() ) ) );
+        BOOST_ASSERT( hldr_from->ctx);
+        callee_ = * hldr_from->ctx;
+        result_ = hldr_from->data;
+        if ( hldr_from->force_unwind) throw forced_unwind();
+        if ( except_) rethrow_exception( except_);
+    }
+
+    bool has_result() const
+    { return result_; }
+
+    R get() const
+    {
+        BOOST_ASSERT( has_result() );
+   
+        return result_.get(); 
+    }
+};
+
+template<>
+class pull_coroutine_base< void > : private noncopyable
+{
+public:
+    typedef intrusive_ptr< pull_coroutine_base >     ptr_t;
+
+private:
+    template<
+        typename X, typename Y, typename Z, typename V, typename W
+    >
+    friend class push_coroutine_object;
+
+    unsigned int        use_count_;
+
+protected:
+    int                 flags_;
+    exception_ptr       except_;
+    coroutine_context   caller_;
+    coroutine_context   callee_;
+
+    virtual void deallocate_object() = 0;
+
+public:
+    pull_coroutine_base( coroutine_context::ctx_fn fn,
+                         stack_context * stack_ctx,
+                         bool unwind, bool preserve_fpu) :
+        use_count_( 0),
+        flags_( 0),
+        except_(),
+        caller_(),
+        callee_( fn, stack_ctx)
+    {
+        if ( unwind) flags_ |= flag_force_unwind;
+        if ( preserve_fpu) flags_ |= flag_preserve_fpu;
+    }
+
+    pull_coroutine_base( coroutine_context const& callee,
+                         bool unwind, bool preserve_fpu) :
+        use_count_( 0),
+        flags_( 0),
+        except_(),
+        caller_(),
+        callee_( callee)
+    {
+        if ( unwind) flags_ |= flag_force_unwind;
+        if ( preserve_fpu) flags_ |= flag_preserve_fpu;
+    }
+
+    virtual ~pull_coroutine_base()
+    {}
+
+    bool force_unwind() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_force_unwind); }
+
+    bool unwind_requested() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_unwind_stack); }
+
+    bool preserve_fpu() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_preserve_fpu); }
+
+    bool is_complete() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_complete); }
+
+    friend inline void intrusive_ptr_add_ref( pull_coroutine_base * p) BOOST_NOEXCEPT
+    { ++p->use_count_; }
+
+    friend inline void intrusive_ptr_release( pull_coroutine_base * p) BOOST_NOEXCEPT
+    { if ( --p->use_count_ == 0) p->deallocate_object(); }
+
+    void pull()
+    {
+        BOOST_ASSERT( ! is_complete() );
+
+        holder< void > hldr_to( & caller_);
+        holder< void > * hldr_from(
+            reinterpret_cast< holder< void > * >(
+                hldr_to.ctx->jump(
+                    callee_,
+                    reinterpret_cast< intptr_t >( & hldr_to),
+                    preserve_fpu() ) ) );
+        BOOST_ASSERT( hldr_from->ctx);
+        callee_ = * hldr_from->ctx;
+        if ( hldr_from->force_unwind) throw forced_unwind();
+        if ( except_) rethrow_exception( except_);
+    }
+};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_BASE_H
diff --git a/include/boost/coroutine/v2/detail/pull_coroutine_caller.hpp b/include/boost/coroutine/v2/detail/pull_coroutine_caller.hpp
new file mode 100644
index 0000000..43b3506
--- /dev/null
+++ b/include/boost/coroutine/v2/detail/pull_coroutine_caller.hpp
@@ -0,0 +1,84 @@
+//          Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_V2_DETAIL_PULL_COROUTINE_CALLER_H
+#define BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_CALLER_H
+
+#include <boost/config.hpp>
+#include <boost/context/fcontext.hpp>
+#include <boost/optional.hpp>
+
+#include <boost/coroutine/detail/config.hpp>
+#include <boost/coroutine/v2/detail/pull_coroutine_base.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+template< typename R, typename Allocator >
+class pull_coroutine_caller : public  pull_coroutine_base< R >
+{
+public:
+    typedef typename Allocator::template rebind<
+        pull_coroutine_caller< R, Allocator >
+    >::other   allocator_t;
+
+    pull_coroutine_caller( coroutine_context const& callee, bool unwind, bool preserve_fpu,
+                           allocator_t const& alloc, optional< R > const& data) BOOST_NOEXCEPT :
+        pull_coroutine_base< R >( callee, unwind, preserve_fpu, data),
+        alloc_( alloc)
+    {}
+
+    void deallocate_object()
+    { destroy_( alloc_, this); }
+
+private:
+    allocator_t   alloc_;
+
+    static void destroy_( allocator_t & alloc, pull_coroutine_caller * p)
+    {
+        alloc.destroy( p);
+        alloc.deallocate( p, 1);
+    }
+};
+
+template< typename Allocator >
+class pull_coroutine_caller< void, Allocator > : public  pull_coroutine_base< void >
+{
+public:
+    typedef typename Allocator::template rebind<
+        pull_coroutine_caller< void, Allocator >
+    >::other   allocator_t;
+
+    pull_coroutine_caller( coroutine_context const& callee, bool unwind, bool preserve_fpu,
+                           allocator_t const& alloc) BOOST_NOEXCEPT :
+        pull_coroutine_base< void >( callee, unwind, preserve_fpu),
+        alloc_( alloc)
+    {}
+
+    void deallocate_object()
+    { destroy_( alloc_, this); }
+
+private:
+    allocator_t   alloc_;
+
+    static void destroy_( allocator_t & alloc, pull_coroutine_caller * p)
+    {
+        alloc.destroy( p);
+        alloc.deallocate( p, 1);
+    }
+};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_CALLER_H
diff --git a/include/boost/coroutine/v2/detail/pull_coroutine_object.hpp b/include/boost/coroutine/v2/detail/pull_coroutine_object.hpp
new file mode 100644
index 0000000..1698417
--- /dev/null
+++ b/include/boost/coroutine/v2/detail/pull_coroutine_object.hpp
@@ -0,0 +1,768 @@
+
+//          Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_V2_DETAIL_PULL_COROUTINE_OBJECT_H
+#define BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_OBJECT_H
+
+#include <cstddef>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/exception_ptr.hpp>
+#include <boost/move/move.hpp>
+#include <boost/ref.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/type_traits/function_traits.hpp>
+#include <boost/utility.hpp>
+
+#include <boost/coroutine/attributes.hpp>
+#include <boost/coroutine/detail/config.hpp>
+#include <boost/coroutine/detail/exceptions.hpp>
+#include <boost/coroutine/detail/flags.hpp>
+#include <boost/coroutine/detail/holder.hpp>
+#include <boost/coroutine/detail/param.hpp>
+#include <boost/coroutine/detail/stack_tuple.hpp>
+#include <boost/coroutine/detail/trampoline.hpp>
+#include <boost/coroutine/flags.hpp>
+#include <boost/coroutine/stack_context.hpp>
+#include <boost/coroutine/v2/detail/pull_coroutine_base.hpp>
+
+#ifdef BOOST_MSVC
+ #pragma warning (push)
+ #pragma warning (disable: 4355) // using 'this' in initializer list
+#endif
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+template<
+    typename R, typename Fn,
+    typename StackAllocator, typename Allocator,
+    typename Caller
+>
+class pull_coroutine_object : private stack_tuple< StackAllocator >,
+                              public pull_coroutine_base< R >
+{
+public:
+    typedef typename Allocator::template rebind<
+        pull_coroutine_object<
+            R, Fn, StackAllocator, Allocator, Caller
+        >
+    >::other                                            allocator_t;
+
+private:
+    typedef stack_tuple< StackAllocator >               pbase_type;
+    typedef pull_coroutine_base< R >                    base_type;
+
+    Fn                      fn_;
+    allocator_t             alloc_;
+
+    static void destroy_( allocator_t & alloc, pull_coroutine_object * p)
+    {
+        alloc.destroy( p);
+        alloc.deallocate( p, 1);
+    }
+
+    pull_coroutine_object( pull_coroutine_object &);
+    pull_coroutine_object & operator=( pull_coroutine_object const&);
+
+    void enter_()
+    {
+        holder< R > * hldr_from(
+            reinterpret_cast< holder< R > * >(
+                this->caller_.jump(
+                    this->callee_,
+                    reinterpret_cast< intptr_t >( this),
+                    this->preserve_fpu() ) ) );
+        this->callee_ = * hldr_from->ctx;
+        this->result_ = hldr_from->data;
+        if ( this->except_) rethrow_exception( this->except_);
+    }
+
+    void unwind_stack_() BOOST_NOEXCEPT
+    {
+        BOOST_ASSERT( ! this->is_complete() );
+
+        this->flags_ |= flag_unwind_stack;
+        holder< R > hldr_to( & this->caller_, true);
+        this->caller_.jump(
+            this->callee_,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        this->flags_ &= ~flag_unwind_stack;
+
+        BOOST_ASSERT( this->is_complete() );
+    }
+
+public:
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+    pull_coroutine_object( Fn && fn, attributes const& attr,
+                           StackAllocator const& stack_alloc,
+                           allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< pull_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( forward< Fn >( fn) ),
+        alloc_( alloc)
+    { enter_(); }
+#else
+    pull_coroutine_object( Fn fn, attributes const& attr,
+                           StackAllocator const& stack_alloc,
+                           allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< pull_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( fn),
+        alloc_( alloc)
+    { enter_(); }
+
+    pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
+                           StackAllocator const& stack_alloc,
+                           allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< pull_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( fn),
+        alloc_( alloc)
+    { enter_(); }
+#endif
+
+    ~pull_coroutine_object()
+    {
+        if ( ! this->is_complete() && this->force_unwind() )
+            unwind_stack_();
+    }
+
+    void run()
+    {
+        coroutine_context callee;
+        coroutine_context caller;
+
+        {
+            // create push_coroutine
+            Caller c( this->caller_, false, this->preserve_fpu(), alloc_);
+            try
+            { fn_( c); }
+            catch ( forced_unwind const&)
+            {}
+            catch (...)
+            { this->except_ = current_exception(); }
+            callee = c.impl_->callee_;
+        }
+
+        this->flags_ |= flag_complete;
+        holder< R > hldr_to( & caller);
+        caller.jump(
+            callee,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
+    }
+
+    void deallocate_object()
+    { destroy_( alloc_, this); }
+};
+
+template<
+    typename R, typename Fn,
+    typename StackAllocator, typename Allocator,
+    typename Caller
+>
+class pull_coroutine_object< R, reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
+    private stack_tuple< StackAllocator >,
+    public pull_coroutine_base< R >
+{
+public:
+    typedef typename Allocator::template rebind<
+        pull_coroutine_object<
+            R, Fn, StackAllocator, Allocator, Caller
+        >
+    >::other                                            allocator_t;
+
+private:
+    typedef stack_tuple< StackAllocator >               pbase_type;
+    typedef pull_coroutine_base< R >                    base_type;
+
+    Fn                      fn_;
+    allocator_t             alloc_;
+
+    static void destroy_( allocator_t & alloc, pull_coroutine_object * p)
+    {
+        alloc.destroy( p);
+        alloc.deallocate( p, 1);
+    }
+
+    pull_coroutine_object( pull_coroutine_object &);
+    pull_coroutine_object & operator=( pull_coroutine_object const&);
+
+    void enter_()
+    {
+        holder< R > * hldr_from(
+            reinterpret_cast< holder< R > * >(
+                this->caller_.jump(
+                    this->callee_,
+                    reinterpret_cast< intptr_t >( this),
+                    this->preserve_fpu() ) ) );
+        this->callee_ = * hldr_from->ctx;
+        if ( this->except_) rethrow_exception( this->except_);
+    }
+
+    void unwind_stack_() BOOST_NOEXCEPT
+    {
+        BOOST_ASSERT( ! this->is_complete() );
+
+        this->flags_ |= flag_unwind_stack;
+        holder< R > hldr_to( & this->caller_, true);
+        this->caller_.jump(
+            this->callee_,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        this->flags_ &= ~flag_unwind_stack;
+
+        BOOST_ASSERT( this->is_complete() );
+    }
+
+public:
+    pull_coroutine_object( reference_wrapper< Fn > fn, attributes const& attr,
+                           StackAllocator const& stack_alloc,
+                           allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< pull_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( fn),
+        alloc_( alloc)
+    { enter_(); }
+
+    ~pull_coroutine_object()
+    {
+        if ( ! this->is_complete() && this->force_unwind() )
+            unwind_stack_();
+    }
+
+    void run()
+    {
+        coroutine_context callee;
+        coroutine_context caller;
+
+        {
+            // create pull_coroutine
+            Caller c( this->caller_, false, this->preserve_fpu(), alloc_);
+            try
+            { fn_( c); }
+            catch ( forced_unwind const&)
+            {}
+            catch (...)
+            { this->except_ = current_exception(); }
+            callee = c.impl_->callee_;
+        }
+
+        this->flags_ |= flag_complete;
+        holder< R > hldr_to( & caller);
+        caller.jump(
+            callee,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
+    }
+
+    void deallocate_object()
+    { destroy_( alloc_, this); }
+};
+
+template<
+    typename R, typename Fn,
+    typename StackAllocator, typename Allocator,
+    typename Caller
+>
+class pull_coroutine_object< R, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
+    private stack_tuple< StackAllocator >,
+    public pull_coroutine_base< R >
+{
+public:
+    typedef typename Allocator::template rebind<
+        pull_coroutine_object<
+            R, Fn, StackAllocator, Allocator, Caller
+        >
+    >::other                                            allocator_t;
+
+private:
+    typedef stack_tuple< StackAllocator >               pbase_type;
+    typedef pull_coroutine_base< R >                    base_type;
+
+    Fn                      fn_;
+    allocator_t             alloc_;
+
+    static void destroy_( allocator_t & alloc, pull_coroutine_object * p)
+    {
+        alloc.destroy( p);
+        alloc.deallocate( p, 1);
+    }
+
+    pull_coroutine_object( pull_coroutine_object &);
+    pull_coroutine_object & operator=( pull_coroutine_object const&);
+
+    void enter_()
+    {
+        holder< R > * hldr_from(
+            reinterpret_cast< holder< R > * >(
+                this->caller_.jump(
+                    this->callee_,
+                    reinterpret_cast< intptr_t >( this),
+                    this->preserve_fpu() ) ) );
+        this->callee_ = * hldr_from->ctx;
+        if ( this->except_) rethrow_exception( this->except_);
+    }
+
+    void unwind_stack_() BOOST_NOEXCEPT
+    {
+        BOOST_ASSERT( ! this->is_complete() );
+
+        this->flags_ |= flag_unwind_stack;
+        holder< R > hldr_to( & this->caller_, true);
+        this->caller_.jump(
+            this->callee_,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        this->flags_ &= ~flag_unwind_stack;
+
+        BOOST_ASSERT( this->is_complete() );
+    }
+
+public:
+    pull_coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr,
+                           StackAllocator const& stack_alloc,
+                           allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< pull_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( fn),
+        alloc_( alloc)
+    { enter_(); }
+
+    ~pull_coroutine_object()
+    {
+        if ( ! this->is_complete() && this->force_unwind() )
+            unwind_stack_();
+    }
+
+    void run()
+    {
+        coroutine_context callee;
+        coroutine_context caller;
+
+        {
+            // create pull_coroutine
+            Caller c( this->caller_, false, this->preserve_fpu(), alloc_);
+            try
+            { fn_( c); }
+            catch ( forced_unwind const&)
+            {}
+            catch (...)
+            { this->except_ = current_exception(); }
+            callee = c.impl_->callee_;
+        }
+
+        this->flags_ |= flag_complete;
+        holder< R > hldr_to( & caller);
+        caller.jump(
+            callee,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
+    }
+
+    void deallocate_object()
+    { destroy_( alloc_, this); }
+};
+
+template<
+    typename Fn,
+    typename StackAllocator, typename Allocator,
+    typename Caller
+>
+class pull_coroutine_object< void, Fn, StackAllocator, Allocator, Caller > :
+    private stack_tuple< StackAllocator >,
+    public pull_coroutine_base< void >
+{
+public:
+    typedef typename Allocator::template rebind<
+        pull_coroutine_object<
+            void, Fn, StackAllocator, Allocator, Caller
+        >
+    >::other                                            allocator_t;
+
+private:
+    typedef stack_tuple< StackAllocator >               pbase_type;
+    typedef pull_coroutine_base< void >                 base_type;
+
+    Fn                      fn_;
+    allocator_t             alloc_;
+
+    static void destroy_( allocator_t & alloc, pull_coroutine_object * p)
+    {
+        alloc.destroy( p);
+        alloc.deallocate( p, 1);
+    }
+
+    pull_coroutine_object( pull_coroutine_object &);
+    pull_coroutine_object & operator=( pull_coroutine_object const&);
+
+    void enter_()
+    {
+        holder< void > * hldr_from(
+            reinterpret_cast< holder< void > * >(
+                this->caller_.jump(
+                    this->callee_,
+                    reinterpret_cast< intptr_t >( this),
+                    this->preserve_fpu() ) ) );
+        this->callee_ = * hldr_from->ctx;
+        if ( this->except_) rethrow_exception( this->except_);
+    }
+
+    void unwind_stack_() BOOST_NOEXCEPT
+    {
+        BOOST_ASSERT( ! this->is_complete() );
+
+        this->flags_ |= flag_unwind_stack;
+        holder< void > hldr_to( & this->caller_, true);
+        this->caller_.jump(
+            this->callee_,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        this->flags_ &= ~flag_unwind_stack;
+
+        BOOST_ASSERT( this->is_complete() );
+    }
+
+public:
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+    pull_coroutine_object( Fn && fn, attributes const& attr,
+                           StackAllocator const& stack_alloc,
+                           allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< pull_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( forward< Fn >( fn) ),
+        alloc_( alloc)
+    { enter_(); }
+#else
+    pull_coroutine_object( Fn fn, attributes const& attr,
+                           StackAllocator const& stack_alloc,
+                           allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< pull_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( fn),
+        alloc_( alloc)
+    { enter_(); }
+
+    pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
+                           StackAllocator const& stack_alloc,
+                           allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< pull_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( fn),
+        alloc_( alloc)
+    { enter_(); }
+#endif
+
+    ~pull_coroutine_object()
+    {
+        if ( ! this->is_complete() && this->force_unwind() )
+            unwind_stack_();
+    }
+
+    void run()
+    {
+        coroutine_context callee;
+        coroutine_context caller;
+
+        {
+            // create push_coroutine
+            Caller c( this->caller_, false, this->preserve_fpu(), alloc_);
+            try
+            { fn_( c); }
+            catch ( forced_unwind const&)
+            {}
+            catch (...)
+            { this->except_ = current_exception(); }
+            callee = c.impl_->callee_;
+        }
+
+        this->flags_ |= flag_complete;
+        holder< void > hldr_to( & caller);
+        caller.jump(
+            callee,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
+    }
+
+    void deallocate_object()
+    { destroy_( alloc_, this); }
+};
+
+template<
+    typename Fn,
+    typename StackAllocator, typename Allocator,
+    typename Caller
+>
+class pull_coroutine_object< void, reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
+    private stack_tuple< StackAllocator >,
+    public pull_coroutine_base< void >
+{
+public:
+    typedef typename Allocator::template rebind<
+        pull_coroutine_object<
+            void, Fn, StackAllocator, Allocator, Caller
+        >
+    >::other                                            allocator_t;
+
+private:
+    typedef stack_tuple< StackAllocator >               pbase_type;
+    typedef pull_coroutine_base< void >                 base_type;
+
+    Fn                      fn_;
+    allocator_t             alloc_;
+
+    static void destroy_( allocator_t & alloc, pull_coroutine_object * p)
+    {
+        alloc.destroy( p);
+        alloc.deallocate( p, 1);
+    }
+
+    pull_coroutine_object( pull_coroutine_object &);
+    pull_coroutine_object & operator=( pull_coroutine_object const&);
+
+    void enter_()
+    {
+        holder< void > * hldr_from(
+            reinterpret_cast< holder< void > * >(
+                this->caller_.jump(
+                    this->callee_,
+                    reinterpret_cast< intptr_t >( this),
+                    this->preserve_fpu() ) ) );
+        this->callee_ = * hldr_from->ctx;
+        if ( this->except_) rethrow_exception( this->except_);
+    }
+
+    void unwind_stack_() BOOST_NOEXCEPT
+    {
+        BOOST_ASSERT( ! this->is_complete() );
+
+        this->flags_ |= flag_unwind_stack;
+        holder< void > hldr_to( & this->caller_, true);
+        this->caller_.jump(
+            this->callee_,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        this->flags_ &= ~flag_unwind_stack;
+
+        BOOST_ASSERT( this->is_complete() );
+    }
+
+public:
+    pull_coroutine_object( reference_wrapper< Fn > fn, attributes const& attr,
+                           StackAllocator const& stack_alloc,
+                           allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< pull_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( fn),
+        alloc_( alloc)
+    { enter_(); }
+
+    ~pull_coroutine_object()
+    {
+        if ( ! this->is_complete() && this->force_unwind() )
+            unwind_stack_();
+    }
+
+    void run()
+    {
+        coroutine_context callee;
+        coroutine_context caller;
+
+        {
+            // create pull_coroutine
+            Caller c( this->caller_, false, this->preserve_fpu(), alloc_);
+            try
+            { fn_( c); }
+            catch ( forced_unwind const&)
+            {}
+            catch (...)
+            { this->except_ = current_exception(); }
+            callee = c.impl_->callee_;
+        }
+
+        this->flags_ |= flag_complete;
+        holder< void > hldr_to( & caller);
+        caller.jump(
+            callee,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
+    }
+
+    void deallocate_object()
+    { destroy_( alloc_, this); }
+};
+
+template<
+    typename Fn,
+    typename StackAllocator, typename Allocator,
+    typename Caller
+>
+class pull_coroutine_object< void, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
+    private stack_tuple< StackAllocator >,
+    public pull_coroutine_base< void >
+{
+public:
+    typedef typename Allocator::template rebind<
+        pull_coroutine_object<
+            void, Fn, StackAllocator, Allocator, Caller
+        >
+    >::other                                            allocator_t;
+
+private:
+    typedef stack_tuple< StackAllocator >               pbase_type;
+    typedef pull_coroutine_base< void >                 base_type;
+
+    Fn                      fn_;
+    allocator_t             alloc_;
+
+    static void destroy_( allocator_t & alloc, pull_coroutine_object * p)
+    {
+        alloc.destroy( p);
+        alloc.deallocate( p, 1);
+    }
+
+    pull_coroutine_object( pull_coroutine_object &);
+    pull_coroutine_object & operator=( pull_coroutine_object const&);
+
+    void enter_()
+    {
+        holder< void > * hldr_from(
+            reinterpret_cast< holder< void > * >(
+                this->caller_.jump(
+                    this->callee_,
+                    reinterpret_cast< intptr_t >( this),
+                    this->preserve_fpu() ) ) );
+        this->callee_ = * hldr_from->ctx;
+        if ( this->except_) rethrow_exception( this->except_);
+    }
+
+    void unwind_stack_() BOOST_NOEXCEPT
+    {
+        BOOST_ASSERT( ! this->is_complete() );
+
+        this->flags_ |= flag_unwind_stack;
+        holder< void > hldr_to( & this->caller_, true);
+        this->caller_.jump(
+            this->callee_,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        this->flags_ &= ~flag_unwind_stack;
+
+        BOOST_ASSERT( this->is_complete() );
+    }
+
+public:
+    pull_coroutine_object( const reference_wrapper< Fn > fn,
+                           attributes const& attr,
+                           StackAllocator const& stack_alloc,
+                           allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< pull_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( fn),
+        alloc_( alloc)
+    { enter_(); }
+
+    ~pull_coroutine_object()
+    {
+        if ( ! this->is_complete() && this->force_unwind() )
+            unwind_stack_();
+    }
+
+    void run()
+    {
+        coroutine_context callee;
+        coroutine_context caller;
+
+        {
+            // create pull_coroutine
+            Caller c( this->caller_, false, this->preserve_fpu(), alloc_);
+            try
+            { fn_( c); }
+            catch ( forced_unwind const&)
+            {}
+            catch (...)
+            { this->except_ = current_exception(); }
+            callee = c.impl_->callee_;
+        }
+
+        this->flags_ |= flag_complete;
+        holder< void > hldr_to( & caller);
+        caller.jump(
+            callee,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
+    }
+
+    void deallocate_object()
+    { destroy_( alloc_, this); }
+};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_SUFFIX
+#endif
+
+#ifdef BOOST_MSVC
+ #pragma warning (pop)
+#endif
+
+#endif // BOOST_COROUTINES_V2_DETAIL_PULL_COROUTINE_OBJECT_H
diff --git a/include/boost/coroutine/v2/detail/push_coroutine_base.hpp b/include/boost/coroutine/v2/detail/push_coroutine_base.hpp
new file mode 100644
index 0000000..1a4156d
--- /dev/null
+++ b/include/boost/coroutine/v2/detail/push_coroutine_base.hpp
@@ -0,0 +1,441 @@
+
+//          Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_V2_DETAIL_PUSH_COROUTINE_BASE_H
+#define BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_BASE_H
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/context/fcontext.hpp>
+#include <boost/exception_ptr.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/type_traits/function_traits.hpp>
+#include <boost/utility.hpp>
+
+#include <boost/coroutine/detail/config.hpp>
+#include <boost/coroutine/detail/coroutine_context.hpp>
+#include <boost/coroutine/detail/exceptions.hpp>
+#include <boost/coroutine/detail/flags.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+
+struct stack_context;
+
+namespace detail {
+
+template< typename Arg >
+class push_coroutine_base : private noncopyable
+{
+public:
+    typedef intrusive_ptr< push_coroutine_base >     ptr_t;
+
+private:
+    template<
+        typename X, typename Y, typename Z, typename V, typename W
+    >
+    friend class pull_coroutine_object;
+
+    unsigned int        use_count_;
+
+protected:
+    int                 flags_;
+    exception_ptr       except_;
+    coroutine_context   caller_;
+    coroutine_context   callee_;
+
+    virtual void deallocate_object() = 0;
+
+public:
+    push_coroutine_base( coroutine_context::ctx_fn fn,
+                         stack_context * stack_ctx,
+                         bool unwind, bool preserve_fpu) :
+        use_count_( 0),
+        flags_( 0),
+        except_(),
+        caller_(),
+        callee_( fn, stack_ctx)
+    {
+        if ( unwind) flags_ |= flag_force_unwind;
+        if ( preserve_fpu) flags_ |= flag_preserve_fpu;
+    }
+
+    push_coroutine_base( coroutine_context const& callee,
+                         bool unwind, bool preserve_fpu) :
+        use_count_( 0),
+        flags_( 0),
+        except_(),
+        caller_(),
+        callee_( callee)
+    {
+        if ( unwind) flags_ |= flag_force_unwind;
+        if ( preserve_fpu) flags_ |= flag_preserve_fpu;
+    }
+
+    virtual ~push_coroutine_base()
+    {}
+
+    bool force_unwind() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_force_unwind); }
+
+    bool unwind_requested() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_unwind_stack); }
+
+    bool preserve_fpu() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_preserve_fpu); }
+
+    bool is_complete() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_complete); }
+
+    friend inline void intrusive_ptr_add_ref( push_coroutine_base * p) BOOST_NOEXCEPT
+    { ++p->use_count_; }
+
+    friend inline void intrusive_ptr_release( push_coroutine_base * p) BOOST_NOEXCEPT
+    { if ( --p->use_count_ == 0) p->deallocate_object(); }
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+    void push( Arg const& arg)
+    {
+        BOOST_ASSERT( ! is_complete() );
+
+        holder< Arg > hldr_to( & caller_, arg);
+        holder< Arg > * hldr_from(
+            reinterpret_cast< holder< Arg > * >(
+                hldr_to.ctx->jump(
+                    callee_,
+                    reinterpret_cast< intptr_t >( & hldr_to),
+                    preserve_fpu() ) ) );
+        BOOST_ASSERT( hldr_from->ctx);
+        callee_ = * hldr_from->ctx;
+        if ( hldr_from->force_unwind) throw forced_unwind();
+        if ( except_) rethrow_exception( except_);
+    }
+
+    void push( Arg && arg)
+    {
+        BOOST_ASSERT( ! is_complete() );
+
+        holder< Arg > hldr_to( & caller_, arg);
+        holder< Arg > * hldr_from(
+            reinterpret_cast< holder< Arg > * >(
+                hldr_to.ctx->jump(
+                    callee_,
+                    reinterpret_cast< intptr_t >( & hldr_to),
+                    preserve_fpu() ) ) );
+        BOOST_ASSERT( hldr_from->ctx);
+        callee_ = * hldr_from->ctx;
+        if ( hldr_from->force_unwind) throw forced_unwind();
+        if ( except_) rethrow_exception( except_);
+    }
+#else
+    void push( Arg arg)
+    {
+        BOOST_ASSERT( ! is_complete() );
+
+        holder< Arg > hldr_to( & caller_, arg);
+        holder< Arg > * hldr_from(
+            reinterpret_cast< holder< Arg > * >(
+                hldr_to.ctx->jump(
+                    callee_,
+                    reinterpret_cast< intptr_t >( & hldr_to),
+                    preserve_fpu() ) ) );
+        BOOST_ASSERT( hldr_from->ctx);
+        callee_ = * hldr_from->ctx;
+        if ( hldr_from->force_unwind) throw forced_unwind();
+        if ( except_) rethrow_exception( except_);
+    }
+
+    void push( BOOST_RV_REF( Arg) arg)
+    {
+        BOOST_ASSERT( ! is_complete() );
+
+        holder< Arg > hldr_to( & caller_, arg);
+        holder< Arg > * hldr_from(
+            reinterpret_cast< holder< Arg > * >(
+                hldr_to.ctx->jump(
+                    callee_,
+                    reinterpret_cast< intptr_t >( & hldr_to),
+                    preserve_fpu() ) ) );
+        BOOST_ASSERT( hldr_from->ctx);
+        callee_ = * hldr_from->ctx;
+        if ( hldr_from->force_unwind) throw forced_unwind();
+        if ( except_) rethrow_exception( except_);
+    }
+#endif
+};
+
+template< typename Arg >
+class push_coroutine_base< Arg & > : private noncopyable
+{
+public:
+    typedef intrusive_ptr< push_coroutine_base >     ptr_t;
+
+private:
+    template<
+        typename X, typename Y, typename Z, typename V, typename W
+    >
+    friend class pull_coroutine_object;
+
+    unsigned int        use_count_;
+
+protected:
+    int                 flags_;
+    exception_ptr       except_;
+    coroutine_context   caller_;
+    coroutine_context   callee_;
+
+    virtual void deallocate_object() = 0;
+
+public:
+    push_coroutine_base( coroutine_context::ctx_fn fn,
+                         stack_context * stack_ctx,
+                         bool unwind, bool preserve_fpu) :
+        use_count_( 0),
+        flags_( 0),
+        except_(),
+        caller_(),
+        callee_( fn, stack_ctx)
+    {
+        if ( unwind) flags_ |= flag_force_unwind;
+        if ( preserve_fpu) flags_ |= flag_preserve_fpu;
+    }
+
+    push_coroutine_base( coroutine_context const& callee,
+                         bool unwind, bool preserve_fpu) :
+        use_count_( 0),
+        flags_( 0),
+        except_(),
+        caller_(),
+        callee_( callee)
+    {
+        if ( unwind) flags_ |= flag_force_unwind;
+        if ( preserve_fpu) flags_ |= flag_preserve_fpu;
+    }
+
+    virtual ~push_coroutine_base()
+    {}
+
+    bool force_unwind() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_force_unwind); }
+
+    bool unwind_requested() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_unwind_stack); }
+
+    bool preserve_fpu() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_preserve_fpu); }
+
+    bool is_complete() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_complete); }
+
+    friend inline void intrusive_ptr_add_ref( push_coroutine_base * p) BOOST_NOEXCEPT
+    { ++p->use_count_; }
+
+    friend inline void intrusive_ptr_release( push_coroutine_base * p) BOOST_NOEXCEPT
+    { if ( --p->use_count_ == 0) p->deallocate_object(); }
+
+    void push( Arg & arg)
+    {
+        BOOST_ASSERT( ! is_complete() );
+
+        holder< Arg & > hldr_to( & caller_, arg);
+        holder< Arg & > * hldr_from(
+            reinterpret_cast< holder< Arg & > * >(
+                hldr_to.ctx->jump(
+                    callee_,
+                    reinterpret_cast< intptr_t >( & hldr_to),
+                    preserve_fpu() ) ) );
+        BOOST_ASSERT( hldr_from->ctx);
+        callee_ = * hldr_from->ctx;
+        if ( hldr_from->force_unwind) throw forced_unwind();
+        if ( except_) rethrow_exception( except_);
+    }
+};
+
+template< typename Arg >
+class push_coroutine_base< Arg const& > : private noncopyable
+{
+public:
+    typedef intrusive_ptr< push_coroutine_base >     ptr_t;
+
+private:
+    template<
+        typename X, typename Y, typename Z, typename V, typename W
+    >
+    friend class pull_coroutine_object;
+
+    unsigned int        use_count_;
+
+protected:
+    int                 flags_;
+    exception_ptr       except_;
+    coroutine_context   caller_;
+    coroutine_context   callee_;
+
+    virtual void deallocate_object() = 0;
+
+public:
+    push_coroutine_base( coroutine_context::ctx_fn fn,
+                         stack_context * stack_ctx,
+                         bool unwind, bool preserve_fpu) :
+        use_count_( 0),
+        flags_( 0),
+        except_(),
+        caller_(),
+        callee_( fn, stack_ctx)
+    {
+        if ( unwind) flags_ |= flag_force_unwind;
+        if ( preserve_fpu) flags_ |= flag_preserve_fpu;
+    }
+
+    push_coroutine_base( coroutine_context const& callee,
+                         bool unwind, bool preserve_fpu) :
+        use_count_( 0),
+        flags_( 0),
+        except_(),
+        caller_(),
+        callee_( callee)
+    {
+        if ( unwind) flags_ |= flag_force_unwind;
+        if ( preserve_fpu) flags_ |= flag_preserve_fpu;
+    }
+
+    virtual ~push_coroutine_base()
+    {}
+
+    bool force_unwind() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_force_unwind); }
+
+    bool unwind_requested() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_unwind_stack); }
+
+    bool preserve_fpu() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_preserve_fpu); }
+
+    bool is_complete() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_complete); }
+
+    friend inline void intrusive_ptr_add_ref( push_coroutine_base * p) BOOST_NOEXCEPT
+    { ++p->use_count_; }
+
+    friend inline void intrusive_ptr_release( push_coroutine_base * p) BOOST_NOEXCEPT
+    { if ( --p->use_count_ == 0) p->deallocate_object(); }
+
+    void push( Arg const& arg)
+    {
+        BOOST_ASSERT( ! is_complete() );
+
+        holder< Arg const& > hldr_to( & caller_, arg);
+        holder< Arg const& > * hldr_from(
+            reinterpret_cast< holder< Arg const& > * >(
+                hldr_to.ctx->jump(
+                    callee_,
+                    reinterpret_cast< intptr_t >( & hldr_to),
+                    preserve_fpu() ) ) );
+        BOOST_ASSERT( hldr_from->ctx);
+        callee_ = * hldr_from->ctx;
+        if ( hldr_from->force_unwind) throw forced_unwind();
+        if ( except_) rethrow_exception( except_);
+    }
+};
+
+template<>
+class push_coroutine_base< void > : private noncopyable
+{
+public:
+    typedef intrusive_ptr< push_coroutine_base >     ptr_t;
+
+private:
+    template<
+        typename X, typename Y, typename Z, typename V, typename W
+    >
+    friend class pull_coroutine_object;
+
+    unsigned int        use_count_;
+
+protected:
+    int                 flags_;
+    exception_ptr       except_;
+    coroutine_context   caller_;
+    coroutine_context   callee_;
+
+    virtual void deallocate_object() = 0;
+
+public:
+    push_coroutine_base( coroutine_context::ctx_fn fn,
+                         stack_context * stack_ctx,
+                         bool unwind, bool preserve_fpu) :
+        use_count_( 0),
+        flags_( 0),
+        except_(),
+        caller_(),
+        callee_( fn, stack_ctx)
+    {
+        if ( unwind) flags_ |= flag_force_unwind;
+        if ( preserve_fpu) flags_ |= flag_preserve_fpu;
+    }
+
+    push_coroutine_base( coroutine_context const& callee,
+                         bool unwind, bool preserve_fpu) :
+        use_count_( 0),
+        flags_( 0),
+        except_(),
+        caller_(),
+        callee_( callee)
+    {
+        if ( unwind) flags_ |= flag_force_unwind;
+        if ( preserve_fpu) flags_ |= flag_preserve_fpu;
+    }
+
+    virtual ~push_coroutine_base()
+    {}
+
+    bool force_unwind() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_force_unwind); }
+
+    bool unwind_requested() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_unwind_stack); }
+
+    bool preserve_fpu() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_preserve_fpu); }
+
+    bool is_complete() const BOOST_NOEXCEPT
+    { return 0 != ( flags_ & flag_complete); }
+
+    friend inline void intrusive_ptr_add_ref( push_coroutine_base * p) BOOST_NOEXCEPT
+    { ++p->use_count_; }
+
+    friend inline void intrusive_ptr_release( push_coroutine_base * p) BOOST_NOEXCEPT
+    { if ( --p->use_count_ == 0) p->deallocate_object(); }
+
+    void push()
+    {
+        BOOST_ASSERT( ! is_complete() );
+
+        holder< void > hldr_to( & caller_);
+        holder< void > * hldr_from(
+            reinterpret_cast< holder< void > * >(
+                hldr_to.ctx->jump(
+                    callee_,
+                    reinterpret_cast< intptr_t >( & hldr_to),
+                    preserve_fpu() ) ) );
+        BOOST_ASSERT( hldr_from->ctx);
+        callee_ = * hldr_from->ctx;
+        if ( hldr_from->force_unwind) throw forced_unwind();
+        if ( except_) rethrow_exception( except_);
+    }
+};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_BASE_H
diff --git a/include/boost/coroutine/v2/detail/push_coroutine_caller.hpp b/include/boost/coroutine/v2/detail/push_coroutine_caller.hpp
new file mode 100644
index 0000000..1358250
--- /dev/null
+++ b/include/boost/coroutine/v2/detail/push_coroutine_caller.hpp
@@ -0,0 +1,56 @@
+//          Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_V2_DETAIL_PUSH_COROUTINE_CALLER_H
+#define BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_CALLER_H
+
+#include <boost/config.hpp>
+#include <boost/context/fcontext.hpp>
+
+#include <boost/coroutine/detail/config.hpp>
+#include <boost/coroutine/v2/detail/push_coroutine_base.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+template< typename Arg, typename Allocator >
+class push_coroutine_caller : public  push_coroutine_base< Arg >
+{
+public:
+    typedef typename Allocator::template rebind<
+        push_coroutine_caller< Arg, Allocator >
+    >::other   allocator_t;
+
+    push_coroutine_caller( coroutine_context const& callee, bool unwind,
+                           bool preserve_fpu, allocator_t const& alloc) BOOST_NOEXCEPT :
+        push_coroutine_base< Arg >( callee, unwind, preserve_fpu),
+        alloc_( alloc)
+    {}
+
+    void deallocate_object()
+    { destroy_( alloc_, this); }
+
+private:
+    allocator_t   alloc_;
+
+    static void destroy_( allocator_t & alloc, push_coroutine_caller * p)
+    {
+        alloc.destroy( p);
+        alloc.deallocate( p, 1);
+    }
+};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_CALLER_H
diff --git a/include/boost/coroutine/v2/detail/push_coroutine_object.hpp b/include/boost/coroutine/v2/detail/push_coroutine_object.hpp
new file mode 100644
index 0000000..2fc439a
--- /dev/null
+++ b/include/boost/coroutine/v2/detail/push_coroutine_object.hpp
@@ -0,0 +1,823 @@
+
+//          Copyright Oliver Kowalke 2009.
+// 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_COROUTINES_V2_DETAIL_PUSH_COROUTINE_OBJECT_H
+#define BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_OBJECT_H
+
+#include <cstddef>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/exception_ptr.hpp>
+#include <boost/move/move.hpp>
+#include <boost/ref.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/type_traits/function_traits.hpp>
+#include <boost/utility.hpp>
+
+#include <boost/coroutine/attributes.hpp>
+#include <boost/coroutine/detail/config.hpp>
+#include <boost/coroutine/detail/exceptions.hpp>
+#include <boost/coroutine/detail/flags.hpp>
+#include <boost/coroutine/detail/holder.hpp>
+#include <boost/coroutine/detail/param.hpp>
+#include <boost/coroutine/detail/stack_tuple.hpp>
+#include <boost/coroutine/detail/trampoline.hpp>
+#include <boost/coroutine/flags.hpp>
+#include <boost/coroutine/stack_context.hpp>
+#include <boost/coroutine/v2/detail/push_coroutine_base.hpp>
+
+#ifdef BOOST_MSVC
+ #pragma warning (push)
+ #pragma warning (disable: 4355) // using 'this' in initializer list
+#endif
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_PREFIX
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+template<
+    typename Arg, typename Fn,
+    typename StackAllocator, typename Allocator,
+    typename Caller
+>
+class push_coroutine_object : private stack_tuple< StackAllocator >,
+                              public push_coroutine_base< Arg >
+{
+public:
+    typedef typename Allocator::template rebind<
+        push_coroutine_object<
+            Arg, Fn, StackAllocator, Allocator, Caller
+        >
+    >::other                                            allocator_t;
+
+private:
+    typedef stack_tuple< StackAllocator >               pbase_type;
+    typedef push_coroutine_base< Arg >                  base_type;
+
+    Fn                      fn_;
+    allocator_t             alloc_;
+
+    static void destroy_( allocator_t & alloc, push_coroutine_object * p)
+    {
+        alloc.destroy( p);
+        alloc.deallocate( p, 1);
+    }
+
+    push_coroutine_object( push_coroutine_object &);
+    push_coroutine_object & operator=( push_coroutine_object const&);
+
+    void enter_()
+    {
+        holder< void > * hldr_from(
+            reinterpret_cast< holder< void > * >(
+                this->caller_.jump(
+                    this->callee_,
+                    reinterpret_cast< intptr_t >( this),
+                    this->preserve_fpu() ) ) );
+        this->callee_ = * hldr_from->ctx;
+        if ( this->except_) rethrow_exception( this->except_);
+    }
+
+    void unwind_stack_() BOOST_NOEXCEPT
+    {
+        BOOST_ASSERT( ! this->is_complete() );
+
+        this->flags_ |= flag_unwind_stack;
+        holder< Arg > hldr_to( & this->caller_, true);
+        this->caller_.jump(
+            this->callee_,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        this->flags_ &= ~flag_unwind_stack;
+
+        BOOST_ASSERT( this->is_complete() );
+    }
+
+public:
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+    push_coroutine_object( Fn && fn, attributes const& attr,
+                           StackAllocator const& stack_alloc,
+                           allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< push_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( forward< Fn >( fn) ),
+        alloc_( alloc)
+    { enter_(); }
+#else
+    push_coroutine_object( Fn fn, attributes const& attr,
+                           StackAllocator const& stack_alloc,
+                           allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< push_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( fn),
+        alloc_( alloc)
+    { enter_(); }
+
+    push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
+                      StackAllocator const& stack_alloc,
+                      allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< push_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( fn),
+        alloc_( alloc)
+    { enter_(); }
+#endif
+
+    ~push_coroutine_object()
+    {
+        if ( ! this->is_complete() && this->force_unwind() )
+            unwind_stack_();
+    }
+
+    void run()
+    {
+        coroutine_context callee;
+        coroutine_context caller;
+
+        {
+            holder< void > hldr_to( & caller);
+            holder< Arg > * hldr_from(
+                reinterpret_cast< holder< Arg > * >(
+                    caller.jump(
+                        this->caller_,
+                        reinterpret_cast< intptr_t >( & hldr_to),
+                        this->preserve_fpu() ) ) );
+            BOOST_ASSERT( hldr_from->ctx);
+            BOOST_ASSERT( hldr_from->data);
+
+            // create pull_coroutine
+            Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_, hldr_from->data);
+            try
+            { fn_( c); }
+            catch ( forced_unwind const&)
+            {}
+            catch (...)
+            { this->except_ = current_exception(); }
+            callee = c.impl_->callee_;
+        }
+
+        this->flags_ |= flag_complete;
+        holder< Arg > hldr_to( & caller);
+        caller.jump(
+            callee,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        BOOST_ASSERT_MSG( false, "push_coroutine is complete");
+    }
+
+    void deallocate_object()
+    { destroy_( alloc_, this); }
+};
+
+template<
+    typename Arg, typename Fn,
+    typename StackAllocator, typename Allocator,
+    typename Caller
+>
+class push_coroutine_object< Arg, reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
+    private stack_tuple< StackAllocator >,
+    public push_coroutine_base< Arg >
+{
+public:
+    typedef typename Allocator::template rebind<
+        push_coroutine_object<
+            Arg, Fn, StackAllocator, Allocator, Caller
+        >
+    >::other                                            allocator_t;
+
+private:
+    typedef stack_tuple< StackAllocator >               pbase_type;
+    typedef push_coroutine_base< Arg >                  base_type;
+
+    Fn                      fn_;
+    allocator_t             alloc_;
+
+    static void destroy_( allocator_t & alloc, push_coroutine_object * p)
+    {
+        alloc.destroy( p);
+        alloc.deallocate( p, 1);
+    }
+
+    push_coroutine_object( push_coroutine_object &);
+    push_coroutine_object & operator=( push_coroutine_object const&);
+
+    void enter_()
+    {
+        holder< void > * hldr_from(
+            reinterpret_cast< holder< void > * >(
+                this->caller_.jump(
+                    this->callee_,
+                    reinterpret_cast< intptr_t >( this),
+                    this->preserve_fpu() ) ) );
+        this->callee_ = * hldr_from->ctx;
+        if ( this->except_) rethrow_exception( this->except_);
+    }
+
+    void unwind_stack_() BOOST_NOEXCEPT
+    {
+        BOOST_ASSERT( ! this->is_complete() );
+
+        this->flags_ |= flag_unwind_stack;
+        holder< Arg > hldr_to( & this->caller_, true);
+        this->caller_.jump(
+            this->callee_,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        this->flags_ &= ~flag_unwind_stack;
+
+        BOOST_ASSERT( this->is_complete() );
+    }
+
+public:
+    push_coroutine_object( reference_wrapper< Fn > fn, attributes const& attr,
+                           StackAllocator const& stack_alloc,
+                           allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< push_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( fn),
+        alloc_( alloc)
+    { enter_(); }
+
+    ~push_coroutine_object()
+    {
+        if ( ! this->is_complete() && this->force_unwind() )
+            unwind_stack_();
+    }
+
+    void run()
+    {
+        coroutine_context callee;
+        coroutine_context caller;
+
+        {
+            holder< void > hldr_to( & caller);
+            holder< Arg > * hldr_from(
+                reinterpret_cast< holder< Arg > * >(
+                    caller.jump(
+                        this->caller_,
+                        reinterpret_cast< intptr_t >( & hldr_to),
+                        this->preserve_fpu() ) ) );
+            BOOST_ASSERT( hldr_from->ctx);
+            BOOST_ASSERT( hldr_from->data);
+
+            // create pull_coroutine
+            Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_, hldr_from->data);
+            try
+            { fn_( c); }
+            catch ( forced_unwind const&)
+            {}
+            catch (...)
+            { this->except_ = current_exception(); }
+            callee = c.impl_->callee_;
+        }
+
+        this->flags_ |= flag_complete;
+        holder< Arg > hldr_to( & caller);
+        caller.jump(
+            callee,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        BOOST_ASSERT_MSG( false, "push_coroutine is complete");
+    }
+
+    void deallocate_object()
+    { destroy_( alloc_, this); }
+};
+
+template<
+    typename Arg, typename Fn,
+    typename StackAllocator, typename Allocator,
+    typename Caller
+>
+class push_coroutine_object< Arg, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
+    private stack_tuple< StackAllocator >,
+    public push_coroutine_base< Arg >
+{
+public:
+    typedef typename Allocator::template rebind<
+        push_coroutine_object<
+            Arg, Fn, StackAllocator, Allocator, Caller
+        >
+    >::other                                            allocator_t;
+
+private:
+    typedef stack_tuple< StackAllocator >               pbase_type;
+    typedef push_coroutine_base< Arg >                  base_type;
+
+    Fn                      fn_;
+    allocator_t             alloc_;
+
+    static void destroy_( allocator_t & alloc, push_coroutine_object * p)
+    {
+        alloc.destroy( p);
+        alloc.deallocate( p, 1);
+    }
+
+    push_coroutine_object( push_coroutine_object &);
+    push_coroutine_object & operator=( push_coroutine_object const&);
+
+    void enter_()
+    {
+        holder< void > * hldr_from(
+            reinterpret_cast< holder< void > * >(
+                this->caller_.jump(
+                    this->callee_,
+                    reinterpret_cast< intptr_t >( this),
+                    this->preserve_fpu() ) ) );
+        this->callee_ = * hldr_from->ctx;
+        if ( this->except_) rethrow_exception( this->except_);
+    }
+
+    void unwind_stack_() BOOST_NOEXCEPT
+    {
+        BOOST_ASSERT( ! this->is_complete() );
+
+        this->flags_ |= flag_unwind_stack;
+        holder< Arg > hldr_to( & this->caller_, true);
+        this->caller_.jump(
+            this->callee_,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        this->flags_ &= ~flag_unwind_stack;
+
+        BOOST_ASSERT( this->is_complete() );
+    }
+
+public:
+    push_coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr,
+                      StackAllocator const& stack_alloc,
+                      allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< push_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( fn),
+        alloc_( alloc)
+    { enter_(); }
+
+    ~push_coroutine_object()
+    {
+        if ( ! this->is_complete() && this->force_unwind() )
+            unwind_stack_();
+    }
+
+    void run()
+    {
+        coroutine_context callee;
+        coroutine_context caller;
+
+        {
+            holder< void > hldr_to( & caller);
+            holder< Arg > * hldr_from(
+                reinterpret_cast< holder< Arg > * >(
+                    caller.jump(
+                        this->caller_,
+                        reinterpret_cast< intptr_t >( & hldr_to),
+                        this->preserve_fpu() ) ) );
+            BOOST_ASSERT( hldr_from->ctx);
+            BOOST_ASSERT( hldr_from->data);
+
+            // create pull_coroutine
+            Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_, hldr_from->data);
+            try
+            { fn_( c); }
+            catch ( forced_unwind const&)
+            {}
+            catch (...)
+            { this->except_ = current_exception(); }
+            callee = c.impl_->callee_;
+        }
+
+        this->flags_ |= flag_complete;
+        holder< Arg > hldr_to( & caller);
+        caller.jump(
+            callee,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        BOOST_ASSERT_MSG( false, "push_coroutine is complete");
+    }
+
+    void deallocate_object()
+    { destroy_( alloc_, this); }
+};
+
+template<
+    typename Fn,
+    typename StackAllocator, typename Allocator,
+    typename Caller
+>
+class push_coroutine_object< void, Fn, StackAllocator, Allocator, Caller > :
+    private stack_tuple< StackAllocator >,
+    public push_coroutine_base< void >
+{
+public:
+    typedef typename Allocator::template rebind<
+        push_coroutine_object<
+            void, Fn, StackAllocator, Allocator, Caller
+        >
+    >::other                                            allocator_t;
+
+private:
+    typedef stack_tuple< StackAllocator >               pbase_type;
+    typedef push_coroutine_base< void >                 base_type;
+
+    Fn                      fn_;
+    allocator_t             alloc_;
+
+    static void destroy_( allocator_t & alloc, push_coroutine_object * p)
+    {
+        alloc.destroy( p);
+        alloc.deallocate( p, 1);
+    }
+
+    push_coroutine_object( push_coroutine_object &);
+    push_coroutine_object & operator=( push_coroutine_object const&);
+
+    void enter_()
+    {
+        holder< void > * hldr_from(
+            reinterpret_cast< holder< void > * >(
+                this->caller_.jump(
+                    this->callee_,
+                    reinterpret_cast< intptr_t >( this),
+                    this->preserve_fpu() ) ) );
+        this->callee_ = * hldr_from->ctx;
+        if ( this->except_) rethrow_exception( this->except_);
+    }
+
+    void unwind_stack_() BOOST_NOEXCEPT
+    {
+        BOOST_ASSERT( ! this->is_complete() );
+
+        this->flags_ |= flag_unwind_stack;
+        holder< void > hldr_to( & this->caller_, true);
+        this->caller_.jump(
+            this->callee_,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        this->flags_ &= ~flag_unwind_stack;
+
+        BOOST_ASSERT( this->is_complete() );
+    }
+
+public:
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+    push_coroutine_object( Fn && fn, attributes const& attr,
+                           StackAllocator const& stack_alloc,
+                           allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< push_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( forward< Fn >( fn) ),
+        alloc_( alloc)
+    { enter_(); }
+#else
+    push_coroutine_object( Fn fn, attributes const& attr,
+                           StackAllocator const& stack_alloc,
+                           allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< push_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( fn),
+        alloc_( alloc)
+    { enter_(); }
+
+    push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attr,
+                      StackAllocator const& stack_alloc,
+                      allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< push_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( fn),
+        alloc_( alloc)
+    { enter_(); }
+#endif
+
+    ~push_coroutine_object()
+    {
+        if ( ! this->is_complete() && this->force_unwind() )
+            unwind_stack_();
+    }
+
+    void run()
+    {
+        coroutine_context callee;
+        coroutine_context caller;
+
+        {
+            holder< void > hldr_to( & caller);
+            holder< void > * hldr_from(
+                reinterpret_cast< holder< void > * >(
+                    caller.jump(
+                        this->caller_,
+                        reinterpret_cast< intptr_t >( & hldr_to),
+                        this->preserve_fpu() ) ) );
+            BOOST_ASSERT( hldr_from->ctx);
+
+            // create pull_coroutine
+            Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_);
+            try
+            { fn_( c); }
+            catch ( forced_unwind const&)
+            {}
+            catch (...)
+            { this->except_ = current_exception(); }
+            callee = c.impl_->callee_;
+        }
+
+        this->flags_ |= flag_complete;
+        holder< void > hldr_to( & caller);
+        caller.jump(
+            callee,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        BOOST_ASSERT_MSG( false, "push_coroutine is complete");
+    }
+
+    void deallocate_object()
+    { destroy_( alloc_, this); }
+};
+
+template<
+    typename Fn,
+    typename StackAllocator, typename Allocator,
+    typename Caller
+>
+class push_coroutine_object< void, reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
+    private stack_tuple< StackAllocator >,
+    public push_coroutine_base< void >
+{
+public:
+    typedef typename Allocator::template rebind<
+        push_coroutine_object<
+            void, Fn, StackAllocator, Allocator, Caller
+        >
+    >::other                                            allocator_t;
+
+private:
+    typedef stack_tuple< StackAllocator >               pbase_type;
+    typedef push_coroutine_base< void >                 base_type;
+
+    Fn                      fn_;
+    allocator_t             alloc_;
+
+    static void destroy_( allocator_t & alloc, push_coroutine_object * p)
+    {
+        alloc.destroy( p);
+        alloc.deallocate( p, 1);
+    }
+
+    push_coroutine_object( push_coroutine_object &);
+    push_coroutine_object & operator=( push_coroutine_object const&);
+
+    void enter_()
+    {
+        holder< void > * hldr_from(
+            reinterpret_cast< holder< void > * >(
+                this->caller_.jump(
+                    this->callee_,
+                    reinterpret_cast< intptr_t >( this),
+                    this->preserve_fpu() ) ) );
+        this->callee_ = * hldr_from->ctx;
+        if ( this->except_) rethrow_exception( this->except_);
+    }
+
+    void unwind_stack_() BOOST_NOEXCEPT
+    {
+        BOOST_ASSERT( ! this->is_complete() );
+
+        this->flags_ |= flag_unwind_stack;
+        holder< void > hldr_to( & this->caller_, true);
+        this->caller_.jump(
+            this->callee_,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        this->flags_ &= ~flag_unwind_stack;
+
+        BOOST_ASSERT( this->is_complete() );
+    }
+
+public:
+    push_coroutine_object( reference_wrapper< Fn > fn, attributes const& attr,
+                           StackAllocator const& stack_alloc,
+                           allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< push_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( fn),
+        alloc_( alloc)
+    { enter_(); }
+
+    ~push_coroutine_object()
+    {
+        if ( ! this->is_complete() && this->force_unwind() )
+            unwind_stack_();
+    }
+
+    void run()
+    {
+        coroutine_context callee;
+        coroutine_context caller;
+
+        {
+            holder< void > hldr_to( & caller);
+            holder< void > * hldr_from(
+                reinterpret_cast< holder< void > * >(
+                    caller.jump(
+                        this->caller_,
+                        reinterpret_cast< intptr_t >( & hldr_to),
+                        this->preserve_fpu() ) ) );
+            BOOST_ASSERT( hldr_from->ctx);
+
+            // create pull_coroutine
+            Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_);
+            try
+            { fn_( c); }
+            catch ( forced_unwind const&)
+            {}
+            catch (...)
+            { this->except_ = current_exception(); }
+            callee = c.impl_->callee_;
+        }
+
+        this->flags_ |= flag_complete;
+        holder< void > hldr_to( & caller);
+        caller.jump(
+            callee,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        BOOST_ASSERT_MSG( false, "push_coroutine is complete");
+    }
+
+    void deallocate_object()
+    { destroy_( alloc_, this); }
+};
+
+template<
+    typename Fn,
+    typename StackAllocator, typename Allocator,
+    typename Caller
+>
+class push_coroutine_object< void, const reference_wrapper< Fn >, StackAllocator, Allocator, Caller > :
+    private stack_tuple< StackAllocator >,
+    public push_coroutine_base< void >
+{
+public:
+    typedef typename Allocator::template rebind<
+        push_coroutine_object<
+            void, Fn, StackAllocator, Allocator, Caller
+        >
+    >::other                                            allocator_t;
+
+private:
+    typedef stack_tuple< StackAllocator >               pbase_type;
+    typedef push_coroutine_base< void >                 base_type;
+
+    Fn                      fn_;
+    allocator_t             alloc_;
+
+    static void destroy_( allocator_t & alloc, push_coroutine_object * p)
+    {
+        alloc.destroy( p);
+        alloc.deallocate( p, 1);
+    }
+
+    push_coroutine_object( push_coroutine_object &);
+    push_coroutine_object & operator=( push_coroutine_object const&);
+
+    void enter_()
+    {
+        holder< void > * hldr_from(
+            reinterpret_cast< holder< void > * >(
+                this->caller_.jump(
+                    this->callee_,
+                    reinterpret_cast< intptr_t >( this),
+                    this->preserve_fpu() ) ) );
+        this->callee_ = * hldr_from->ctx;
+        if ( this->except_) rethrow_exception( this->except_);
+    }
+
+    void unwind_stack_() BOOST_NOEXCEPT
+    {
+        BOOST_ASSERT( ! this->is_complete() );
+
+        this->flags_ |= flag_unwind_stack;
+        holder< void > hldr_to( & this->caller_, true);
+        this->caller_.jump(
+            this->callee_,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        this->flags_ &= ~flag_unwind_stack;
+
+        BOOST_ASSERT( this->is_complete() );
+    }
+
+public:
+    push_coroutine_object( const reference_wrapper< Fn > fn, attributes const& attr,
+                      StackAllocator const& stack_alloc,
+                      allocator_t const& alloc) :
+        pbase_type( stack_alloc, attr.size),
+        base_type(
+            trampoline1< push_coroutine_object >,
+            & this->stack_ctx,
+            stack_unwind == attr.do_unwind,
+            fpu_preserved == attr.preserve_fpu),
+        fn_( fn),
+        alloc_( alloc)
+    { enter_(); }
+
+    ~push_coroutine_object()
+    {
+        if ( ! this->is_complete() && this->force_unwind() )
+            unwind_stack_();
+    }
+
+    void run()
+    {
+        coroutine_context callee;
+        coroutine_context caller;
+
+        {
+            holder< void > hldr_to( & caller);
+            holder< void > * hldr_from(
+                reinterpret_cast< holder< void > * >(
+                    caller.jump(
+                        this->caller_,
+                        reinterpret_cast< intptr_t >( & hldr_to),
+                        this->preserve_fpu() ) ) );
+            BOOST_ASSERT( hldr_from->ctx);
+
+            // create pull_coroutine
+            Caller c( * hldr_from->ctx, false, this->preserve_fpu(), alloc_);
+            try
+            { fn_( c); }
+            catch ( forced_unwind const&)
+            {}
+            catch (...)
+            { this->except_ = current_exception(); }
+            callee = c.impl_->callee_;
+        }
+
+        this->flags_ |= flag_complete;
+        holder< void > hldr_to( & caller);
+        caller.jump(
+            callee,
+            reinterpret_cast< intptr_t >( & hldr_to),
+            this->preserve_fpu() );
+        BOOST_ASSERT_MSG( false, "push_coroutine is complete");
+    }
+
+    void deallocate_object()
+    { destroy_( alloc_, this); }
+};
+
+}}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+#  include BOOST_ABI_SUFFIX
+#endif
+
+#ifdef BOOST_MSVC
+ #pragma warning (pop)
+#endif
+
+#endif // BOOST_COROUTINES_V2_DETAIL_PUSH_COROUTINE_OBJECT_H
diff --git a/performance/performance.cpp b/performance/performance.cpp
index c9ac8ab..67ec895 100644
--- a/performance/performance.cpp
+++ b/performance/performance.cpp
@@ -27,25 +27,24 @@
 
 namespace coro = boost::coroutines;
 
-typedef coro::coroutine< void() >   coro_t;
+# define COUNTER BOOST_PP_LIMIT_MAG
 
-#define COUNTER BOOST_PP_LIMIT_MAG
-
-#define CALL_COROUTINE(z,n,unused) \
+# define CALL_COROUTINE(z,n,unused) \
     c();
 
-void fn( coro_t::caller_type & c)
+#ifdef BOOST_COROUTINES_V2
+void fn( boost::coroutines::push_coroutine< void > & c)
 { while ( true) c(); }
 
-#ifdef BOOST_CONTEXT_CYCLE
+# ifdef BOOST_CONTEXT_CYCLE
 cycle_t test_cycles( cycle_t ov, coro::flag_fpu_t preserve_fpu)
 {
-#if defined(BOOST_USE_SEGMENTED_STACKS)
-    coro_t c( fn, coro::attributes( preserve_fpu) );
-#else
+#  if defined(BOOST_USE_SEGMENTED_STACKS)
+    boost::coroutines::pull_coroutine< void > c( fn, coro::attributes( preserve_fpu) );
+#  else
     coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc;
-    coro_t c( fn, coro::attributes( preserve_fpu), alloc);
-#endif
+    boost::coroutines::pull_coroutine< void > c( fn, coro::attributes( preserve_fpu), alloc);
+#  endif
 
     // cache warum-up
 BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~)
@@ -61,17 +60,17 @@ BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~)
 
     return total;
 }
-#endif
+# endif
 
-#if _POSIX_C_SOURCE >= 199309L
+# if _POSIX_C_SOURCE >= 199309L
 zeit_t test_zeit( zeit_t ov, coro::flag_fpu_t preserve_fpu)
 {
-#if defined(BOOST_USE_SEGMENTED_STACKS)
-    coro_t c( fn, coro::attributes( preserve_fpu) );
-#else
+#  if defined(BOOST_USE_SEGMENTED_STACKS)
+    boost::coroutines::pull_coroutine< void > c( fn, coro::attributes( preserve_fpu) );
+#  else
     coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc;
-    coro_t c( fn, coro::attributes( preserve_fpu), alloc);
-#endif
+    boost::coroutines::pull_coroutine< void > c( fn, coro::attributes( preserve_fpu), alloc);
+#  endif
 
     // cache warum-up
 BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~)
@@ -87,6 +86,64 @@ BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~)
 
     return total;
 }
+# endif
+#else
+typedef coro::coroutine< void() >   coro_t;
+
+void fn( coro_t::caller_type & c)
+{ while ( true) c(); }
+
+# ifdef BOOST_CONTEXT_CYCLE
+cycle_t test_cycles( cycle_t ov, coro::flag_fpu_t preserve_fpu)
+{
+#  if defined(BOOST_USE_SEGMENTED_STACKS)
+    coro_t c( fn, coro::attributes( preserve_fpu) );
+#  else
+    coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc;
+    coro_t c( fn, coro::attributes( preserve_fpu), alloc);
+#  endif
+
+    // cache warum-up
+BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~)
+
+    cycle_t start( cycles() );
+BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~)
+    cycle_t total( cycles() - start);
+
+    // we have two jumps and two measuremt-overheads
+    total -= ov; // overhead of measurement
+    total /= COUNTER; // per call
+    total /= 2; // 2x jump_to c1->c2 && c2->c1
+
+    return total;
+}
+# endif
+
+# if _POSIX_C_SOURCE >= 199309L
+zeit_t test_zeit( zeit_t ov, coro::flag_fpu_t preserve_fpu)
+{
+#  if defined(BOOST_USE_SEGMENTED_STACKS)
+    coro_t c( fn, coro::attributes( preserve_fpu) );
+#  else
+    coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc;
+    coro_t c( fn, coro::attributes( preserve_fpu), alloc);
+#  endif
+
+    // cache warum-up
+BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~)
+
+    zeit_t start( zeit() );
+BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~)
+    zeit_t total( zeit() - start);
+
+    // we have two jumps and two measuremt-overheads
+    total -= ov; // overhead of measurement
+    total /= BOOST_PP_LIMIT_MAG; // per call
+    total /= 2; // 2x jump_to c1->c2 && c2->c1
+
+    return total;
+}
+# endif
 #endif
 
 int main( int argc, char * argv[])
diff --git a/test/test_coroutine.cpp b/test/test_coroutine.cpp
index c2adea2..1361b0c 100644
--- a/test/test_coroutine.cpp
+++ b/test/test_coroutine.cpp
@@ -30,7 +30,487 @@ namespace coro = boost::coroutines;
 int value1 = 0;
 std::string value2 = "";
 bool value3 = false;
+double value4 = .0;
+int * value5 = 0;
+int& value6 = value1;
+int& value7 = value1;
+int value8 = 0;
+int value9 = 0;
 
+#ifdef BOOST_COROUTINES_V2
+struct X : private boost::noncopyable
+{
+    X() { value1 = 7; }
+    ~X() { value1 = 0; }
+};
+
+class copyable
+{
+public:
+    bool    state;
+
+    copyable() :
+        state( false)
+    {}
+
+    copyable( int) :
+        state( true)
+    {}
+
+    void operator()( coro::push_coroutine< int > &)
+    { value3 = state; }
+};
+
+class moveable
+{
+private:
+    BOOST_MOVABLE_BUT_NOT_COPYABLE( moveable);
+
+public:
+    bool    state;
+
+    moveable() :
+        state( false)
+    {}
+
+    moveable( int) :
+        state( true)
+    {}
+
+    moveable( BOOST_RV_REF( moveable) other) :
+        state( false)
+    { std::swap( state, other.state); }
+
+    moveable & operator=( BOOST_RV_REF( moveable) other)
+    {
+        if ( this == & other) return * this;
+        moveable tmp( boost::move( other) );
+        std::swap( state, tmp.state);
+        return * this;
+    }
+
+    void operator()( coro::push_coroutine< int > &)
+    { value3 = state; }
+};
+
+struct my_exception {};
+
+void f1( coro::push_coroutine< void > & c)
+{ c(); }
+
+void f2( coro::push_coroutine< void > &)
+{ ++value1; }
+
+void f3( coro::push_coroutine< void > & c)
+{
+    ++value1;
+    c();
+    ++value1;
+}
+
+void f4( coro::push_coroutine< int > & c)
+{
+    c( 3);
+    c( 7);
+}
+
+void f5( coro::push_coroutine< std::string > & c)
+{
+    std::string res("abc");
+    c( res);
+    res = "xyz";
+    c( res);
+}
+
+void f6( coro::pull_coroutine< int > & c)
+{ value1 = c.get(); }
+
+void f7( coro::pull_coroutine< std::string > & c)
+{ value2 = c.get(); }
+
+void f8( coro::pull_coroutine< boost::tuple< double, double > > & c)
+{
+    double x = 0, y = 0;
+    boost::tie( x, y) = c.get();
+    value4 = x + y;
+    c();
+    boost::tie( x, y) = c.get();
+    value4 = x + y;
+}
+
+void f9( coro::pull_coroutine< int * > & c)
+{ value5 = c.get(); }
+
+void f91( coro::pull_coroutine< int const* > & c)
+{ value5 = const_cast< int * >( c.get() ); }
+
+void f10( coro::pull_coroutine< int & > & c)
+{
+    int const& i = c.get();
+    value5 = const_cast< int * >( & i);
+}
+
+void f101( coro::pull_coroutine< int const& > & c)
+{
+    int const& i = c.get();
+    value5 = const_cast< int * >( & i);
+}
+
+void f11( coro::pull_coroutine< boost::tuple< int, int > > & c)
+{
+    boost::tie( value8, value9) = c.get();
+}
+
+void f12( coro::pull_coroutine< void > & c)
+{
+    X x_;
+    c();
+    c();
+}
+
+template< typename E >
+void f14( coro::pull_coroutine< void > &, E const& e)
+{ throw e; }
+
+void f16( coro::push_coroutine< int > & c)
+{
+    c( 1);
+    c( 2);
+    c( 3);
+    c( 4);
+    c( 5);
+}
+
+void f17( coro::pull_coroutine< int > & c, std::vector< int > & vec)
+{
+    int x = c.get();
+    while ( 5 > x)
+    {
+        vec.push_back( x);
+        x = c().get();
+    }
+}
+
+void f19( coro::push_coroutine< const int* > & c, std::vector< const int * > & vec)
+{
+    BOOST_FOREACH( const int * ptr, vec)
+    { c( ptr); }
+}
+
+void test_move()
+{
+    {
+        coro::pull_coroutine< void > coro1;
+        coro::pull_coroutine< void > coro2( f1);
+        BOOST_CHECK( ! coro1);
+        BOOST_CHECK( coro1.empty() );
+        BOOST_CHECK( coro2);
+        BOOST_CHECK( ! coro2.empty() );
+        coro1 = boost::move( coro2);
+        BOOST_CHECK( coro1);
+        BOOST_CHECK( ! coro1.empty() );
+        BOOST_CHECK( ! coro2);
+        BOOST_CHECK( coro2.empty() );
+    }
+
+    {
+        value3 = false;
+        copyable cp( 3);
+        BOOST_CHECK( cp.state);
+        BOOST_CHECK( ! value3);
+        coro::pull_coroutine< int > coro( cp);
+        BOOST_CHECK( cp.state);
+        BOOST_CHECK( value3);
+    }
+
+    {
+        value3 = false;
+        moveable mv( 7);
+        BOOST_CHECK( mv.state);
+        BOOST_CHECK( ! value3);
+        coro::pull_coroutine< int > coro( boost::move( mv) );
+        BOOST_CHECK( ! mv.state);
+        BOOST_CHECK( value3);
+    }
+}
+
+void test_complete()
+{
+    value1 = 0;
+
+    coro::pull_coroutine< void > coro( f2);
+    BOOST_CHECK( ! coro);
+    BOOST_CHECK_EQUAL( ( int)1, value1);
+}
+
+void test_jump()
+{
+    value1 = 0;
+
+    coro::pull_coroutine< void > coro( f3);
+    BOOST_CHECK( coro);
+    BOOST_CHECK_EQUAL( ( int)1, value1);
+    coro();
+    BOOST_CHECK( ! coro);
+    BOOST_CHECK_EQUAL( ( int)2, value1);
+}
+
+void test_result_int()
+{
+    coro::pull_coroutine< int > coro( f4);
+    BOOST_CHECK( coro);
+    int result = coro.get();
+    BOOST_CHECK( coro);
+    BOOST_CHECK_EQUAL( 3, result);
+    result = coro().get();
+    BOOST_CHECK( coro);
+    BOOST_CHECK_EQUAL( 7, result);
+    coro();
+    BOOST_CHECK( ! coro);
+}
+
+void test_result_string()
+{
+    coro::pull_coroutine< std::string > coro( f5);
+    BOOST_CHECK( coro);
+    std::string result = coro.get();
+    BOOST_CHECK( coro);
+    BOOST_CHECK_EQUAL( std::string("abc"), result);
+    result = coro().get();
+    BOOST_CHECK( coro);
+    BOOST_CHECK_EQUAL( std::string("xyz"), result);
+    coro();
+    BOOST_CHECK( ! coro);
+}
+
+void test_arg_int()
+{
+    value1 = 0;
+
+    coro::push_coroutine< int > coro( f6);
+    BOOST_CHECK( coro);
+    coro( 3);
+    BOOST_CHECK( ! coro);
+    BOOST_CHECK_EQUAL( 3, value1);
+}
+
+void test_arg_string()
+{
+    value2 = "";
+
+    coro::push_coroutine< std::string > coro( f7);
+    BOOST_CHECK( coro);
+    coro( std::string("abc") );
+    BOOST_CHECK( ! coro);
+    BOOST_CHECK_EQUAL( std::string("abc"), value2);
+}
+
+void test_fp()
+{
+    value4 = 0;
+
+    coro::push_coroutine< boost::tuple< double, double > > coro( f8);
+    BOOST_CHECK( coro);
+    coro( boost::make_tuple( 7.35, 3.14) );
+    BOOST_CHECK( coro);
+    BOOST_CHECK_EQUAL( ( double) 10.49, value4);
+
+    value4 = 0;
+    coro( boost::make_tuple( 1.15, 3.14) );
+    BOOST_CHECK( ! coro);
+    BOOST_CHECK_EQUAL( ( double) 4.29, value4);
+}
+
+void test_ptr()
+{
+    value5 = 0;
+
+    int a = 3;
+    coro::push_coroutine< int * > coro( f9);
+    BOOST_CHECK( coro);
+    coro( & a);
+    BOOST_CHECK( ! coro);
+    BOOST_CHECK_EQUAL( & a, value5);
+}
+
+void test_const_ptr()
+{
+    value5 = 0;
+
+    int a = 3;
+    coro::push_coroutine< int const* > coro( f91);
+    BOOST_CHECK( coro);
+    coro( & a);
+    BOOST_CHECK( ! coro);
+    BOOST_CHECK_EQUAL( & a, value5);
+}
+
+void test_ref()
+{
+    value5 = 0;
+
+    int a = 3;
+    coro::push_coroutine< int & > coro( f10);
+    BOOST_CHECK( coro);
+    coro( a);
+    BOOST_CHECK( ! coro);
+    BOOST_CHECK_EQUAL( & a, value5);
+}
+
+void test_const_ref()
+{
+    value5 = 0;
+
+    int a = 3;
+    coro::push_coroutine< int const& > coro( f101);
+    BOOST_CHECK( coro);
+    coro( a);
+    BOOST_CHECK( ! coro);
+    BOOST_CHECK_EQUAL( & a, value5);
+}
+
+void test_tuple()
+{
+    value8 = 0;
+    value9 = 0;
+
+    int a = 3, b = 7;
+    boost::tuple< int, int > tpl( a, b);
+    BOOST_CHECK_EQUAL( a, tpl.get< 0 >() );
+    BOOST_CHECK_EQUAL( b, tpl.get< 1 >() );
+    coro::push_coroutine< boost::tuple< int, int > > coro( f11);
+    BOOST_CHECK( coro);
+    coro( tpl);
+    BOOST_CHECK( ! coro);
+    BOOST_CHECK_EQUAL( a, value8);
+    BOOST_CHECK_EQUAL( b, value9);
+}
+
+void test_unwind()
+{
+    value1 = 0;
+    {
+        coro::push_coroutine< void > coro( f12);
+        BOOST_CHECK( coro);
+        BOOST_CHECK_EQUAL( ( int) 0, value1);
+        coro();
+        BOOST_CHECK( coro);
+        BOOST_CHECK_EQUAL( ( int) 7, value1);
+        coro();
+        BOOST_CHECK_EQUAL( ( int) 7, value1);
+    }
+    BOOST_CHECK_EQUAL( ( int) 0, value1);
+}
+
+void test_no_unwind()
+{
+    value1 = 0;
+    {
+        coro::push_coroutine< void > coro(
+            f12,
+            coro::attributes(
+                coro::stack_allocator::default_stacksize(),
+                coro::no_stack_unwind) );
+        BOOST_CHECK( coro);
+        BOOST_CHECK_EQUAL( ( int) 0, value1);
+        coro();
+        BOOST_CHECK( coro);
+        BOOST_CHECK_EQUAL( ( int) 7, value1);
+        coro();
+        BOOST_CHECK_EQUAL( ( int) 7, value1);
+    }
+    BOOST_CHECK_EQUAL( ( int) 7, value1);
+}
+
+void test_exceptions()
+{
+    bool thrown = false;
+    std::runtime_error ex("abc");
+    try
+    {
+        coro::push_coroutine< void > coro( boost::bind( f14< std::runtime_error >, _1, ex) );
+        BOOST_CHECK( coro);
+        coro();
+        BOOST_CHECK( ! coro);
+        BOOST_CHECK( false);
+    }
+    catch ( std::runtime_error const&)
+    { thrown = true; }
+    catch ( std::exception const&)
+    {}
+    catch (...)
+    {}
+    BOOST_CHECK( thrown);
+}
+
+void test_output_iterator()
+{
+    {
+        std::vector< int > vec;
+        coro::pull_coroutine< int > coro( f16);
+        BOOST_FOREACH( int i, coro)
+        { vec.push_back( i); }
+        BOOST_CHECK_EQUAL( ( std::size_t)5, vec.size() );
+        BOOST_CHECK_EQUAL( ( int)1, vec[0] );
+        BOOST_CHECK_EQUAL( ( int)2, vec[1] );
+        BOOST_CHECK_EQUAL( ( int)3, vec[2] );
+        BOOST_CHECK_EQUAL( ( int)4, vec[3] );
+        BOOST_CHECK_EQUAL( ( int)5, vec[4] );
+    }
+    {
+        std::vector< int > vec;
+        coro::pull_coroutine< int > coro( f16);
+        coro::pull_coroutine< int >::iterator e = boost::end( coro);
+        for (
+            coro::pull_coroutine< int >::iterator i = boost::begin( coro);
+            i != e; ++i)
+        { vec.push_back( * i); }
+        BOOST_CHECK_EQUAL( ( std::size_t)5, vec.size() );
+        BOOST_CHECK_EQUAL( ( int)1, vec[0] );
+        BOOST_CHECK_EQUAL( ( int)2, vec[1] );
+        BOOST_CHECK_EQUAL( ( int)3, vec[2] );
+        BOOST_CHECK_EQUAL( ( int)4, vec[3] );
+        BOOST_CHECK_EQUAL( ( int)5, vec[4] );
+    }
+    {
+        int i1 = 1, i2 = 2, i3 = 3;
+        std::vector< const int* > vec_in;
+        vec_in.push_back( & i1);
+        vec_in.push_back( & i2);
+        vec_in.push_back( & i3);
+        std::vector< const int* > vec_out;
+        coro::pull_coroutine< const int* > coro( boost::bind( f19, _1, boost::ref( vec_in) ) );
+        coro::pull_coroutine< const int* >::const_iterator e = boost::const_end( coro);
+        for (
+            coro::pull_coroutine< const int* >::const_iterator i = boost::const_begin( coro);
+            i != e; ++i)
+        { vec_out.push_back( * i); }
+        BOOST_CHECK_EQUAL( ( std::size_t)3, vec_out.size() );
+        BOOST_CHECK_EQUAL( & i1, vec_out[0] );
+        BOOST_CHECK_EQUAL( & i2, vec_out[1] );
+        BOOST_CHECK_EQUAL( & i3, vec_out[2] );
+    }
+}
+
+void test_input_iterator()
+{
+    int counter = 0;
+    std::vector< int > vec;
+    coro::push_coroutine< int > coro(
+        boost::bind( f17, _1, boost::ref( vec) ) );
+    coro::push_coroutine< int >::iterator e( boost::end( coro) );
+    for ( coro::push_coroutine< int >::iterator i( boost::begin( coro) );
+          i != e; ++i)
+    {
+        i = ++counter;
+    }
+    BOOST_CHECK_EQUAL( ( std::size_t)4, vec.size() );
+    BOOST_CHECK_EQUAL( ( int)1, vec[0] );
+    BOOST_CHECK_EQUAL( ( int)2, vec[1] );
+    BOOST_CHECK_EQUAL( ( int)3, vec[2] );
+    BOOST_CHECK_EQUAL( ( int)4, vec[3] );
+}
+#else
 typedef coro::coroutine< void() > coro_void_void;
 typedef coro::coroutine< int() > coro_int_void;
 typedef coro::coroutine< std::string() > coro_string_void;
@@ -40,7 +520,9 @@ typedef coro::coroutine< double(double,double) > coro_double;
 typedef coro::coroutine< int(int,int) > coro_int;
 typedef coro::coroutine< int(int) > coro_int_int;
 typedef coro::coroutine< int*(int*) > coro_ptr;
-typedef coro::coroutine< int const&(int const&) > coro_ref;
+typedef coro::coroutine< int const*(int const*) > coro_const_ptr;
+typedef coro::coroutine< int&(int&) > coro_ref;
+typedef coro::coroutine< int const&(int const&) > coro_const_ref;
 typedef coro::coroutine< boost::tuple<int&,int&>(int&,int&) > coro_tuple;
 typedef coro::coroutine< const int *() > coro_const_int_ptr_void;
 
@@ -146,9 +628,15 @@ void f8( coro_double::caller_type & self)
 void f9( coro_ptr::caller_type & self)
 { self( self.get() ); }
 
+void f91( coro_const_ptr::caller_type & self)
+{ self( self.get() ); }
+
 void f10( coro_ref::caller_type & self)
 { self( self.get() ); }
 
+void f101( coro_const_ref::caller_type & self)
+{ self( self.get() ); }
+
 void f11( coro_tuple::caller_type & self)
 {
     boost::tuple<int&,int&> tpl( self.get().get< 0 >(), self.get().get< 1 >() );
@@ -338,6 +826,18 @@ void test_ptr()
     BOOST_CHECK( ! coro);
 }
 
+void test_const_ptr()
+{
+    int a = 3;
+    coro_const_ptr coro( f91, & a);
+    BOOST_CHECK( coro);
+    int const* res = coro.get();
+    BOOST_CHECK( coro);
+    BOOST_CHECK_EQUAL( & a, res);
+    coro( & a);
+    BOOST_CHECK( ! coro);
+}
+
 void test_ref()
 {
     int a = 3;
@@ -350,6 +850,18 @@ void test_ref()
     BOOST_CHECK( ! coro);
 }
 
+void test_const_ref()
+{
+    int a = 3;
+    coro_const_ref coro( f101, a);
+    BOOST_CHECK( coro);
+    int const& res = coro.get();
+    BOOST_CHECK( coro);
+    BOOST_CHECK_EQUAL( & a, & res);
+    coro( a);
+    BOOST_CHECK( ! coro);
+}
+
 void test_tuple()
 {
     int a = 3, b = 7;
@@ -507,6 +1019,7 @@ void test_post()
     coro( -1);
     BOOST_CHECK( ! coro);
 }
+#endif
 
 boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
 {
@@ -516,15 +1029,19 @@ boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
     test->add( BOOST_TEST_CASE( & test_move) );
     test->add( BOOST_TEST_CASE( & test_complete) );
     test->add( BOOST_TEST_CASE( & test_jump) );
-    test->add( BOOST_TEST_CASE( & test_pre) );
-    test->add( BOOST_TEST_CASE( & test_post) );
     test->add( BOOST_TEST_CASE( & test_result_int) );
     test->add( BOOST_TEST_CASE( & test_result_string) );
     test->add( BOOST_TEST_CASE( & test_arg_int) );
     test->add( BOOST_TEST_CASE( & test_arg_string) );
     test->add( BOOST_TEST_CASE( & test_fp) );
     test->add( BOOST_TEST_CASE( & test_ptr) );
+    test->add( BOOST_TEST_CASE( & test_const_ptr) );
+#ifndef BOOST_COROUTINES_V2
+    test->add( BOOST_TEST_CASE( & test_pre) );
+    test->add( BOOST_TEST_CASE( & test_post) );
+#endif
     test->add( BOOST_TEST_CASE( & test_ref) );
+    test->add( BOOST_TEST_CASE( & test_const_ref) );
     test->add( BOOST_TEST_CASE( & test_tuple) );
     test->add( BOOST_TEST_CASE( & test_unwind) );
     test->add( BOOST_TEST_CASE( & test_no_unwind) );