summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/coroutine
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/coroutine')
-rw-r--r--src/boost/libs/coroutine/README.md14
-rw-r--r--src/boost/libs/coroutine/build/Jamfile.v245
-rw-r--r--src/boost/libs/coroutine/example/asymmetric/Jamfile.v263
-rw-r--r--src/boost/libs/coroutine/example/asymmetric/X.h13
-rw-r--r--src/boost/libs/coroutine/example/asymmetric/chaining.cpp206
-rw-r--r--src/boost/libs/coroutine/example/asymmetric/echo.cpp48
-rw-r--r--src/boost/libs/coroutine/example/asymmetric/exception.cpp53
-rw-r--r--src/boost/libs/coroutine/example/asymmetric/fibonacci.cpp43
-rw-r--r--src/boost/libs/coroutine/example/asymmetric/layout.cpp74
-rw-r--r--src/boost/libs/coroutine/example/asymmetric/parallel.cpp50
-rw-r--r--src/boost/libs/coroutine/example/asymmetric/power.cpp48
-rw-r--r--src/boost/libs/coroutine/example/asymmetric/same_fringe.cpp162
-rw-r--r--src/boost/libs/coroutine/example/asymmetric/segmented_stack.cpp63
-rw-r--r--src/boost/libs/coroutine/example/asymmetric/simple.cpp53
-rw-r--r--src/boost/libs/coroutine/example/asymmetric/test.cpp45
-rw-r--r--src/boost/libs/coroutine/example/asymmetric/tree.h125
-rw-r--r--src/boost/libs/coroutine/example/asymmetric/unwind.cpp45
-rw-r--r--src/boost/libs/coroutine/example/symmetric/Jamfile.v249
-rw-r--r--src/boost/libs/coroutine/example/symmetric/dice_game.cpp70
-rw-r--r--src/boost/libs/coroutine/example/symmetric/merge_arrays.cpp105
-rw-r--r--src/boost/libs/coroutine/example/symmetric/segmented_stack.cpp67
-rw-r--r--src/boost/libs/coroutine/example/symmetric/simple.cpp47
-rw-r--r--src/boost/libs/coroutine/example/symmetric/unwind.cpp51
-rw-r--r--src/boost/libs/coroutine/index.html14
-rw-r--r--src/boost/libs/coroutine/meta/libraries.json15
-rw-r--r--src/boost/libs/coroutine/performance/asymmetric/Jamfile.v283
-rw-r--r--src/boost/libs/coroutine/performance/asymmetric/performance_create_prealloc.cpp116
-rw-r--r--src/boost/libs/coroutine/performance/asymmetric/performance_create_protected.cpp113
-rw-r--r--src/boost/libs/coroutine/performance/asymmetric/performance_create_standard.cpp113
-rw-r--r--src/boost/libs/coroutine/performance/asymmetric/performance_switch.cpp205
-rw-r--r--src/boost/libs/coroutine/performance/asymmetric/segmented/Jamfile.v268
-rw-r--r--src/boost/libs/coroutine/performance/asymmetric/segmented/performance_create_segmented.cpp106
-rw-r--r--src/boost/libs/coroutine/performance/bind_processor.hpp12
-rw-r--r--src/boost/libs/coroutine/performance/bind_processor_aix.cpp25
-rw-r--r--src/boost/libs/coroutine/performance/bind_processor_freebsd.cpp29
-rw-r--r--src/boost/libs/coroutine/performance/bind_processor_hpux.cpp31
-rw-r--r--src/boost/libs/coroutine/performance/bind_processor_linux.cpp30
-rw-r--r--src/boost/libs/coroutine/performance/bind_processor_solaris.cpp26
-rw-r--r--src/boost/libs/coroutine/performance/bind_processor_windows.cpp24
-rw-r--r--src/boost/libs/coroutine/performance/clock.hpp44
-rw-r--r--src/boost/libs/coroutine/performance/cycle.hpp26
-rw-r--r--src/boost/libs/coroutine/performance/cycle_i386.hpp83
-rw-r--r--src/boost/libs/coroutine/performance/cycle_x86-64.hpp79
-rw-r--r--src/boost/libs/coroutine/performance/preallocated_stack_allocator.hpp56
-rw-r--r--src/boost/libs/coroutine/performance/symmetric/Jamfile.v283
-rw-r--r--src/boost/libs/coroutine/performance/symmetric/performance_create_prealloc.cpp114
-rw-r--r--src/boost/libs/coroutine/performance/symmetric/performance_create_protected.cpp112
-rw-r--r--src/boost/libs/coroutine/performance/symmetric/performance_create_standard.cpp112
-rw-r--r--src/boost/libs/coroutine/performance/symmetric/performance_switch.cpp207
-rw-r--r--src/boost/libs/coroutine/performance/symmetric/segmented/Jamfile.v268
-rw-r--r--src/boost/libs/coroutine/performance/symmetric/segmented/performance_create_segmented.cpp105
-rw-r--r--src/boost/libs/coroutine/src/detail/coroutine_context.cpp82
-rw-r--r--src/boost/libs/coroutine/src/exceptions.cpp37
-rw-r--r--src/boost/libs/coroutine/src/posix/stack_traits.cpp112
-rw-r--r--src/boost/libs/coroutine/src/windows/stack_traits.cpp114
-rw-r--r--src/boost/libs/coroutine/test/Jamfile.v233
-rw-r--r--src/boost/libs/coroutine/test/test_asymmetric_coroutine.cpp627
-rw-r--r--src/boost/libs/coroutine/test/test_symmetric_coroutine.cpp604
58 files changed, 5247 insertions, 0 deletions
diff --git a/src/boost/libs/coroutine/README.md b/src/boost/libs/coroutine/README.md
new file mode 100644
index 000000000..2e1458915
--- /dev/null
+++ b/src/boost/libs/coroutine/README.md
@@ -0,0 +1,14 @@
+boost.coroutine
+===============
+
+boost.coroutine provides templates for generalized subroutines which allow multiple entry points for
+suspending and resuming execution at certain locations. It preserves the local state of execution and
+allows re-entering subroutines more than once (useful if state must be kept across function calls).
+
+Coroutines can be viewed as a language-level construct providing a special kind of control flow.
+
+In contrast to threads, which are pre-emptive, coroutines switches are cooperative (programmer controls
+when a switch will happen). The kernel is not involved in the coroutine switches.
+
+Note that boost.coroutine is deprecated - boost.coroutine2 is its successor.
+If you are forced to use a pre-C++11 compiler you should still use boost.coroutine.
diff --git a/src/boost/libs/coroutine/build/Jamfile.v2 b/src/boost/libs/coroutine/build/Jamfile.v2
new file mode 100644
index 000000000..bc32ec4ec
--- /dev/null
+++ b/src/boost/libs/coroutine/build/Jamfile.v2
@@ -0,0 +1,45 @@
+
+# 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)
+
+import feature ;
+import modules ;
+import toolset ;
+
+project boost/coroutine
+ : requirements
+ <library>/boost/context//boost_context
+ <library>/boost/thread//boost_thread
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <link>shared:<define>BOOST_COROUTINES_DYN_LINK=1
+ <define>BOOST_COROUTINES_SOURCE
+ : usage-requirements
+ <link>shared:<define>BOOST_COROUTINES_DYN_LINK=1
+ : source-location ../src
+ ;
+
+alias stack_traits_sources
+ : windows/stack_traits.cpp
+ : <target-os>windows
+ ;
+
+alias stack_traits_sources
+ : posix/stack_traits.cpp
+ ;
+
+explicit stack_traits_sources ;
+
+lib boost_coroutine
+ : detail/coroutine_context.cpp
+ exceptions.cpp
+ stack_traits_sources
+ : <link>shared:<library>../../context/build//boost_context
+ <link>shared:<library>../../thread/build//boost_thread
+ ;
+
+boost-install boost_coroutine ;
diff --git a/src/boost/libs/coroutine/example/asymmetric/Jamfile.v2 b/src/boost/libs/coroutine/example/asymmetric/Jamfile.v2
new file mode 100644
index 000000000..c1cba6735
--- /dev/null
+++ b/src/boost/libs/coroutine/example/asymmetric/Jamfile.v2
@@ -0,0 +1,63 @@
+# Boost.Coroutine Library Examples Jamfile
+
+# 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)
+
+# For more information, see http://www.boost.org/
+
+import common ;
+import feature ;
+import indirect ;
+import modules ;
+import os ;
+import toolset ;
+
+project boost/coroutine/example/asymmetric
+ : requirements
+ <library>/boost/context//boost_context
+ <library>/boost/coroutine//boost_coroutine
+ <library>/boost/program_options//boost_program_options
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <link>shared
+ <threading>multi
+ ;
+
+exe chaining
+ : chaining.cpp
+ ;
+exe echo
+ : echo.cpp
+ ;
+exe exception
+ : exception.cpp
+ ;
+exe fibonacci
+ : fibonacci.cpp
+ ;
+exe layout
+ : layout.cpp
+ ;
+exe parallel
+ : parallel.cpp
+ ;
+exe power
+ : power.cpp
+ ;
+exe same_fringe
+ : same_fringe.cpp
+ ;
+exe segmented_stack
+ : segmented_stack.cpp
+ ;
+exe simple
+ : simple.cpp
+ test.cpp
+ ;
+exe unwind
+ : unwind.cpp
+ ;
diff --git a/src/boost/libs/coroutine/example/asymmetric/X.h b/src/boost/libs/coroutine/example/asymmetric/X.h
new file mode 100644
index 000000000..254d44f65
--- /dev/null
+++ b/src/boost/libs/coroutine/example/asymmetric/X.h
@@ -0,0 +1,13 @@
+#ifndef X_H
+#define X_H
+
+struct X
+{
+ int i;
+
+ X( int i_) :
+ i( i_)
+ {}
+};
+
+#endif // X_H
diff --git a/src/boost/libs/coroutine/example/asymmetric/chaining.cpp b/src/boost/libs/coroutine/example/asymmetric/chaining.cpp
new file mode 100644
index 000000000..4a4dd9979
--- /dev/null
+++ b/src/boost/libs/coroutine/example/asymmetric/chaining.cpp
@@ -0,0 +1,206 @@
+
+// Copyright Nat Goodspeed 2013.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/coroutine/all.hpp>
+
+#include <iostream>
+#include <iomanip>
+#include <string>
+#include <cctype>
+#include <sstream>
+
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+
+typedef boost::coroutines::asymmetric_coroutine<std::string> coro_t;
+
+// deliver each line of input stream to sink as a separate string
+void readlines(coro_t::push_type& sink, std::istream& in)
+{
+ std::string line;
+ while (std::getline(in, line))
+ sink(line);
+}
+
+void tokenize(coro_t::push_type& sink, coro_t::pull_type& source)
+{
+ // This tokenizer doesn't happen to be stateful: you could reasonably
+ // implement it with a single call to push each new token downstream. But
+ // I've worked with stateful tokenizers, in which the meaning of input
+ // characters depends in part on their position within the input line. At
+ // the time, I wished for a way to resume at the suspend point!
+ BOOST_FOREACH(std::string line, source)
+ {
+ std::string::size_type pos = 0;
+ while (pos < line.length())
+ {
+ if (line[pos] == '"')
+ {
+ std::string token;
+ ++pos; // skip open quote
+ while (pos < line.length() && line[pos] != '"')
+ token += line[pos++];
+ ++pos; // skip close quote
+ sink(token); // pass token downstream
+ }
+ else if (std::isspace(line[pos]))
+ {
+ ++pos; // outside quotes, ignore whitespace
+ }
+ else if (std::isalpha(line[pos]))
+ {
+ std::string token;
+ while (pos < line.length() && std::isalpha(line[pos]))
+ token += line[pos++];
+ sink(token); // pass token downstream
+ }
+ else // punctuation
+ {
+ sink(std::string(1, line[pos++]));
+ }
+ }
+ }
+}
+
+void only_words(coro_t::push_type& sink, coro_t::pull_type& source)
+{
+ BOOST_FOREACH(std::string token, source)
+ {
+ if (! token.empty() && std::isalpha(token[0]))
+ sink(token);
+ }
+}
+
+void trace(coro_t::push_type& sink, coro_t::pull_type& source)
+{
+ BOOST_FOREACH(std::string token, source)
+ {
+ std::cout << "trace: '" << token << "'\n";
+ sink(token);
+ }
+}
+
+struct FinalEOL
+{
+ ~FinalEOL() { std::cout << std::endl; }
+};
+
+void layout(coro_t::pull_type& source, int num, int width)
+{
+ // Finish the last line when we leave by whatever means
+ FinalEOL eol;
+
+ // Pull values from upstream, lay them out 'num' to a line
+ for (;;)
+ {
+ for (int i = 0; i < num; ++i)
+ {
+ // when we exhaust the input, stop
+ if (! source)
+ return;
+
+ std::cout << std::setw(width) << source.get();
+ // now that we've handled this item, advance to next
+ source();
+ }
+ // after 'num' items, line break
+ std::cout << std::endl;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ // For example purposes, instead of having a separate text file in the
+ // local filesystem, construct an istringstream to read.
+ std::string data(
+ "This is the first line.\n"
+ "This, the second.\n"
+ "The third has \"a phrase\"!\n"
+ );
+
+ {
+ std::cout << "\nreadlines:\n";
+ std::istringstream infile(data);
+ // Each coroutine-function has a small, specific job to do. Instead of
+ // adding conditional logic to a large, complex input function, the
+ // caller composes smaller functions into the desired processing
+ // chain.
+ coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile)));
+ coro_t::pull_type tracer(boost::bind(trace, _1, boost::ref(reader)));
+ BOOST_FOREACH(std::string line, tracer)
+ {
+ std::cout << "got: " << line << "\n";
+ }
+ }
+
+ {
+ std::cout << "\ncompose a chain:\n";
+ std::istringstream infile(data);
+ coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile)));
+ coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader)));
+ coro_t::pull_type tracer(boost::bind(trace, _1, boost::ref(tokenizer)));
+ BOOST_FOREACH(std::string token, tracer)
+ {
+ // just iterate, we're already pulling through tracer
+ }
+ }
+
+ {
+ std::cout << "\nfilter:\n";
+ std::istringstream infile(data);
+ coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile)));
+ coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader)));
+ coro_t::pull_type filter(boost::bind(only_words, _1, boost::ref(tokenizer)));
+ coro_t::pull_type tracer(boost::bind(trace, _1, boost::ref(filter)));
+ BOOST_FOREACH(std::string token, tracer)
+ {
+ // just iterate, we're already pulling through tracer
+ }
+ }
+
+ {
+ std::cout << "\nlayout() as coroutine::push_type:\n";
+ std::istringstream infile(data);
+ coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile)));
+ coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader)));
+ coro_t::pull_type filter(boost::bind(only_words, _1, boost::ref(tokenizer)));
+ coro_t::push_type writer(boost::bind(layout, _1, 5, 15));
+ BOOST_FOREACH(std::string token, filter)
+ {
+ writer(token);
+ }
+ }
+
+ {
+ std::cout << "\ncalling layout() directly:\n";
+ std::istringstream infile(data);
+ coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile)));
+ coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader)));
+ coro_t::pull_type filter(boost::bind(only_words, _1, boost::ref(tokenizer)));
+ // Because of the symmetry of the API, we can directly call layout()
+ // instead of using it as a coroutine-function.
+ layout(filter, 5, 15);
+ }
+
+ {
+ std::cout << "\nfiltering output:\n";
+ std::istringstream infile(data);
+ coro_t::pull_type reader(boost::bind(readlines, _1, boost::ref(infile)));
+ coro_t::pull_type tokenizer(boost::bind(tokenize, _1, boost::ref(reader)));
+ coro_t::push_type writer(boost::bind(layout, _1, 5, 15));
+ // Because of the symmetry of the API, we can use any of these
+ // chaining functions in a push_type coroutine chain as well.
+ coro_t::push_type filter(boost::bind(only_words, boost::ref(writer), _1));
+ BOOST_FOREACH(std::string token, tokenizer)
+ {
+ filter(token);
+ }
+ }
+
+ std::cout << "\nDone" << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine/example/asymmetric/echo.cpp b/src/boost/libs/coroutine/example/asymmetric/echo.cpp
new file mode 100644
index 000000000..ba3e82e2e
--- /dev/null
+++ b/src/boost/libs/coroutine/example/asymmetric/echo.cpp
@@ -0,0 +1,48 @@
+
+// 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)
+
+#include <boost/coroutine/all.hpp>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <boost/bind.hpp>
+
+typedef boost::coroutines::asymmetric_coroutine< void >::pull_type pull_coro_t;
+typedef boost::coroutines::asymmetric_coroutine< void >::push_type push_coro_t;
+
+void echo( pull_coro_t & source, int i)
+{
+ std::cout << i;
+ source();
+}
+
+void runit( push_coro_t & sink1)
+{
+ std::cout << "started! ";
+ for ( int i = 0; i < 10; ++i)
+ {
+ push_coro_t sink2( boost::bind( echo, _1, i) );
+ while ( sink2)
+ sink2();
+ sink1();
+ }
+}
+
+int main( int argc, char * argv[])
+{
+ {
+ pull_coro_t source( runit);
+ while ( source) {
+ std::cout << "-";
+ source();
+ }
+ }
+
+ std::cout << "\nDone" << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine/example/asymmetric/exception.cpp b/src/boost/libs/coroutine/example/asymmetric/exception.cpp
new file mode 100644
index 000000000..5a8ac6a52
--- /dev/null
+++ b/src/boost/libs/coroutine/example/asymmetric/exception.cpp
@@ -0,0 +1,53 @@
+
+// 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)
+
+#include <boost/coroutine/all.hpp>
+
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+#include <string>
+
+#include <boost/bind.hpp>
+#include <boost/throw_exception.hpp>
+
+typedef boost::coroutines::asymmetric_coroutine< int >::pull_type pull_coro_t;
+typedef boost::coroutines::asymmetric_coroutine< int >::push_type push_coro_t;
+
+struct my_exception : public std::runtime_error
+{
+ my_exception( std::string const& str) :
+ std::runtime_error( str)
+ {}
+};
+
+void echo( push_coro_t & sink, int j)
+{
+ for ( int i = 0; i < j; ++i)
+ {
+ if ( i == 5) boost::throw_exception( my_exception("abc") );
+ sink( i);
+ }
+}
+
+int main( int argc, char * argv[])
+{
+ pull_coro_t source( boost::bind( echo, _1, 10) );
+ try
+ {
+ while ( source)
+ {
+ std::cout << source.get() << std::endl;
+ source();
+ }
+ }
+ catch ( my_exception const& ex)
+ { std::cout << "exception: " << ex.what() << std::endl; }
+
+ std::cout << "\nDone" << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine/example/asymmetric/fibonacci.cpp b/src/boost/libs/coroutine/example/asymmetric/fibonacci.cpp
new file mode 100644
index 000000000..bba8cc4a5
--- /dev/null
+++ b/src/boost/libs/coroutine/example/asymmetric/fibonacci.cpp
@@ -0,0 +1,43 @@
+
+// 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)
+
+#include <boost/coroutine/all.hpp>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <boost/range.hpp>
+
+void fibonacci( boost::coroutines::asymmetric_coroutine< int >::push_type & sink)
+{
+ int first = 1, second = 1;
+ sink( first);
+ sink( second);
+ while ( true)
+ {
+ int third = first + second;
+ first = second;
+ second = third;
+ sink( third);
+ }
+}
+
+int main()
+{
+ boost::coroutines::asymmetric_coroutine< int >::pull_type source( fibonacci);
+ boost::range_iterator<
+ boost::coroutines::asymmetric_coroutine< int >::pull_type
+ >::type it( boost::begin( source) );
+ for ( int i = 0; i < 10; ++i)
+ {
+ std::cout << * it << " ";
+ ++it;
+ }
+
+ std::cout << "\nDone" << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine/example/asymmetric/layout.cpp b/src/boost/libs/coroutine/example/asymmetric/layout.cpp
new file mode 100644
index 000000000..bc1924f6d
--- /dev/null
+++ b/src/boost/libs/coroutine/example/asymmetric/layout.cpp
@@ -0,0 +1,74 @@
+
+// Copyright Nat Goodspeed 2013.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/coroutine/all.hpp>
+
+#include <iostream>
+#include <iomanip>
+#include <vector>
+#include <string>
+#include <utility>
+
+#include <boost/assign/list_of.hpp>
+#include <boost/bind.hpp>
+#include <boost/range.hpp>
+
+struct FinalEOL
+{
+ ~FinalEOL() { std::cout << std::endl; }
+};
+
+void layout(boost::coroutines::asymmetric_coroutine<std::string>::pull_type& in, int num, int width)
+{
+ // Finish the last line when we leave by whatever means
+ FinalEOL eol;
+
+ // Pull values from upstream, lay them out 'num' to a line
+ for (;;)
+ {
+ for (int i = 0; i < num; ++i)
+ {
+ // when we exhaust the input, stop
+ if (! in)
+ return;
+
+ std::cout << std::setw(width) << in.get();
+ // now that we've handled this item, advance to next
+ in();
+ }
+ // after 'num' items, line break
+ std::cout << std::endl;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ std::vector<std::string> words = boost::assign::list_of
+ ("peas")
+ ("porridge")
+ ("hot")
+ ("peas")
+ ("porridge")
+ ("cold")
+ ("peas")
+ ("porridge")
+ ("in")
+ ("the")
+ ("pot")
+ ("nine")
+ ("days")
+ ("old")
+ ;
+
+ boost::coroutines::asymmetric_coroutine<std::string>::push_type writer(
+ boost::bind(layout, _1, 5, 15));
+
+ std::copy(boost::begin(words), boost::end(words), boost::begin(writer));
+
+ std::cout << "\nDone" << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine/example/asymmetric/parallel.cpp b/src/boost/libs/coroutine/example/asymmetric/parallel.cpp
new file mode 100644
index 000000000..350279365
--- /dev/null
+++ b/src/boost/libs/coroutine/example/asymmetric/parallel.cpp
@@ -0,0 +1,50 @@
+
+// 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)
+
+#include <boost/coroutine/all.hpp>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <boost/bind.hpp>
+
+void first( boost::coroutines::asymmetric_coroutine< void >::push_type & sink)
+{
+ std::cout << "started first! ";
+ for ( int i = 0; i < 10; ++i)
+ {
+ sink();
+ std::cout << "a" << i;
+ }
+}
+
+void second( boost::coroutines::asymmetric_coroutine< void >::push_type & sink)
+{
+ std::cout << "started second! ";
+ for ( int i = 0; i < 10; ++i)
+ {
+ sink();
+ std::cout << "b" << i;
+ }
+}
+
+int main( int argc, char * argv[])
+{
+ {
+ boost::coroutines::asymmetric_coroutine< void >::pull_type source1( boost::bind( first, _1) );
+ boost::coroutines::asymmetric_coroutine< void >::pull_type source2( boost::bind( second, _1) );
+ while ( source1 && source2) {
+ source1();
+ std::cout << " ";
+ source2();
+ std::cout << " ";
+ }
+ }
+
+ std::cout << "\nDone" << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine/example/asymmetric/power.cpp b/src/boost/libs/coroutine/example/asymmetric/power.cpp
new file mode 100644
index 000000000..df16d0fc5
--- /dev/null
+++ b/src/boost/libs/coroutine/example/asymmetric/power.cpp
@@ -0,0 +1,48 @@
+
+// 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)
+
+#include <boost/coroutine/all.hpp>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+#include <boost/range.hpp>
+
+void power( boost::coroutines::asymmetric_coroutine< int >::push_type & sink, int number, int exponent)
+{
+ int counter = 0;
+ int result = 1;
+ while ( counter++ < exponent)
+ {
+ result = result * number;
+ sink( result);
+ }
+}
+
+int main()
+{
+ {
+ std::cout << "using range functions" << std::endl;
+ boost::coroutines::asymmetric_coroutine< int >::pull_type source( boost::bind( power, _1, 2, 8) );
+ boost::coroutines::asymmetric_coroutine< int >::pull_type::iterator e( boost::end( source) );
+ for ( boost::coroutines::asymmetric_coroutine< int >::pull_type::iterator i( boost::begin( source) );
+ i != e; ++i)
+ std::cout << * i << " ";
+ }
+
+ {
+ std::cout << "\nusing BOOST_FOREACH" << std::endl;
+ boost::coroutines::asymmetric_coroutine< int >::pull_type source( boost::bind( power, _1, 2, 8) );
+ BOOST_FOREACH( int i, source)
+ { std::cout << i << " "; }
+ }
+
+ std::cout << "\nDone" << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine/example/asymmetric/same_fringe.cpp b/src/boost/libs/coroutine/example/asymmetric/same_fringe.cpp
new file mode 100644
index 000000000..8860eccd3
--- /dev/null
+++ b/src/boost/libs/coroutine/example/asymmetric/same_fringe.cpp
@@ -0,0 +1,162 @@
+
+// Copyright Nat Goodspeed 2013.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/coroutine/all.hpp>
+
+#include <cstddef>
+#include <cstdlib>
+#include <iostream>
+#include <iterator>
+#include <string>
+#include <utility>
+
+#include <boost/bind.hpp>
+#include <boost/range.hpp>
+#include <boost/shared_ptr.hpp>
+
+struct node
+{
+ typedef boost::shared_ptr< node > ptr_t;
+
+ // Each tree node has an optional left subtree, an optional right subtree
+ // and a value of its own. The value is considered to be between the left
+ // subtree and the right.
+ ptr_t left, right;
+ std::string value;
+
+ // construct leaf
+ node(const std::string& v):
+ left(), right(), value(v)
+ {}
+ // construct nonleaf
+ node(ptr_t l, const std::string& v, ptr_t r):
+ left(l), right(r), value(v)
+ {}
+
+ static ptr_t create(const std::string& v)
+ {
+ return ptr_t(new node(v));
+ }
+
+ static ptr_t create(ptr_t l, const std::string& v, ptr_t r)
+ {
+ return ptr_t(new node(l, v, r));
+ }
+};
+
+node::ptr_t create_left_tree_from(const std::string& root)
+{
+ /* --------
+ root
+ / \
+ b e
+ / \
+ a c
+ -------- */
+ return node::create(
+ node::create(
+ node::create("a"),
+ "b",
+ node::create("c")),
+ root,
+ node::create("e"));
+}
+
+node::ptr_t create_right_tree_from(const std::string& root)
+{
+ /* --------
+ root
+ / \
+ a d
+ / \
+ c e
+ -------- */
+ return node::create(
+ node::create("a"),
+ root,
+ node::create(
+ node::create("c"),
+ "d",
+ node::create("e")));
+}
+
+// recursively walk the tree, delivering values in order
+void traverse(node::ptr_t n,boost::coroutines::asymmetric_coroutine<std::string>::push_type& out)
+{
+ if (n->left) traverse(n->left,out);
+ out(n->value);
+ if (n->right) traverse(n->right,out);
+}
+
+int main()
+{
+ {
+ node::ptr_t left_d(create_left_tree_from("d"));
+ boost::coroutines::asymmetric_coroutine<std::string>::pull_type left_d_reader(
+ boost::bind(traverse, left_d, _1));
+ std::cout << "left tree from d:\n";
+ std::copy(boost::begin(left_d_reader),
+ boost::end(left_d_reader),
+ std::ostream_iterator<std::string>(std::cout, " "));
+ std::cout << std::endl;
+
+ node::ptr_t right_b(create_right_tree_from("b"));
+ boost::coroutines::asymmetric_coroutine<std::string>::pull_type right_b_reader(
+ boost::bind(traverse, right_b, _1));
+ std::cout << "right tree from b:\n";
+ std::copy(boost::begin(right_b_reader),
+ boost::end(right_b_reader),
+ std::ostream_iterator<std::string>(std::cout, " "));
+ std::cout << std::endl;
+
+ node::ptr_t right_x(create_right_tree_from("x"));
+ boost::coroutines::asymmetric_coroutine<std::string>::pull_type right_x_reader(
+ boost::bind(traverse, right_x, _1));
+ std::cout << "right tree from x:\n";
+ std::copy(boost::begin(right_x_reader),
+ boost::end(right_x_reader),
+ std::ostream_iterator<std::string>(std::cout, " "));
+ std::cout << std::endl;
+ }
+
+ {
+ node::ptr_t left_d(create_left_tree_from("d"));
+ boost::coroutines::asymmetric_coroutine<std::string>::pull_type left_d_reader(
+ boost::bind(traverse, left_d, _1));
+
+ node::ptr_t right_b(create_right_tree_from("b"));
+ boost::coroutines::asymmetric_coroutine<std::string>::pull_type right_b_reader(
+ boost::bind(traverse, right_b, _1));
+
+ std::cout << "left tree from d == right tree from b? "
+ << std::boolalpha
+ << std::equal(boost::begin(left_d_reader),
+ boost::end(left_d_reader),
+ boost::begin(right_b_reader))
+ << std::endl;
+ }
+
+ {
+ node::ptr_t left_d(create_left_tree_from("d"));
+ boost::coroutines::asymmetric_coroutine<std::string>::pull_type left_d_reader(
+ boost::bind(traverse, left_d, _1));
+
+ node::ptr_t right_x(create_right_tree_from("x"));
+ boost::coroutines::asymmetric_coroutine<std::string>::pull_type right_x_reader(
+ boost::bind(traverse, right_x, _1));
+
+ std::cout << "left tree from d == right tree from x? "
+ << std::boolalpha
+ << std::equal(boost::begin(left_d_reader),
+ boost::end(left_d_reader),
+ boost::begin(right_x_reader))
+ << std::endl;
+ }
+
+ std::cout << "Done" << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine/example/asymmetric/segmented_stack.cpp b/src/boost/libs/coroutine/example/asymmetric/segmented_stack.cpp
new file mode 100644
index 000000000..b8b27ab19
--- /dev/null
+++ b/src/boost/libs/coroutine/example/asymmetric/segmented_stack.cpp
@@ -0,0 +1,63 @@
+
+// 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)
+
+#include <boost/coroutine/all.hpp>
+
+#include <iostream>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+
+int count = 384;
+
+#ifdef BOOST_MSVC //MS VisualStudio
+__declspec(noinline) void access( char *buf);
+#else // GCC
+void access( char *buf) __attribute__ ((noinline));
+#endif
+void access( char *buf)
+{
+ buf[0] = '\0';
+}
+
+void bar( int i)
+{
+ char buf[4 * 1024];
+
+ if ( i > 0)
+ {
+ access( buf);
+ std::cout << i << ". iteration" << std::endl;
+ bar( i - 1);
+ }
+}
+
+void foo( boost::coroutines::asymmetric_coroutine< void >::pull_type & source)
+{
+ bar( count);
+ source();
+}
+
+
+int main( int argc, char * argv[])
+{
+#if defined(BOOST_USE_SEGMENTED_STACKS)
+ std::cout << "using segmented stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
+ std::cout << "initial stack size = " << boost::coroutines::stack_allocator::traits_type::default_size() / 1024 << "kB" << std::endl;
+ std::cout << "application should not fail" << std::endl;
+#else
+ std::cout << "using standard stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
+ std::cout << "initial stack size = " << boost::coroutines::stack_allocator::traits_type::default_size() / 1024 << "kB" << std::endl;
+ std::cout << "application might fail" << std::endl;
+#endif
+
+ boost::coroutines::asymmetric_coroutine< void >::push_type sink( foo);
+ sink();
+
+ std::cout << "Done" << std::endl;
+
+ return 0;
+}
diff --git a/src/boost/libs/coroutine/example/asymmetric/simple.cpp b/src/boost/libs/coroutine/example/asymmetric/simple.cpp
new file mode 100644
index 000000000..045bed84e
--- /dev/null
+++ b/src/boost/libs/coroutine/example/asymmetric/simple.cpp
@@ -0,0 +1,53 @@
+#include <boost/coroutine/all.hpp>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <boost/bind.hpp>
+
+#include "X.h"
+
+typedef boost::coroutines::asymmetric_coroutine< X& >::pull_type pull_coro_t;
+typedef boost::coroutines::asymmetric_coroutine< X& >::push_type push_coro_t;
+
+void fn1( push_coro_t & sink)
+{
+ for ( int i = 0; i < 10; ++i)
+ {
+ X x( i);
+ sink( x);
+ }
+}
+
+void fn2( pull_coro_t & source)
+{
+ while ( source) {
+ X & x = source.get();
+ std::cout << "i = " << x.i << std::endl;
+ source();
+ }
+}
+
+int main( int argc, char * argv[])
+{
+ {
+ pull_coro_t source( fn1);
+ while ( source) {
+ X & x = source.get();
+ std::cout << "i = " << x.i << std::endl;
+ source();
+ }
+ }
+ {
+ push_coro_t sink( fn2);
+ for ( int i = 0; i < 10; ++i)
+ {
+ X x( i);
+ sink( x);
+ }
+ }
+ std::cout << "Done" << std::endl;
+
+ return EXIT_SUCCESS;
+}
+
diff --git a/src/boost/libs/coroutine/example/asymmetric/test.cpp b/src/boost/libs/coroutine/example/asymmetric/test.cpp
new file mode 100644
index 000000000..c6de170bc
--- /dev/null
+++ b/src/boost/libs/coroutine/example/asymmetric/test.cpp
@@ -0,0 +1,45 @@
+#include <boost/coroutine/all.hpp>
+
+#include <boost/bind.hpp>
+
+#include "X.h"
+
+typedef boost::coroutines::asymmetric_coroutine< X& >::pull_type pull_coro_t;
+typedef boost::coroutines::asymmetric_coroutine< X& >::push_type push_coro_t;
+
+void foo1( push_coro_t & sink)
+{
+ for ( int i = 0; i < 10; ++i)
+ {
+ X x( i);
+ sink( x);
+ }
+}
+
+void foo2( pull_coro_t & source)
+{
+ while ( source) {
+ X & x = source.get();
+ source();
+ }
+}
+
+void bar()
+{
+ {
+ pull_coro_t source( foo1);
+ while ( source) {
+ X & x = source.get();
+ source();
+ }
+ }
+ {
+ push_coro_t sink( foo2);
+ for ( int i = 0; i < 10; ++i)
+ {
+ X x( i);
+ sink( x);
+ }
+ }
+}
+
diff --git a/src/boost/libs/coroutine/example/asymmetric/tree.h b/src/boost/libs/coroutine/example/asymmetric/tree.h
new file mode 100644
index 000000000..0a45237ec
--- /dev/null
+++ b/src/boost/libs/coroutine/example/asymmetric/tree.h
@@ -0,0 +1,125 @@
+
+// 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 TREE_H
+#define TREE_H
+
+#include <boost/coroutine/all.hpp>
+
+#include <cstddef>
+#include <string>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+#if defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable:4355)
+#endif
+
+struct branch;
+struct leaf;
+
+struct visitor
+{
+ virtual ~visitor() {};
+
+ virtual void visit( branch & b) = 0;
+ virtual void visit( leaf & l) = 0;
+};
+
+struct node
+{
+ typedef boost::intrusive_ptr< node > ptr_t;
+
+ std::size_t use_count;
+
+ node() :
+ use_count( 0)
+ {}
+
+ virtual ~node() {}
+
+ virtual void accept( visitor & v) = 0;
+
+ friend inline void intrusive_ptr_add_ref( node * p)
+ { ++p->use_count; }
+
+ friend inline void intrusive_ptr_release( node * p)
+ { if ( 0 == --p->use_count) delete p; }
+};
+
+struct branch : public node
+{
+ node::ptr_t left;
+ node::ptr_t right;
+
+ static ptr_t create( node::ptr_t left_, node::ptr_t right_)
+ { return ptr_t( new branch( left_, right_) ); }
+
+ branch( node::ptr_t left_, node::ptr_t right_) :
+ left( left_), right( right_)
+ {}
+
+ void accept( visitor & v)
+ { v.visit( * this); }
+};
+
+struct leaf : public node
+{
+ std::string value;
+
+ static ptr_t create( std::string const& value_)
+ { return ptr_t( new leaf( value_) ); }
+
+ leaf( std::string const& value_) :
+ value( value_)
+ {}
+
+ void accept( visitor & v)
+ { v.visit( * this); }
+};
+
+inline
+bool operator==( leaf const& l, leaf const& r)
+{ return l.value == r.value; }
+
+inline
+bool operator!=( leaf const& l, leaf const& r)
+{ return l.value != r.value; }
+
+class tree_visitor : public visitor
+{
+private:
+ boost::coroutines::asymmetric_coroutine< leaf & >::push_type & c_;
+
+public:
+ tree_visitor( boost::coroutines::asymmetric_coroutine< leaf & >::push_type & 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::asymmetric_coroutine< leaf & >::push_type & c, node::ptr_t root)
+{
+ tree_visitor v( c);
+ root->accept( v);
+}
+
+#if defined(_MSC_VER)
+# pragma warning(pop)
+#endif
+
+#endif // TREE_H
diff --git a/src/boost/libs/coroutine/example/asymmetric/unwind.cpp b/src/boost/libs/coroutine/example/asymmetric/unwind.cpp
new file mode 100644
index 000000000..b8d9d4322
--- /dev/null
+++ b/src/boost/libs/coroutine/example/asymmetric/unwind.cpp
@@ -0,0 +1,45 @@
+
+// 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)
+
+#include <boost/coroutine/all.hpp>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <boost/bind.hpp>
+
+struct X : private boost::noncopyable
+{
+ X() { std::cout << "X()" << std::endl; }
+ ~X() { std::cout << "~X()" << std::endl; }
+};
+
+void fn( boost::coroutines::asymmetric_coroutine< void >::push_type & sink)
+{
+ X x;
+ int i = 0;
+ while ( true)
+ {
+ std::cout << "fn() : " << ++i << std::endl;
+ sink();
+ }
+}
+
+int main( int argc, char * argv[])
+{
+ {
+ boost::coroutines::asymmetric_coroutine< void >::pull_type source( fn);
+ for ( int k = 0; k < 3; ++k)
+ {
+ source();
+ }
+ std::cout << "destroying coroutine and unwinding stack" << std::endl;
+ }
+
+ std::cout << "\nDone" << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine/example/symmetric/Jamfile.v2 b/src/boost/libs/coroutine/example/symmetric/Jamfile.v2
new file mode 100644
index 000000000..c88a44f8d
--- /dev/null
+++ b/src/boost/libs/coroutine/example/symmetric/Jamfile.v2
@@ -0,0 +1,49 @@
+# Boost.Coroutine Library Examples Jamfile
+
+# 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)
+
+# For more information, see http://www.boost.org/
+
+import common ;
+import feature ;
+import indirect ;
+import modules ;
+import os ;
+import toolset ;
+
+project boost/coroutine/example/symmetric
+ : requirements
+ <library>/boost/context//boost_context
+ <library>/boost/coroutine//boost_coroutine
+ <library>/boost/program_options//boost_program_options
+ <library>/boost/random//boost_random
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <link>static
+ <threading>multi
+ ;
+
+exe simple
+ : simple.cpp
+ ;
+
+exe dice_game
+ : dice_game.cpp
+ ;
+
+exe merge_arrays
+ : merge_arrays.cpp
+ ;
+
+exe unwind
+ : unwind.cpp
+ ;
+
+exe segmented_stack
+ : segmented_stack.cpp
+ ;
diff --git a/src/boost/libs/coroutine/example/symmetric/dice_game.cpp b/src/boost/libs/coroutine/example/symmetric/dice_game.cpp
new file mode 100644
index 000000000..09eabf5a2
--- /dev/null
+++ b/src/boost/libs/coroutine/example/symmetric/dice_game.cpp
@@ -0,0 +1,70 @@
+
+// Copyright Keld Helsgaun 2000, Oliver Kowalke 2014.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/coroutine/all.hpp>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <boost/bind.hpp>
+#include <boost/move/move.hpp>
+#include <boost/random/random_device.hpp>
+#include <boost/random/uniform_int_distribution.hpp>
+
+typedef boost::coroutines::symmetric_coroutine< void > coro_t;
+
+class player
+{
+private:
+ int die()
+ {
+ boost::random::uniform_int_distribution<> dist( 1, 6);
+ return dist( gen);
+ }
+
+ void run_( coro_t::yield_type & yield)
+ {
+ int sum = 0;
+ while ( ( sum += die() ) < 100)
+ yield( nxt->coro);
+ std::cout << "player " << id << " winns" << std::endl;
+ }
+
+ player( player const&);
+ player & operator=( player const&);
+
+public:
+ int id;
+ player * nxt;
+ coro_t::call_type coro;
+ boost::random::random_device gen;
+
+ player( int id_) :
+ id( id_), nxt( 0),
+ coro( boost::bind( & player::run_, this, _1) ),
+ gen()
+ {}
+
+ void run()
+ { coro(); }
+};
+
+int main( int argc, char * argv[])
+{
+ player * first = new player( 1);
+ player * p = first;
+ for ( int i = 2; i <= 4; ++i)
+ {
+ p->nxt = new player( i);
+ p = p->nxt;
+ }
+ p->nxt = first;
+ first->run();
+
+ std::cout << "Done" << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine/example/symmetric/merge_arrays.cpp b/src/boost/libs/coroutine/example/symmetric/merge_arrays.cpp
new file mode 100644
index 000000000..d72f2f7e9
--- /dev/null
+++ b/src/boost/libs/coroutine/example/symmetric/merge_arrays.cpp
@@ -0,0 +1,105 @@
+
+// Copyright Keld Helsgaun 2000, Oliver Kowalke 2014.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/coroutine/all.hpp>
+
+#include <cstdlib>
+#include <cstddef>
+#include <iostream>
+#include <vector>
+
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+
+typedef boost::coroutines::symmetric_coroutine< void > coro_t;
+
+class merger
+{
+private:
+ std::size_t max_;
+ std::vector< int > & to_;
+
+ void run_( coro_t::yield_type & yield)
+ {
+ while ( idx < from.size() )
+ {
+ if ( other->from[other->idx] < from[idx])
+ yield( other->coro);
+ to_.push_back(from[idx++]);
+ }
+ while ( to_.size() < max_)
+ to_.push_back( other->from[other->idx++]);
+ }
+
+ merger( merger const&);
+ merger & operator=( merger const&);
+
+public:
+ std::vector< int > const& from;
+ std::size_t idx;
+ merger * other;
+ coro_t::call_type coro;
+
+ merger( std::vector< int > const& from_, std::vector< int > & to, std::size_t max) :
+ max_( max),
+ to_( to),
+ from( from_),
+ idx( 0),
+ other( 0),
+ coro( boost::bind( & merger::run_, this, _1) )
+ {}
+
+ void run()
+ { coro(); }
+};
+
+std::vector< int > merge( std::vector< int > const& a, std::vector< int > const& b)
+{
+ std::vector< int > c;
+ merger ma( a, c, a.size() + b. size() );
+ merger mb( b, c, a.size() + b. size() );
+
+ ma.other = & mb;
+ mb.other = & ma;
+
+ ma.run();
+
+ return c;
+}
+
+void print( std::string const& name, std::vector< int > const& v)
+{
+ std::cout << name << " : ";
+ BOOST_FOREACH( int itm, v)
+ { std::cout << itm << " "; }
+ std::cout << "\n";
+}
+
+int main( int argc, char * argv[])
+{
+ std::vector< int > a;
+ a.push_back( 1);
+ a.push_back( 5);
+ a.push_back( 6);
+ a.push_back( 10);
+ print( "a", a);
+
+ std::vector< int > b;
+ b.push_back( 2);
+ b.push_back( 4);
+ b.push_back( 7);
+ b.push_back( 8);
+ b.push_back( 9);
+ b.push_back( 13);
+ print( "b", b);
+
+ std::vector< int > c = merge( a, b);
+ print( "c", c);
+
+ std::cout << "Done" << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine/example/symmetric/segmented_stack.cpp b/src/boost/libs/coroutine/example/symmetric/segmented_stack.cpp
new file mode 100644
index 000000000..8f45c601e
--- /dev/null
+++ b/src/boost/libs/coroutine/example/symmetric/segmented_stack.cpp
@@ -0,0 +1,67 @@
+
+// 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)
+
+#include <boost/coroutine/all.hpp>
+
+#include <iostream>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/thread.hpp>
+
+int count = 384;
+
+#ifdef BOOST_MSVC //MS VisualStudio
+__declspec(noinline) void access( char *buf);
+#else // GCC
+void access( char *buf) __attribute__ ((noinline));
+#endif
+void access( char *buf)
+{
+ buf[0] = '\0';
+}
+
+void bar( int i)
+{
+ char buf[4 * 1024];
+
+ if ( i > 0)
+ {
+ access( buf);
+ std::cout << i << ". iteration" << std::endl;
+ bar( i - 1);
+ }
+}
+
+void foo( boost::coroutines::symmetric_coroutine< void >::yield_type &)
+{
+ bar( count);
+}
+
+void thread_fn()
+{
+ {
+ boost::coroutines::symmetric_coroutine< void >::call_type coro( foo);
+ coro();
+ }
+}
+
+int main( int argc, char * argv[])
+{
+#if defined(BOOST_USE_SEGMENTED_STACKS)
+ std::cout << "using segmented stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
+ std::cout << "initial stack size = " << boost::coroutines::stack_allocator::traits_type::default_size() / 1024 << "kB" << std::endl;
+ std::cout << "application should not fail" << std::endl;
+#else
+ std::cout << "using standard stacks: allocates " << count << " * 4kB == " << 4 * count << "kB on stack, ";
+ std::cout << "initial stack size = " << boost::coroutines::stack_allocator::traits_type::default_size() / 1024 << "kB" << std::endl;
+ std::cout << "application might fail" << std::endl;
+#endif
+
+ boost::thread( thread_fn).join();
+
+ return 0;
+}
diff --git a/src/boost/libs/coroutine/example/symmetric/simple.cpp b/src/boost/libs/coroutine/example/symmetric/simple.cpp
new file mode 100644
index 000000000..9fbd9ec65
--- /dev/null
+++ b/src/boost/libs/coroutine/example/symmetric/simple.cpp
@@ -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)
+
+#include <boost/coroutine/all.hpp>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <boost/bind.hpp>
+
+typedef boost::coroutines::symmetric_coroutine< void > coro_t;
+
+coro_t::call_type * c1 = 0;
+coro_t::call_type * c2 = 0;
+
+void foo( coro_t::yield_type & yield)
+{
+ std::cout << "foo1" << std::endl;
+ yield( * c2);
+ std::cout << "foo2" << std::endl;
+ yield( * c2);
+ std::cout << "foo3" << std::endl;
+}
+
+void bar( coro_t::yield_type & yield)
+{
+ std::cout << "bar1" << std::endl;
+ yield( * c1);
+ std::cout << "bar2" << std::endl;
+ yield( * c1);
+ std::cout << "bar3" << std::endl;
+}
+
+int main( int argc, char * argv[])
+{
+ coro_t::call_type coro1( foo);
+ coro_t::call_type coro2( bar);
+ c1 = & coro1;
+ c2 = & coro2;
+ coro1();
+ std::cout << "Done" << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine/example/symmetric/unwind.cpp b/src/boost/libs/coroutine/example/symmetric/unwind.cpp
new file mode 100644
index 000000000..2af574e6f
--- /dev/null
+++ b/src/boost/libs/coroutine/example/symmetric/unwind.cpp
@@ -0,0 +1,51 @@
+
+// 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)
+
+#include <boost/coroutine/all.hpp>
+
+#include <cstdlib>
+#include <iostream>
+
+#include <boost/bind.hpp>
+
+struct X : private boost::noncopyable
+{
+ X() { std::cout << "X()" << std::endl; }
+ ~X() { std::cout << "~X()" << std::endl; }
+};
+
+typedef boost::coroutines::symmetric_coroutine< void > coro_t;
+
+coro_t::call_type * c1 = 0;
+coro_t::call_type * c2 = 0;
+
+void foo( coro_t::yield_type & yield)
+{
+ X x;
+ std::cout << "foo() entered" << std::endl;
+ yield( * c2);
+ yield( * c2);
+ std::cout << "foo() finished" << std::endl;
+}
+
+void bar( coro_t::yield_type & yield)
+{
+ std::cout << "bar() entered" << std::endl;
+ yield( * c1);
+ std::cout << "bar() finished" << std::endl;
+}
+
+int main( int argc, char * argv[])
+{
+ coro_t::call_type coro1( foo);
+ coro_t::call_type coro2( bar);
+ c1 = & coro1;
+ c2 = & coro2;
+ coro1();
+ std::cout << "Done" << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/coroutine/index.html b/src/boost/libs/coroutine/index.html
new file mode 100644
index 000000000..0ade6cbd2
--- /dev/null
+++ b/src/boost/libs/coroutine/index.html
@@ -0,0 +1,14 @@
+<html>
+<head>
+<meta http-equiv="refresh" content="0; URL=doc/html/index.html">
+</head>
+<body>
+Automatic redirection failed, please go to
+<a href="doc/html/index.html">doc/html/index.html</a>
+<hr>
+<p>&copy; Copyright Beman Dawes, 2001</p>
+<p> Distributed under the Boost Software
+License, Version 1.0. (See accompanying file <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
+www.boost.org/LICENSE_1_0.txt</a>)</p>
+</body>
+</html>
diff --git a/src/boost/libs/coroutine/meta/libraries.json b/src/boost/libs/coroutine/meta/libraries.json
new file mode 100644
index 000000000..c6841d5b2
--- /dev/null
+++ b/src/boost/libs/coroutine/meta/libraries.json
@@ -0,0 +1,15 @@
+{
+ "key": "coroutine",
+ "status": "deprecated",
+ "name": "Coroutine",
+ "authors": [
+ "Oliver Kowalke"
+ ],
+ "description": "Coroutine library.",
+ "category": [
+ "Concurrent"
+ ],
+ "maintainers": [
+ "Oliver Kowalke <oliver.kowalke -at- gmail.com>"
+ ]
+}
diff --git a/src/boost/libs/coroutine/performance/asymmetric/Jamfile.v2 b/src/boost/libs/coroutine/performance/asymmetric/Jamfile.v2
new file mode 100644
index 000000000..2baab38d3
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/asymmetric/Jamfile.v2
@@ -0,0 +1,83 @@
+
+# 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)
+
+# For more information, see http://www.boost.org/
+
+import common ;
+import feature ;
+import indirect ;
+import modules ;
+import os ;
+import toolset ;
+
+project boost/coroutine/performance/asymmetric
+ : requirements
+ <library>/boost/chrono//boost_chrono
+ <library>/boost/context//boost_context
+ <library>/boost/coroutine//boost_coroutine
+ <library>/boost/program_options//boost_program_options
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <link>static
+ <threading>multi
+ <cxxflags>-DBOOST_DISABLE_ASSERTS
+ <optimization>speed
+ <variant>release
+ ;
+
+alias sources
+ : ../bind_processor_aix.cpp
+ : <target-os>aix
+ ;
+
+alias sources
+ : ../bind_processor_freebsd.cpp
+ : <target-os>freebsd
+ ;
+
+alias sources
+ : ../bind_processor_hpux.cpp
+ : <target-os>hpux
+ ;
+
+alias sources
+ : ../bind_processor_linux.cpp
+ : <target-os>linux
+ ;
+
+alias sources
+ : ../bind_processor_solaris.cpp
+ : <target-os>solaris
+ ;
+
+alias sources
+ : ../bind_processor_windows.cpp
+ : <target-os>windows
+ ;
+
+explicit sources ;
+
+exe performance_create_protected
+ : sources
+ performance_create_protected.cpp
+ ;
+
+exe performance_create_standard
+ : sources
+ performance_create_standard.cpp
+ ;
+
+exe performance_create_prealloc
+ : sources
+ performance_create_prealloc.cpp
+ ;
+
+exe performance_switch
+ : sources
+ performance_switch.cpp
+ ;
diff --git a/src/boost/libs/coroutine/performance/asymmetric/performance_create_prealloc.cpp b/src/boost/libs/coroutine/performance/asymmetric/performance_create_prealloc.cpp
new file mode 100644
index 000000000..350d4399b
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/asymmetric/performance_create_prealloc.cpp
@@ -0,0 +1,116 @@
+
+// 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)
+
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+
+#include <boost/chrono.hpp>
+#include <boost/coroutine/all.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/program_options.hpp>
+
+#include "../bind_processor.hpp"
+#include "../clock.hpp"
+#include "../cycle.hpp"
+#include "../preallocated_stack_allocator.hpp"
+
+typedef preallocated_stack_allocator stack_allocator;
+typedef boost::coroutines::asymmetric_coroutine< void > coro_type;
+
+boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
+boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind;
+boost::uint64_t jobs = 1000;
+
+void fn( coro_type::push_type & c)
+{ while ( true) c(); }
+
+duration_type measure_time( duration_type overhead)
+{
+ stack_allocator stack_alloc;
+
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ coro_type::pull_type c( fn,
+ boost::coroutines::attributes( unwind_stack, preserve_fpu),
+ stack_alloc);
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead_clock(); // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+
+# ifdef BOOST_CONTEXT_CYCLE
+cycle_type measure_cycles( cycle_type overhead)
+{
+ stack_allocator stack_alloc;
+
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ coro_type::pull_type c( fn,
+ boost::coroutines::attributes( unwind_stack, preserve_fpu),
+ stack_alloc);
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+# endif
+
+int main( int argc, char * argv[])
+{
+ try
+ {
+ bool preserve = false, unwind = true, bind = false;
+ boost::program_options::options_description desc("allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
+ ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
+ ("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack")
+ ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
+
+ boost::program_options::variables_map vm;
+ boost::program_options::store(
+ boost::program_options::parse_command_line(
+ argc,
+ argv,
+ desc),
+ vm);
+ boost::program_options::notify( vm);
+
+ if ( vm.count("help") ) {
+ std::cout << desc << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
+ if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind;
+ if ( bind) bind_to_processor( 0);
+
+ duration_type overhead_c = overhead_clock();
+ std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
+ boost::uint64_t res = measure_time( overhead_c).count();
+ std::cout << "average of " << res << " nano seconds" << std::endl;
+#ifdef BOOST_CONTEXT_CYCLE
+ cycle_type overhead_y = overhead_cycle();
+ std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
+ res = measure_cycles( overhead_y);
+ std::cout << "average of " << res << " cpu cycles" << std::endl;
+#endif
+
+ return EXIT_SUCCESS;
+ }
+ catch ( std::exception const& e)
+ { std::cerr << "exception: " << e.what() << std::endl; }
+ catch (...)
+ { std::cerr << "unhandled exception" << std::endl; }
+ return EXIT_FAILURE;
+}
diff --git a/src/boost/libs/coroutine/performance/asymmetric/performance_create_protected.cpp b/src/boost/libs/coroutine/performance/asymmetric/performance_create_protected.cpp
new file mode 100644
index 000000000..90f46a455
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/asymmetric/performance_create_protected.cpp
@@ -0,0 +1,113 @@
+
+// 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)
+
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+
+#include <boost/chrono.hpp>
+#include <boost/coroutine/all.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/program_options.hpp>
+
+#include "../bind_processor.hpp"
+#include "../clock.hpp"
+#include "../cycle.hpp"
+
+typedef boost::coroutines::protected_stack_allocator stack_allocator;
+typedef boost::coroutines::asymmetric_coroutine< void > coro_type;
+
+boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
+boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind;
+boost::uint64_t jobs = 1000;
+
+void fn( coro_type::push_type & c)
+{ while ( true) c(); }
+
+duration_type measure_time( duration_type overhead)
+{
+ stack_allocator stack_alloc;
+
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ coro_type::pull_type c( fn,
+ boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc);
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead_clock(); // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+
+# ifdef BOOST_CONTEXT_CYCLE
+cycle_type measure_cycles( cycle_type overhead)
+{
+ stack_allocator stack_alloc;
+
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ coro_type::pull_type c( fn,
+ boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc);
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+# endif
+
+int main( int argc, char * argv[])
+{
+ try
+ {
+ bool preserve = false, unwind = true, bind = false;
+ boost::program_options::options_description desc("allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
+ ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
+ ("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack")
+ ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
+
+ boost::program_options::variables_map vm;
+ boost::program_options::store(
+ boost::program_options::parse_command_line(
+ argc,
+ argv,
+ desc),
+ vm);
+ boost::program_options::notify( vm);
+
+ if ( vm.count("help") ) {
+ std::cout << desc << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
+ if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind;
+ if ( bind) bind_to_processor( 0);
+
+ duration_type overhead_c = overhead_clock();
+ std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
+ boost::uint64_t res = measure_time( overhead_c).count();
+ std::cout << "average of " << res << " nano seconds" << std::endl;
+#ifdef BOOST_CONTEXT_CYCLE
+ cycle_type overhead_y = overhead_cycle();
+ std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
+ res = measure_cycles( overhead_y);
+ std::cout << "average of " << res << " cpu cycles" << std::endl;
+#endif
+
+ return EXIT_SUCCESS;
+ }
+ catch ( std::exception const& e)
+ { std::cerr << "exception: " << e.what() << std::endl; }
+ catch (...)
+ { std::cerr << "unhandled exception" << std::endl; }
+ return EXIT_FAILURE;
+}
diff --git a/src/boost/libs/coroutine/performance/asymmetric/performance_create_standard.cpp b/src/boost/libs/coroutine/performance/asymmetric/performance_create_standard.cpp
new file mode 100644
index 000000000..6736a1e76
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/asymmetric/performance_create_standard.cpp
@@ -0,0 +1,113 @@
+
+// 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)
+
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+
+#include <boost/chrono.hpp>
+#include <boost/coroutine/all.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/program_options.hpp>
+
+#include "../bind_processor.hpp"
+#include "../clock.hpp"
+#include "../cycle.hpp"
+
+typedef boost::coroutines::standard_stack_allocator stack_allocator;
+typedef boost::coroutines::asymmetric_coroutine< void > coro_type;
+
+boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
+boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind;
+boost::uint64_t jobs = 1000;
+
+void fn( coro_type::push_type & c)
+{ while ( true) c(); }
+
+duration_type measure_time( duration_type overhead)
+{
+ stack_allocator stack_alloc;
+
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ coro_type::pull_type c( fn,
+ boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc);
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead_clock(); // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+
+# ifdef BOOST_CONTEXT_CYCLE
+cycle_type measure_cycles( cycle_type overhead)
+{
+ stack_allocator stack_alloc;
+
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ coro_type::pull_type c( fn,
+ boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc);
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+# endif
+
+int main( int argc, char * argv[])
+{
+ try
+ {
+ bool preserve = false, unwind = true, bind = false;
+ boost::program_options::options_description desc("allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
+ ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
+ ("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack")
+ ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
+
+ boost::program_options::variables_map vm;
+ boost::program_options::store(
+ boost::program_options::parse_command_line(
+ argc,
+ argv,
+ desc),
+ vm);
+ boost::program_options::notify( vm);
+
+ if ( vm.count("help") ) {
+ std::cout << desc << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
+ if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind;
+ if ( bind) bind_to_processor( 0);
+
+ duration_type overhead_c = overhead_clock();
+ std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
+ boost::uint64_t res = measure_time( overhead_c).count();
+ std::cout << "average of " << res << " nano seconds" << std::endl;
+#ifdef BOOST_CONTEXT_CYCLE
+ cycle_type overhead_y = overhead_cycle();
+ std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
+ res = measure_cycles( overhead_y);
+ std::cout << "average of " << res << " cpu cycles" << std::endl;
+#endif
+
+ return EXIT_SUCCESS;
+ }
+ catch ( std::exception const& e)
+ { std::cerr << "exception: " << e.what() << std::endl; }
+ catch (...)
+ { std::cerr << "unhandled exception" << std::endl; }
+ return EXIT_FAILURE;
+}
diff --git a/src/boost/libs/coroutine/performance/asymmetric/performance_switch.cpp b/src/boost/libs/coroutine/performance/asymmetric/performance_switch.cpp
new file mode 100644
index 000000000..c99946b4e
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/asymmetric/performance_switch.cpp
@@ -0,0 +1,205 @@
+
+// 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)
+
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+#include <string>
+
+#include <boost/chrono.hpp>
+#include <boost/coroutine/all.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/program_options.hpp>
+
+#include "../bind_processor.hpp"
+#include "../clock.hpp"
+#include "../cycle.hpp"
+
+boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
+boost::uint64_t jobs = 1000;
+
+struct X
+{
+ std::string str;
+
+ X( std::string const& str_) :
+ str( str_)
+ {}
+};
+
+const X x("abc");
+
+void fn_void( boost::coroutines::asymmetric_coroutine< void >::push_type & c)
+{ while ( true) c(); }
+
+void fn_int( boost::coroutines::asymmetric_coroutine< int >::push_type & c)
+{ while ( true) c( 7); }
+
+void fn_x( boost::coroutines::asymmetric_coroutine< X >::push_type & c)
+{
+ while ( true) c( x);
+}
+
+duration_type measure_time_void( duration_type overhead)
+{
+ boost::coroutines::asymmetric_coroutine< void >::pull_type c( fn_void,
+ boost::coroutines::attributes( preserve_fpu) );
+
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c();
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead_clock(); // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+
+duration_type measure_time_int( duration_type overhead)
+{
+ boost::coroutines::asymmetric_coroutine< int >::pull_type c( fn_int,
+ boost::coroutines::attributes( preserve_fpu) );
+
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c();
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead_clock(); // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+
+duration_type measure_time_x( duration_type overhead)
+{
+ boost::coroutines::asymmetric_coroutine< X >::pull_type c( fn_x,
+ boost::coroutines::attributes( preserve_fpu) );
+
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c();
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead_clock(); // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+
+# ifdef BOOST_CONTEXT_CYCLE
+cycle_type measure_cycles_void( cycle_type overhead)
+{
+ boost::coroutines::asymmetric_coroutine< void >::pull_type c( fn_void,
+ boost::coroutines::attributes( preserve_fpu) );
+
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c();
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+
+cycle_type measure_cycles_int( cycle_type overhead)
+{
+ boost::coroutines::asymmetric_coroutine< int >::pull_type c( fn_int,
+ boost::coroutines::attributes( preserve_fpu) );
+
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c();
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+
+cycle_type measure_cycles_x( cycle_type overhead)
+{
+ boost::coroutines::asymmetric_coroutine< X >::pull_type c( fn_x,
+ boost::coroutines::attributes( preserve_fpu) );
+
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c();
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+# endif
+
+int main( int argc, char * argv[])
+{
+ try
+ {
+ bool preserve = false, bind = false;
+ boost::program_options::options_description desc("allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
+ ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
+ ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
+
+ boost::program_options::variables_map vm;
+ boost::program_options::store(
+ boost::program_options::parse_command_line(
+ argc,
+ argv,
+ desc),
+ vm);
+ boost::program_options::notify( vm);
+
+ if ( vm.count("help") ) {
+ std::cout << desc << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
+ if ( bind) bind_to_processor( 0);
+
+ duration_type overhead_c = overhead_clock();
+ std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
+ boost::uint64_t res = measure_time_void( overhead_c).count();
+ std::cout << "void: average of " << res << " nano seconds" << std::endl;
+ res = measure_time_int( overhead_c).count();
+ std::cout << "int: average of " << res << " nano seconds" << std::endl;
+ res = measure_time_x( overhead_c).count();
+ std::cout << "X: average of " << res << " nano seconds" << std::endl;
+#ifdef BOOST_CONTEXT_CYCLE
+ cycle_type overhead_y = overhead_cycle();
+ std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
+ res = measure_cycles_void( overhead_y);
+ std::cout << "void: average of " << res << " cpu cycles" << std::endl;
+ res = measure_cycles_int( overhead_y);
+ std::cout << "int: average of " << res << " cpu cycles" << std::endl;
+ res = measure_cycles_x( overhead_y);
+ std::cout << "X: average of " << res << " cpu cycles" << std::endl;
+#endif
+
+ return EXIT_SUCCESS;
+ }
+ catch ( std::exception const& e)
+ { std::cerr << "exception: " << e.what() << std::endl; }
+ catch (...)
+ { std::cerr << "unhandled exception" << std::endl; }
+ return EXIT_FAILURE;
+}
diff --git a/src/boost/libs/coroutine/performance/asymmetric/segmented/Jamfile.v2 b/src/boost/libs/coroutine/performance/asymmetric/segmented/Jamfile.v2
new file mode 100644
index 000000000..073f7e7af
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/asymmetric/segmented/Jamfile.v2
@@ -0,0 +1,68 @@
+
+# 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)
+
+# For more information, see http://www.boost.org/
+
+import common ;
+import feature ;
+import indirect ;
+import modules ;
+import os ;
+import toolset ;
+
+project boost/coroutine/performance/segmented
+ : requirements
+ <library>/boost/chrono//boost_chrono
+ <library>/boost/context//boost_context
+ <library>/boost/coroutine//boost_coroutine
+ <library>/boost/program_options//boost_program_options
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <link>static
+ <threading>multi
+ <cxxflags>-DBOOST_DISABLE_ASSERTS
+ <optimization>speed
+ <variant>release
+ ;
+
+alias sources
+ : ../../bind_processor_aix.cpp
+ : <target-os>aix
+ ;
+
+alias sources
+ : ../../bind_processor_freebsd.cpp
+ : <target-os>freebsd
+ ;
+
+alias sources
+ : ../../bind_processor_hpux.cpp
+ : <target-os>hpux
+ ;
+
+alias sources
+ : ../../bind_processor_linux.cpp
+ : <target-os>linux
+ ;
+
+alias sources
+ : ../../bind_processor_solaris.cpp
+ : <target-os>solaris
+ ;
+
+alias sources
+ : ../../bind_processor_windows.cpp
+ : <target-os>windows
+ ;
+
+explicit sources ;
+
+exe performance_create_segmented
+ : sources
+ performance_create_segmented.cpp
+ ;
diff --git a/src/boost/libs/coroutine/performance/asymmetric/segmented/performance_create_segmented.cpp b/src/boost/libs/coroutine/performance/asymmetric/segmented/performance_create_segmented.cpp
new file mode 100644
index 000000000..c174e6859
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/asymmetric/segmented/performance_create_segmented.cpp
@@ -0,0 +1,106 @@
+
+// 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)
+
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+
+#include <boost/chrono.hpp>
+#include <boost/coroutine/all.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/program_options.hpp>
+
+#include "../../bind_processor.hpp"
+#include "../../clock.hpp"
+#include "../../cycle.hpp"
+
+boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
+boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind;
+boost::uint64_t jobs = 1000;
+
+void fn( boost::coroutines::asymmetric_coroutine< void >::push_type & c)
+{ while ( true) c(); }
+
+duration_type measure_time( duration_type overhead)
+{
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ boost::coroutines::asymmetric_coroutine< void >::pull_type c( fn,
+ boost::coroutines::attributes( unwind_stack, preserve_fpu) );
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead_clock(); // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+
+# ifdef BOOST_CONTEXT_CYCLE
+cycle_type measure_cycles( cycle_type overhead)
+{
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ boost::coroutines::asymmetric_coroutine< void >::pull_type c( fn,
+ boost::coroutines::attributes( unwind_stack, preserve_fpu) );
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+# endif
+
+int main( int argc, char * argv[])
+{
+ try
+ {
+ bool preserve = false, unwind = true, bind = false;
+ boost::program_options::options_description desc("allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
+ ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
+ ("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack")
+ ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
+
+ boost::program_options::variables_map vm;
+ boost::program_options::store(
+ boost::program_options::parse_command_line(
+ argc,
+ argv,
+ desc),
+ vm);
+ boost::program_options::notify( vm);
+
+ if ( vm.count("help") ) {
+ std::cout << desc << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
+ if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind;
+ if ( bind) bind_to_processor( 0);
+
+ duration_type overhead_c = overhead_clock();
+ std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
+ boost::uint64_t res = measure_time( overhead_c).count();
+ std::cout << "average of " << res << " nano seconds" << std::endl;
+#ifdef BOOST_CONTEXT_CYCLE
+ cycle_type overhead_y = overhead_cycle();
+ std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
+ res = measure_cycles( overhead_y);
+ std::cout << "average of " << res << " cpu cycles" << std::endl;
+#endif
+
+ return EXIT_SUCCESS;
+ }
+ catch ( std::exception const& e)
+ { std::cerr << "exception: " << e.what() << std::endl; }
+ catch (...)
+ { std::cerr << "unhandled exception" << std::endl; }
+ return EXIT_FAILURE;
+}
diff --git a/src/boost/libs/coroutine/performance/bind_processor.hpp b/src/boost/libs/coroutine/performance/bind_processor.hpp
new file mode 100644
index 000000000..f89b50744
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/bind_processor.hpp
@@ -0,0 +1,12 @@
+
+// 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 BIND_TO_PROCESSOR_H
+#define BIND_TO_PROCESSOR_H
+
+void bind_to_processor( unsigned int n);
+
+#endif // BIND_TO_PROCESSOR_H
diff --git a/src/boost/libs/coroutine/performance/bind_processor_aix.cpp b/src/boost/libs/coroutine/performance/bind_processor_aix.cpp
new file mode 100644
index 000000000..8c477fcad
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/bind_processor_aix.cpp
@@ -0,0 +1,25 @@
+
+// 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)
+
+#include "bind_processor.hpp"
+
+extern "C"
+{
+#include <sys/processor.h>
+#include <sys/thread.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ if ( ::bindprocessor( BINDTHREAD, ::thread_yield(), static_cast< cpu_t >( n) ) == -1)
+ throw std::runtime_error("::bindprocessor() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
diff --git a/src/boost/libs/coroutine/performance/bind_processor_freebsd.cpp b/src/boost/libs/coroutine/performance/bind_processor_freebsd.cpp
new file mode 100644
index 000000000..7e28b7067
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/bind_processor_freebsd.cpp
@@ -0,0 +1,29 @@
+
+// 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)
+
+#include "bind_processor.hpp"
+
+extern "C"
+{
+#include <sys/param.h>
+#include <sys/cpuset.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ cpuset_t cpuset;
+ CPU_ZERO( & cpuset);
+ CPU_SET( n, & cpuset);
+
+ if ( ::cpuset_setaffinity( CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof( cpuset), & cpuset) == -1)
+ throw std::runtime_error("::cpuset_setaffinity() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
diff --git a/src/boost/libs/coroutine/performance/bind_processor_hpux.cpp b/src/boost/libs/coroutine/performance/bind_processor_hpux.cpp
new file mode 100644
index 000000000..af33c1125
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/bind_processor_hpux.cpp
@@ -0,0 +1,31 @@
+
+// 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)
+
+#include "bind_processor.hpp"
+
+extern "C"
+{
+#include <sys/pthread.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ ::pthread_spu_t spu;
+ int errno_(
+ ::pthread_processor_bind_np(
+ PTHREAD_BIND_FORCED_NP,
+ & spu,
+ static_cast< pthread_spu_t >( n),
+ PTHREAD_SELFTID_NP) );
+ if ( errno_ != 0)
+ throw std::runtime_error("::pthread_processor_bind_np() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
diff --git a/src/boost/libs/coroutine/performance/bind_processor_linux.cpp b/src/boost/libs/coroutine/performance/bind_processor_linux.cpp
new file mode 100644
index 000000000..3fb958813
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/bind_processor_linux.cpp
@@ -0,0 +1,30 @@
+
+// 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)
+
+#include "bind_processor.hpp"
+
+extern "C"
+{
+#include <pthread.h>
+#include <sched.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ cpu_set_t cpuset;
+ CPU_ZERO( & cpuset);
+ CPU_SET( n, & cpuset);
+
+ int errno_( ::pthread_setaffinity_np( ::pthread_self(), sizeof( cpuset), & cpuset) );
+ if ( errno_ != 0)
+ throw std::runtime_error("::pthread_setaffinity_np() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
diff --git a/src/boost/libs/coroutine/performance/bind_processor_solaris.cpp b/src/boost/libs/coroutine/performance/bind_processor_solaris.cpp
new file mode 100644
index 000000000..0830c1b45
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/bind_processor_solaris.cpp
@@ -0,0 +1,26 @@
+
+// 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)
+
+#include "bind_processor.hpp"
+
+extern "C"
+{
+#include <sys/types.h>
+#include <sys/processor.h>
+#include <sys/procset.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ if ( ::processor_bind( P_LWPID, P_MYID, static_cast< processorid_t >( n), 0) == -1)
+ throw std::runtime_error("::processor_bind() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
diff --git a/src/boost/libs/coroutine/performance/bind_processor_windows.cpp b/src/boost/libs/coroutine/performance/bind_processor_windows.cpp
new file mode 100644
index 000000000..6fefbc65f
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/bind_processor_windows.cpp
@@ -0,0 +1,24 @@
+
+// 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)
+
+#include "bind_processor.hpp"
+
+extern "C"
+{
+#include <windows.h>
+}
+
+#include <stdexcept>
+
+#include <boost/config/abi_prefix.hpp>
+
+void bind_to_processor( unsigned int n)
+{
+ if ( ::SetThreadAffinityMask( ::GetCurrentThread(), ( DWORD_PTR)1 << n) == 0)
+ throw std::runtime_error("::SetThreadAffinityMask() failed");
+}
+
+#include <boost/config/abi_suffix.hpp>
diff --git a/src/boost/libs/coroutine/performance/clock.hpp b/src/boost/libs/coroutine/performance/clock.hpp
new file mode 100644
index 000000000..6103951fa
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/clock.hpp
@@ -0,0 +1,44 @@
+
+// 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 CLOCK_H
+#define CLOCK_H
+
+#include <algorithm>
+#include <cstddef>
+#include <numeric>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/chrono.hpp>
+#include <boost/cstdint.hpp>
+
+typedef boost::chrono::high_resolution_clock clock_type;
+typedef clock_type::duration duration_type;
+typedef clock_type::time_point time_point_type;
+
+struct clock_overhead
+{
+ boost::uint64_t operator()()
+ {
+ time_point_type start( clock_type::now() );
+ return ( clock_type::now() - start).count();
+ }
+};
+
+duration_type overhead_clock()
+{
+ std::size_t iterations( 10);
+ std::vector< boost::uint64_t > overhead( iterations, 0);
+ for ( std::size_t i = 0; i < iterations; ++i)
+ std::generate(
+ overhead.begin(), overhead.end(),
+ clock_overhead() );
+ BOOST_ASSERT( overhead.begin() != overhead.end() );
+ return duration_type( std::accumulate( overhead.begin(), overhead.end(), 0) / iterations);
+}
+
+#endif // CLOCK_H
diff --git a/src/boost/libs/coroutine/performance/cycle.hpp b/src/boost/libs/coroutine/performance/cycle.hpp
new file mode 100644
index 000000000..c26c85983
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/cycle.hpp
@@ -0,0 +1,26 @@
+
+// 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 CYCLE_H
+#define CYCLE_H
+
+// x86_64
+// test x86_64 before i386 because icc might
+// define __i686__ for x86_64 too
+#if defined(__x86_64__) || defined(__x86_64) \
+ || defined(__amd64__) || defined(__amd64) \
+ || defined(_M_X64) || defined(_M_AMD64)
+# include "cycle_x86-64.hpp"
+// i386
+#elif defined(i386) || defined(__i386__) || defined(__i386) \
+ || defined(__i486__) || defined(__i586__) || defined(__i686__) \
+ || defined(__X86__) || defined(_X86_) || defined(__THW_INTEL__) \
+ || defined(__I86__) || defined(__INTEL__) || defined(__IA32__) \
+ || defined(_M_IX86) || defined(_I86_)
+# include "cycle_i386.hpp"
+#endif
+
+#endif // CYCLE_H
diff --git a/src/boost/libs/coroutine/performance/cycle_i386.hpp b/src/boost/libs/coroutine/performance/cycle_i386.hpp
new file mode 100644
index 000000000..a3eb70398
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/cycle_i386.hpp
@@ -0,0 +1,83 @@
+
+// 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 CYCLE_I386_H
+#define CYCLE_I386_H
+
+#include <algorithm>
+#include <numeric>
+#include <cstddef>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/bind.hpp>
+#include <boost/cstdint.hpp>
+
+#define BOOST_CONTEXT_CYCLE
+
+typedef boost::uint64_t cycle_type;
+
+#if _MSC_VER
+inline
+cycle_type cycles()
+{
+ cycle_type c;
+ __asm {
+ cpuid
+ rdtsc
+ mov dword ptr [c + 0], eax
+ mov dword ptr [c + 4], edx
+ }
+ return c;
+}
+#elif defined(__GNUC__) || \
+ defined(__INTEL_COMPILER) || defined(__ICC) || defined(_ECC) || defined(__ICL)
+inline
+cycle_type cycles()
+{
+ boost::uint32_t lo, hi;
+
+ __asm__ __volatile__ (
+ "xorl %%eax, %%eax\n"
+ "cpuid\n"
+ ::: "%eax", "%ebx", "%ecx", "%edx"
+ );
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi) );
+ __asm__ __volatile__ (
+ "xorl %%eax, %%eax\n"
+ "cpuid\n"
+ ::: "%eax", "%ebx", "%ecx", "%edx"
+ );
+
+ return ( cycle_type)hi << 32 | lo;
+}
+#else
+# error "this compiler is not supported"
+#endif
+
+struct cycle_overhead
+{
+ cycle_type operator()()
+ {
+ cycle_type start( cycles() );
+ return cycles() - start;
+ }
+};
+
+inline
+cycle_type overhead_cycle()
+{
+ std::size_t iterations( 10);
+ std::vector< cycle_type > overhead( iterations, 0);
+ for ( std::size_t i( 0); i < iterations; ++i)
+ std::generate(
+ overhead.begin(), overhead.end(),
+ cycle_overhead() );
+ BOOST_ASSERT( overhead.begin() != overhead.end() );
+ return std::accumulate( overhead.begin(), overhead.end(), 0) / iterations;
+}
+
+#endif // CYCLE_I386_H
diff --git a/src/boost/libs/coroutine/performance/cycle_x86-64.hpp b/src/boost/libs/coroutine/performance/cycle_x86-64.hpp
new file mode 100644
index 000000000..fae0226c9
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/cycle_x86-64.hpp
@@ -0,0 +1,79 @@
+
+// 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 CYCLE_X86_64_H
+#define CYCLE_X86_64_H
+
+#include <algorithm>
+#include <numeric>
+#include <cstddef>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/bind.hpp>
+#include <boost/cstdint.hpp>
+
+#define BOOST_CONTEXT_CYCLE
+
+typedef boost::uint64_t cycle_type;
+
+#if _MSC_VER >= 1400
+# include <intrin.h>
+# pragma intrinsic(__rdtsc)
+inline
+cycle_type cycles()
+{ return __rdtsc(); }
+#elif defined(__INTEL_COMPILER) || defined(__ICC) || defined(_ECC) || defined(__ICL)
+inline
+cycle_type cycles()
+{ return __rdtsc(); }
+#elif defined(__GNUC__) || defined(__SUNPRO_C)
+inline
+cycle_type cycles()
+{
+ boost::uint32_t lo, hi;
+
+ __asm__ __volatile__ (
+ "xorl %%eax, %%eax\n"
+ "cpuid\n"
+ ::: "%rax", "%rbx", "%rcx", "%rdx"
+ );
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi) );
+ __asm__ __volatile__ (
+ "xorl %%eax, %%eax\n"
+ "cpuid\n"
+ ::: "%rax", "%rbx", "%rcx", "%rdx"
+ );
+
+ return ( cycle_type)hi << 32 | lo;
+}
+#else
+# error "this compiler is not supported"
+#endif
+
+struct cycle_overhead
+{
+ cycle_type operator()()
+ {
+ cycle_type start( cycles() );
+ return cycles() - start;
+ }
+};
+
+inline
+cycle_type overhead_cycle()
+{
+ std::size_t iterations( 10);
+ std::vector< cycle_type > overhead( iterations, 0);
+ for ( std::size_t i( 0); i < iterations; ++i)
+ std::generate(
+ overhead.begin(), overhead.end(),
+ cycle_overhead() );
+ BOOST_ASSERT( overhead.begin() != overhead.end() );
+ return std::accumulate( overhead.begin(), overhead.end(), 0) / iterations;
+}
+
+#endif // CYCLE_X86_64_H
diff --git a/src/boost/libs/coroutine/performance/preallocated_stack_allocator.hpp b/src/boost/libs/coroutine/performance/preallocated_stack_allocator.hpp
new file mode 100644
index 000000000..3651ae1b8
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/preallocated_stack_allocator.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_FIBER_PREALLOCATED_STACK_ALLOCATOR_H
+#define BOOST_FIBER_PREALLOCATED_STACK_ALLOCATOR_H
+
+#include <cstddef>
+#include <cstdlib>
+#include <stdexcept>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/coroutine/standard_stack_allocator.hpp>
+#include <boost/coroutine/stack_context.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+class preallocated_stack_allocator
+{
+private:
+ boost::coroutines::stack_context stack_ctx_;
+
+public:
+ preallocated_stack_allocator() :
+ stack_ctx_()
+ {
+ boost::coroutines::standard_stack_allocator allocator;
+ allocator.allocate(
+ stack_ctx_,
+ boost::coroutines::standard_stack_allocator::traits_type::default_size() );
+ }
+
+ void allocate( boost::coroutines::stack_context & ctx, std::size_t size)
+ {
+ ctx.sp = stack_ctx_.sp;
+ ctx.size = stack_ctx_.size;
+ }
+
+ void deallocate( boost::coroutines::stack_context & ctx)
+ {
+ }
+};
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#endif // BOOST_FIBER_PREALLOCATED_STACK_ALLOCATOR_H
diff --git a/src/boost/libs/coroutine/performance/symmetric/Jamfile.v2 b/src/boost/libs/coroutine/performance/symmetric/Jamfile.v2
new file mode 100644
index 000000000..585b03c41
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/symmetric/Jamfile.v2
@@ -0,0 +1,83 @@
+
+# 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)
+
+# For more information, see http://www.boost.org/
+
+import common ;
+import feature ;
+import indirect ;
+import modules ;
+import os ;
+import toolset ;
+
+project boost/coroutine/performance/symmetric
+ : requirements
+ <library>/boost/chrono//boost_chrono
+ <library>/boost/context//boost_context
+ <library>/boost/coroutine//boost_coroutine
+ <library>/boost/program_options//boost_program_options
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <link>static
+ <threading>multi
+ <cxxflags>-DBOOST_DISABLE_ASSERTS
+ <optimization>speed
+ <variant>release
+ ;
+
+alias sources
+ : ../bind_processor_aix.cpp
+ : <target-os>aix
+ ;
+
+alias sources
+ : ../bind_processor_freebsd.cpp
+ : <target-os>freebsd
+ ;
+
+alias sources
+ : ../bind_processor_hpux.cpp
+ : <target-os>hpux
+ ;
+
+alias sources
+ : ../bind_processor_linux.cpp
+ : <target-os>linux
+ ;
+
+alias sources
+ : ../bind_processor_solaris.cpp
+ : <target-os>solaris
+ ;
+
+alias sources
+ : ../bind_processor_windows.cpp
+ : <target-os>windows
+ ;
+
+explicit sources ;
+
+exe performance_create_protected
+ : sources
+ performance_create_protected.cpp
+ ;
+
+exe performance_create_standard
+ : sources
+ performance_create_standard.cpp
+ ;
+
+exe performance_create_prealloc
+ : sources
+ performance_create_prealloc.cpp
+ ;
+
+exe performance_switch
+ : sources
+ performance_switch.cpp
+ ;
diff --git a/src/boost/libs/coroutine/performance/symmetric/performance_create_prealloc.cpp b/src/boost/libs/coroutine/performance/symmetric/performance_create_prealloc.cpp
new file mode 100644
index 000000000..bfc549f93
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/symmetric/performance_create_prealloc.cpp
@@ -0,0 +1,114 @@
+
+// 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)
+
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+
+#include <boost/chrono.hpp>
+#include <boost/coroutine/all.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/program_options.hpp>
+
+#include "../bind_processor.hpp"
+#include "../clock.hpp"
+#include "../cycle.hpp"
+#include "../preallocated_stack_allocator.hpp"
+
+typedef preallocated_stack_allocator stack_allocator;
+typedef boost::coroutines::symmetric_coroutine< void > coro_type;
+
+boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
+boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind;
+boost::uint64_t jobs = 1000;
+
+void fn( coro_type::yield_type &) {}
+
+duration_type measure_time( duration_type overhead)
+{
+ stack_allocator stack_alloc;
+ boost::coroutines::attributes attrs( unwind_stack, preserve_fpu);
+
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ coro_type::call_type c( fn, attrs, stack_alloc);
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+
+# ifdef BOOST_CONTEXT_CYCLE
+cycle_type measure_cycles( cycle_type overhead)
+{
+ stack_allocator stack_alloc;
+
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ coro_type::call_type c( fn,
+ boost::coroutines::attributes( unwind_stack, preserve_fpu),
+ stack_alloc);
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+# endif
+
+int main( int argc, char * argv[])
+{
+ try
+ {
+ bool preserve = false, unwind = true, bind = false;
+ boost::program_options::options_description desc("allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
+ ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
+ ("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack")
+ ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
+
+ boost::program_options::variables_map vm;
+ boost::program_options::store(
+ boost::program_options::parse_command_line(
+ argc,
+ argv,
+ desc),
+ vm);
+ boost::program_options::notify( vm);
+
+ if ( vm.count("help") ) {
+ std::cout << desc << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
+ if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind;
+ if ( bind) bind_to_processor( 0);
+
+ duration_type overhead_c = overhead_clock();
+ std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
+ boost::uint64_t res = measure_time( overhead_c).count();
+ std::cout << "average of " << res << " nano seconds" << std::endl;
+#ifdef BOOST_CONTEXT_CYCLE
+ cycle_type overhead_y = overhead_cycle();
+ std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
+ res = measure_cycles( overhead_y);
+ std::cout << "average of " << res << " cpu cycles" << std::endl;
+#endif
+
+ return EXIT_SUCCESS;
+ }
+ catch ( std::exception const& e)
+ { std::cerr << "exception: " << e.what() << std::endl; }
+ catch (...)
+ { std::cerr << "unhandled exception" << std::endl; }
+ return EXIT_FAILURE;
+}
diff --git a/src/boost/libs/coroutine/performance/symmetric/performance_create_protected.cpp b/src/boost/libs/coroutine/performance/symmetric/performance_create_protected.cpp
new file mode 100644
index 000000000..eb6520e73
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/symmetric/performance_create_protected.cpp
@@ -0,0 +1,112 @@
+
+// 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)
+
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+
+#include <boost/chrono.hpp>
+#include <boost/coroutine/all.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/program_options.hpp>
+
+#include "../bind_processor.hpp"
+#include "../clock.hpp"
+#include "../cycle.hpp"
+
+typedef boost::coroutines::protected_stack_allocator stack_allocator;
+typedef boost::coroutines::symmetric_coroutine< void > coro_type;
+
+boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
+boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind;
+boost::uint64_t jobs = 1000;
+
+void fn( coro_type::yield_type &) {}
+
+duration_type measure_time( duration_type overhead)
+{
+ stack_allocator stack_alloc;
+ boost::coroutines::attributes attrs( unwind_stack, preserve_fpu);
+
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ coro_type::call_type c( fn, attrs, stack_alloc);
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+
+# ifdef BOOST_CONTEXT_CYCLE
+cycle_type measure_cycles( cycle_type overhead)
+{
+ stack_allocator stack_alloc;
+
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ coro_type::call_type c( fn,
+ boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc);
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+# endif
+
+int main( int argc, char * argv[])
+{
+ try
+ {
+ bool preserve = false, unwind = true, bind = false;
+ boost::program_options::options_description desc("allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
+ ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
+ ("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack")
+ ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
+
+ boost::program_options::variables_map vm;
+ boost::program_options::store(
+ boost::program_options::parse_command_line(
+ argc,
+ argv,
+ desc),
+ vm);
+ boost::program_options::notify( vm);
+
+ if ( vm.count("help") ) {
+ std::cout << desc << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
+ if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind;
+ if ( bind) bind_to_processor( 0);
+
+ duration_type overhead_c = overhead_clock();
+ std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
+ boost::uint64_t res = measure_time( overhead_c).count();
+ std::cout << "average of " << res << " nano seconds" << std::endl;
+#ifdef BOOST_CONTEXT_CYCLE
+ cycle_type overhead_y = overhead_cycle();
+ std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
+ res = measure_cycles( overhead_y);
+ std::cout << "average of " << res << " cpu cycles" << std::endl;
+#endif
+
+ return EXIT_SUCCESS;
+ }
+ catch ( std::exception const& e)
+ { std::cerr << "exception: " << e.what() << std::endl; }
+ catch (...)
+ { std::cerr << "unhandled exception" << std::endl; }
+ return EXIT_FAILURE;
+}
diff --git a/src/boost/libs/coroutine/performance/symmetric/performance_create_standard.cpp b/src/boost/libs/coroutine/performance/symmetric/performance_create_standard.cpp
new file mode 100644
index 000000000..91df005bd
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/symmetric/performance_create_standard.cpp
@@ -0,0 +1,112 @@
+
+// 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)
+
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+
+#include <boost/chrono.hpp>
+#include <boost/coroutine/all.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/program_options.hpp>
+
+#include "../bind_processor.hpp"
+#include "../clock.hpp"
+#include "../cycle.hpp"
+
+typedef boost::coroutines::standard_stack_allocator stack_allocator;
+typedef boost::coroutines::symmetric_coroutine< void > coro_type;
+
+boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
+boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind;
+boost::uint64_t jobs = 1000;
+
+void fn( coro_type::yield_type &) {}
+
+duration_type measure_time( duration_type overhead)
+{
+ stack_allocator stack_alloc;
+ boost::coroutines::attributes attrs( unwind_stack, preserve_fpu);
+
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ coro_type::call_type c( fn, attrs, stack_alloc);
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+
+# ifdef BOOST_CONTEXT_CYCLE
+cycle_type measure_cycles( cycle_type overhead)
+{
+ stack_allocator stack_alloc;
+
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ coro_type::call_type c( fn,
+ boost::coroutines::attributes( unwind_stack, preserve_fpu), stack_alloc);
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+# endif
+
+int main( int argc, char * argv[])
+{
+ try
+ {
+ bool preserve = false, unwind = true, bind = false;
+ boost::program_options::options_description desc("allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
+ ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
+ ("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack")
+ ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
+
+ boost::program_options::variables_map vm;
+ boost::program_options::store(
+ boost::program_options::parse_command_line(
+ argc,
+ argv,
+ desc),
+ vm);
+ boost::program_options::notify( vm);
+
+ if ( vm.count("help") ) {
+ std::cout << desc << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
+ if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind;
+ if ( bind) bind_to_processor( 0);
+
+ duration_type overhead_c = overhead_clock();
+ std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
+ boost::uint64_t res = measure_time( overhead_c).count();
+ std::cout << "average of " << res << " nano seconds" << std::endl;
+#ifdef BOOST_CONTEXT_CYCLE
+ cycle_type overhead_y = overhead_cycle();
+ std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
+ res = measure_cycles( overhead_y);
+ std::cout << "average of " << res << " cpu cycles" << std::endl;
+#endif
+
+ return EXIT_SUCCESS;
+ }
+ catch ( std::exception const& e)
+ { std::cerr << "exception: " << e.what() << std::endl; }
+ catch (...)
+ { std::cerr << "unhandled exception" << std::endl; }
+ return EXIT_FAILURE;
+}
diff --git a/src/boost/libs/coroutine/performance/symmetric/performance_switch.cpp b/src/boost/libs/coroutine/performance/symmetric/performance_switch.cpp
new file mode 100644
index 000000000..c97b7a62b
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/symmetric/performance_switch.cpp
@@ -0,0 +1,207 @@
+
+// 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)
+
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+#include <string>
+
+#include <boost/chrono.hpp>
+#include <boost/coroutine/all.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/program_options.hpp>
+
+#include "../bind_processor.hpp"
+#include "../clock.hpp"
+#include "../cycle.hpp"
+
+boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
+boost::uint64_t jobs = 1000;
+time_point_type end;
+
+struct X
+{
+ std::string str;
+
+ X( std::string const& str_) :
+ str( str_)
+ {}
+};
+
+const X x("abc");
+
+void fn_void( boost::coroutines::symmetric_coroutine< void >::yield_type & yield)
+{ while( true) yield(); }
+
+void fn_int( boost::coroutines::symmetric_coroutine< int >::yield_type & yield)
+{ while( true) yield(); }
+
+void fn_x( boost::coroutines::symmetric_coroutine< X >::yield_type & yield)
+{ while( true) yield(); }
+
+duration_type measure_time_void( duration_type overhead)
+{
+ boost::coroutines::symmetric_coroutine< void >::call_type c( fn_void,
+ boost::coroutines::attributes( preserve_fpu) );
+ c();
+
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c();
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead_clock(); // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+
+duration_type measure_time_int( duration_type overhead)
+{
+ boost::coroutines::symmetric_coroutine< int >::call_type c( fn_int,
+ boost::coroutines::attributes( preserve_fpu) );
+
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c( i);
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead_clock(); // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+
+duration_type measure_time_x( duration_type overhead)
+{
+ boost::coroutines::symmetric_coroutine< X >::call_type c( fn_x,
+ boost::coroutines::attributes( preserve_fpu) );
+
+ X x("abc");
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c( x);
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead_clock(); // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+
+# ifdef BOOST_CONTEXT_CYCLE
+cycle_type measure_cycles_void( cycle_type overhead)
+{
+ boost::coroutines::symmetric_coroutine< void >::call_type c( fn_void,
+ boost::coroutines::attributes( preserve_fpu) );
+
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c();
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+
+cycle_type measure_cycles_int( cycle_type overhead)
+{
+ boost::coroutines::symmetric_coroutine< int >::call_type c( fn_int,
+ boost::coroutines::attributes( preserve_fpu) );
+
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c( i);
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+
+cycle_type measure_cycles_x( cycle_type overhead)
+{
+ boost::coroutines::symmetric_coroutine< X >::call_type c( fn_x,
+ boost::coroutines::attributes( preserve_fpu) );
+
+ X x("abc");
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ c( x);
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+ total /= 2; // 2x jump_fcontext
+
+ return total;
+}
+# endif
+
+int main( int argc, char * argv[])
+{
+ try
+ {
+ bool preserve = false, bind = false;
+ boost::program_options::options_description desc("allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
+ ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
+ ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
+
+ boost::program_options::variables_map vm;
+ boost::program_options::store(
+ boost::program_options::parse_command_line(
+ argc,
+ argv,
+ desc),
+ vm);
+ boost::program_options::notify( vm);
+
+ if ( vm.count("help") ) {
+ std::cout << desc << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
+ if ( bind) bind_to_processor( 0);
+
+ duration_type overhead_c = overhead_clock();
+ std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
+ boost::uint64_t res = measure_time_void( overhead_c).count();
+ std::cout << "void: average of " << res << " nano seconds" << std::endl;
+ res = measure_time_int( overhead_c).count();
+ std::cout << "int: average of " << res << " nano seconds" << std::endl;
+ res = measure_time_x( overhead_c).count();
+ std::cout << "X: average of " << res << " nano seconds" << std::endl;
+#ifdef BOOST_CONTEXT_CYCLE
+ cycle_type overhead_y = overhead_cycle();
+ std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
+ res = measure_cycles_void( overhead_y);
+ std::cout << "void: average of " << res << " cpu cycles" << std::endl;
+ res = measure_cycles_int( overhead_y);
+ std::cout << "int: average of " << res << " cpu cycles" << std::endl;
+ res = measure_cycles_x( overhead_y);
+ std::cout << "X: average of " << res << " cpu cycles" << std::endl;
+#endif
+
+ return EXIT_SUCCESS;
+ }
+ catch ( std::exception const& e)
+ { std::cerr << "exception: " << e.what() << std::endl; }
+ catch (...)
+ { std::cerr << "unhandled exception" << std::endl; }
+ return EXIT_FAILURE;
+}
diff --git a/src/boost/libs/coroutine/performance/symmetric/segmented/Jamfile.v2 b/src/boost/libs/coroutine/performance/symmetric/segmented/Jamfile.v2
new file mode 100644
index 000000000..073f7e7af
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/symmetric/segmented/Jamfile.v2
@@ -0,0 +1,68 @@
+
+# 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)
+
+# For more information, see http://www.boost.org/
+
+import common ;
+import feature ;
+import indirect ;
+import modules ;
+import os ;
+import toolset ;
+
+project boost/coroutine/performance/segmented
+ : requirements
+ <library>/boost/chrono//boost_chrono
+ <library>/boost/context//boost_context
+ <library>/boost/coroutine//boost_coroutine
+ <library>/boost/program_options//boost_program_options
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <link>static
+ <threading>multi
+ <cxxflags>-DBOOST_DISABLE_ASSERTS
+ <optimization>speed
+ <variant>release
+ ;
+
+alias sources
+ : ../../bind_processor_aix.cpp
+ : <target-os>aix
+ ;
+
+alias sources
+ : ../../bind_processor_freebsd.cpp
+ : <target-os>freebsd
+ ;
+
+alias sources
+ : ../../bind_processor_hpux.cpp
+ : <target-os>hpux
+ ;
+
+alias sources
+ : ../../bind_processor_linux.cpp
+ : <target-os>linux
+ ;
+
+alias sources
+ : ../../bind_processor_solaris.cpp
+ : <target-os>solaris
+ ;
+
+alias sources
+ : ../../bind_processor_windows.cpp
+ : <target-os>windows
+ ;
+
+explicit sources ;
+
+exe performance_create_segmented
+ : sources
+ performance_create_segmented.cpp
+ ;
diff --git a/src/boost/libs/coroutine/performance/symmetric/segmented/performance_create_segmented.cpp b/src/boost/libs/coroutine/performance/symmetric/segmented/performance_create_segmented.cpp
new file mode 100644
index 000000000..8d1e8c1ad
--- /dev/null
+++ b/src/boost/libs/coroutine/performance/symmetric/segmented/performance_create_segmented.cpp
@@ -0,0 +1,105 @@
+
+// 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)
+
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+
+#include <boost/chrono.hpp>
+#include <boost/coroutine/all.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/program_options.hpp>
+
+#include "../../bind_processor.hpp"
+#include "../../clock.hpp"
+#include "../../cycle.hpp"
+
+boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved;
+boost::coroutines::flag_unwind_t unwind_stack = boost::coroutines::stack_unwind;
+boost::uint64_t jobs = 1000;
+
+void fn( boost::coroutines::symmetric_coroutine< void >::yield_type &) {}
+
+duration_type measure_time( duration_type overhead)
+{
+ time_point_type start( clock_type::now() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ boost::coroutines::symmetric_coroutine< void >::call_type c( fn,
+ boost::coroutines::attributes( unwind_stack, preserve_fpu) );
+ }
+ duration_type total = clock_type::now() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+
+# ifdef BOOST_CONTEXT_CYCLE
+cycle_type measure_cycles( cycle_type overhead)
+{
+ cycle_type start( cycles() );
+ for ( std::size_t i = 0; i < jobs; ++i) {
+ boost::coroutines::symmetric_coroutine< void >::call_type c( fn,
+ boost::coroutines::attributes( unwind_stack, preserve_fpu) );
+ }
+ cycle_type total = cycles() - start;
+ total -= overhead; // overhead of measurement
+ total /= jobs; // loops
+
+ return total;
+}
+# endif
+
+int main( int argc, char * argv[])
+{
+ try
+ {
+ bool preserve = false, unwind = true, bind = false;
+ boost::program_options::options_description desc("allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("bind,b", boost::program_options::value< bool >( & bind), "bind thread to CPU")
+ ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers")
+ ("unwind,u", boost::program_options::value< bool >( & unwind), "unwind coroutine-stack")
+ ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run");
+
+ boost::program_options::variables_map vm;
+ boost::program_options::store(
+ boost::program_options::parse_command_line(
+ argc,
+ argv,
+ desc),
+ vm);
+ boost::program_options::notify( vm);
+
+ if ( vm.count("help") ) {
+ std::cout << desc << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved;
+ if ( ! unwind) unwind_stack = boost::coroutines::no_stack_unwind;
+ if ( bind) bind_to_processor( 0);
+
+ duration_type overhead_c = overhead_clock();
+ std::cout << "overhead " << overhead_c.count() << " nano seconds" << std::endl;
+ boost::uint64_t res = measure_time( overhead_c).count();
+ std::cout << "average of " << res << " nano seconds" << std::endl;
+#ifdef BOOST_CONTEXT_CYCLE
+ cycle_type overhead_y = overhead_cycle();
+ std::cout << "overhead " << overhead_y << " cpu cycles" << std::endl;
+ res = measure_cycles( overhead_y);
+ std::cout << "average of " << res << " cpu cycles" << std::endl;
+#endif
+
+ return EXIT_SUCCESS;
+ }
+ catch ( std::exception const& e)
+ { std::cerr << "exception: " << e.what() << std::endl; }
+ catch (...)
+ { std::cerr << "unhandled exception" << std::endl; }
+ return EXIT_FAILURE;
+}
diff --git a/src/boost/libs/coroutine/src/detail/coroutine_context.cpp b/src/boost/libs/coroutine/src/detail/coroutine_context.cpp
new file mode 100644
index 000000000..6a6d52483
--- /dev/null
+++ b/src/boost/libs/coroutine/src/detail/coroutine_context.cpp
@@ -0,0 +1,82 @@
+
+// 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)
+
+#include "boost/coroutine/detail/coroutine_context.hpp"
+
+#include "boost/coroutine/detail/data.hpp"
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+#if defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable:4355)
+#endif
+
+#if defined(BOOST_USE_SEGMENTED_STACKS)
+extern "C" {
+
+void __splitstack_getcontext( void * [BOOST_CONTEXT_SEGMENTS]);
+
+void __splitstack_setcontext( void * [BOOST_CONTEXT_SEGMENTS]);
+
+}
+#endif
+
+namespace boost {
+namespace coroutines {
+namespace detail {
+
+coroutine_context::coroutine_context() :
+ palloc_(),
+ ctx_( 0)
+{}
+
+coroutine_context::coroutine_context( ctx_fn fn, preallocated const& palloc) :
+ palloc_( palloc),
+ ctx_( context::detail::make_fcontext( palloc_.sp, palloc_.size, fn) )
+{}
+
+coroutine_context::coroutine_context( coroutine_context const& other) :
+ palloc_( other.palloc_),
+ ctx_( other.ctx_)
+{}
+
+coroutine_context &
+coroutine_context::operator=( coroutine_context const& other)
+{
+ if ( this == & other) return * this;
+
+ palloc_ = other.palloc_;
+ ctx_ = other.ctx_;
+
+ return * this;
+}
+
+void *
+coroutine_context::jump( coroutine_context & other, void * param)
+{
+#if defined(BOOST_USE_SEGMENTED_STACKS)
+ __splitstack_getcontext( palloc_.sctx.segments_ctx);
+ __splitstack_setcontext( other.palloc_.sctx.segments_ctx);
+#endif
+ data_t data = { this, param };
+ context::detail::transfer_t t = context::detail::jump_fcontext( other.ctx_, & data);
+ data_t * ret = static_cast< data_t * >( t.data);
+ ret->from->ctx_ = t.fctx;
+ return ret->data;
+}
+
+}}}
+
+#if defined(_MSC_VER)
+# pragma warning(pop)
+#endif
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
diff --git a/src/boost/libs/coroutine/src/exceptions.cpp b/src/boost/libs/coroutine/src/exceptions.cpp
new file mode 100644
index 000000000..d32eb5468
--- /dev/null
+++ b/src/boost/libs/coroutine/src/exceptions.cpp
@@ -0,0 +1,37 @@
+
+// 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)
+
+#include "boost/coroutine/exceptions.hpp"
+
+namespace boost {
+namespace coroutines {
+
+class coroutine_error_category : public system::error_category
+{
+public:
+ virtual const char* name() const BOOST_NOEXCEPT
+ { return "coroutine"; }
+
+ virtual std::string message( int ev) const
+ {
+ switch (BOOST_SCOPED_ENUM_NATIVE(coroutine_errc)(ev))
+ {
+ case coroutine_errc::no_data:
+ return std::string("Operation not permitted because coroutine "
+ "has no valid result.");
+ }
+ return std::string("unspecified coroutine_errc value\n");
+ }
+};
+
+BOOST_COROUTINES_DECL
+system::error_category const& coroutine_category() BOOST_NOEXCEPT
+{
+ static coroutines::coroutine_error_category cat;
+ return cat;
+}
+
+}}
diff --git a/src/boost/libs/coroutine/src/posix/stack_traits.cpp b/src/boost/libs/coroutine/src/posix/stack_traits.cpp
new file mode 100644
index 000000000..b62994322
--- /dev/null
+++ b/src/boost/libs/coroutine/src/posix/stack_traits.cpp
@@ -0,0 +1,112 @@
+
+// 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)
+
+#include "boost/coroutine/stack_traits.hpp"
+
+extern "C" {
+#include <signal.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <unistd.h>
+}
+
+//#if _POSIX_C_SOURCE >= 200112L
+
+#include <algorithm>
+#include <cmath>
+
+#include <boost/assert.hpp>
+#include <boost/thread.hpp>
+
+#if !defined (SIGSTKSZ)
+# define SIGSTKSZ (8 * 1024)
+# define UDEF_SIGSTKSZ
+#endif
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace {
+
+void pagesize_( std::size_t * size)
+{
+ // conform to POSIX.1-2001
+ * size = ::sysconf( _SC_PAGESIZE);
+}
+
+void stacksize_limit_( rlimit * limit)
+{
+ // conforming to POSIX.1-2001
+#if defined(BOOST_DISABLE_ASSERTS) || defined(NDEBUG)
+ ::getrlimit( RLIMIT_STACK, limit);
+#else
+ const int result = ::getrlimit( RLIMIT_STACK, limit);
+ BOOST_ASSERT( 0 == result);
+#endif
+}
+
+std::size_t pagesize()
+{
+ static std::size_t size = 0;
+ static boost::once_flag flag;
+ boost::call_once( flag, pagesize_, & size);
+ return size;
+}
+
+rlimit stacksize_limit()
+{
+ static rlimit limit;
+ static boost::once_flag flag;
+ boost::call_once( flag, stacksize_limit_, & limit);
+ return limit;
+}
+
+}
+
+namespace boost {
+namespace coroutines {
+
+bool
+stack_traits::is_unbounded() BOOST_NOEXCEPT
+{ return RLIM_INFINITY == stacksize_limit().rlim_max; }
+
+std::size_t
+stack_traits::page_size() BOOST_NOEXCEPT
+{ return pagesize(); }
+
+std::size_t
+stack_traits::default_size() BOOST_NOEXCEPT
+{
+ std::size_t size = 8 * minimum_size();
+ if ( is_unbounded() ) return size;
+
+ BOOST_ASSERT( maximum_size() >= minimum_size() );
+ return maximum_size() == size
+ ? size
+ : (std::min)( size, maximum_size() );
+}
+
+std::size_t
+stack_traits::minimum_size() BOOST_NOEXCEPT
+{ return SIGSTKSZ; }
+
+std::size_t
+stack_traits::maximum_size() BOOST_NOEXCEPT
+{
+ BOOST_ASSERT( ! is_unbounded() );
+ return static_cast< std::size_t >( stacksize_limit().rlim_max);
+}
+
+}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
+
+#ifdef UDEF_SIGSTKSZ
+# undef SIGSTKSZ
+#endif
diff --git a/src/boost/libs/coroutine/src/windows/stack_traits.cpp b/src/boost/libs/coroutine/src/windows/stack_traits.cpp
new file mode 100644
index 000000000..bdf417a74
--- /dev/null
+++ b/src/boost/libs/coroutine/src/windows/stack_traits.cpp
@@ -0,0 +1,114 @@
+
+// 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)
+
+#include "boost/coroutine/stack_traits.hpp"
+
+extern "C" {
+#include <windows.h>
+}
+
+//#if defined (BOOST_WINDOWS) || _POSIX_C_SOURCE >= 200112L
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
+#include <stdexcept>
+
+#include <boost/assert.hpp>
+#include <boost/coroutine/detail/config.hpp>
+#include <boost/thread.hpp>
+
+#include <boost/coroutine/stack_context.hpp>
+
+// x86_64
+// test x86_64 before i386 because icc might
+// define __i686__ for x86_64 too
+#if defined(__x86_64__) || defined(__x86_64) \
+ || defined(__amd64__) || defined(__amd64) \
+ || defined(_M_X64) || defined(_M_AMD64)
+
+// Windows seams not to provide a constant or function
+// telling the minimal stacksize
+# define MIN_STACKSIZE 8 * 1024
+#else
+# define MIN_STACKSIZE 4 * 1024
+#endif
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_PREFIX
+#endif
+
+namespace {
+
+void system_info_( SYSTEM_INFO * si)
+{ ::GetSystemInfo( si); }
+
+SYSTEM_INFO system_info()
+{
+ static SYSTEM_INFO si;
+ static boost::once_flag flag;
+ boost::call_once( flag, static_cast< void(*)( SYSTEM_INFO *) >( system_info_), & si);
+ return si;
+}
+
+std::size_t pagesize()
+{ return static_cast< std::size_t >( system_info().dwPageSize); }
+
+std::size_t page_count( std::size_t stacksize)
+{
+ return static_cast< std::size_t >(
+ std::floor(
+ static_cast< float >( stacksize) / pagesize() ) );
+}
+
+}
+
+namespace boost {
+namespace coroutines {
+
+// Windows seams not to provide a limit for the stacksize
+// libcoco uses 32k+4k bytes as minimum
+bool
+stack_traits::is_unbounded() BOOST_NOEXCEPT
+{ return true; }
+
+std::size_t
+stack_traits::page_size() BOOST_NOEXCEPT
+{ return pagesize(); }
+
+std::size_t
+stack_traits::default_size() BOOST_NOEXCEPT
+{
+ std::size_t size = 64 * 1024; // 64 kB
+ if ( is_unbounded() )
+ return (std::max)( size, minimum_size() );
+
+ BOOST_ASSERT( maximum_size() >= minimum_size() );
+ return maximum_size() == minimum_size()
+ ? minimum_size()
+ : ( std::min)( size, maximum_size() );
+}
+
+// because Windows seams not to provide a limit for minimum stacksize
+std::size_t
+stack_traits::minimum_size() BOOST_NOEXCEPT
+{ return MIN_STACKSIZE; }
+
+// because Windows seams not to provide a limit for maximum stacksize
+// maximum_size() can never be called (pre-condition ! is_unbounded() )
+std::size_t
+stack_traits::maximum_size() BOOST_NOEXCEPT
+{
+ BOOST_ASSERT( ! is_unbounded() );
+ return 1 * 1024 * 1024 * 1024; // 1GB
+}
+
+}}
+
+#ifdef BOOST_HAS_ABI_HEADERS
+# include BOOST_ABI_SUFFIX
+#endif
diff --git a/src/boost/libs/coroutine/test/Jamfile.v2 b/src/boost/libs/coroutine/test/Jamfile.v2
new file mode 100644
index 000000000..3481e0f7e
--- /dev/null
+++ b/src/boost/libs/coroutine/test/Jamfile.v2
@@ -0,0 +1,33 @@
+# Boost.Coroutine Library Tests Jamfile
+
+# 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)
+
+import common ;
+import feature ;
+import indirect ;
+import modules ;
+import os ;
+import testing ;
+import toolset ;
+
+project boost/coroutine/test
+ : requirements
+ <library>/boost/context//boost_context
+ <library>/boost/coroutine//boost_coroutine
+ <library>/boost/program_options//boost_program_options
+ <library>/boost/test///boost_unit_test_framework
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack
+ <toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS
+ <link>static
+ <threading>multi
+ ;
+
+test-suite "coroutine" :
+ [ run test_asymmetric_coroutine.cpp ]
+ [ run test_symmetric_coroutine.cpp ]
+ ;
diff --git a/src/boost/libs/coroutine/test/test_asymmetric_coroutine.cpp b/src/boost/libs/coroutine/test/test_asymmetric_coroutine.cpp
new file mode 100644
index 000000000..124271a17
--- /dev/null
+++ b/src/boost/libs/coroutine/test/test_asymmetric_coroutine.cpp
@@ -0,0 +1,627 @@
+
+// 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)
+
+#include <boost/coroutine/asymmetric_coroutine.hpp>
+
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include <cstdio>
+
+#include <boost/assert.hpp>
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+#include <boost/move/move.hpp>
+#include <boost/range.hpp>
+#include <boost/ref.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/utility.hpp>
+
+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;
+
+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::asymmetric_coroutine< int >::push_type &)
+ { 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::asymmetric_coroutine< int >::push_type &)
+ { value3 = state; }
+};
+
+struct my_exception {};
+
+void f1( coro::asymmetric_coroutine< void >::push_type & c)
+{
+ while ( c)
+ c();
+}
+
+void f2( coro::asymmetric_coroutine< void >::push_type &)
+{ ++value1; }
+
+void f3( coro::asymmetric_coroutine< void >::push_type & c)
+{
+ ++value1;
+ c();
+ ++value1;
+}
+
+void f4( coro::asymmetric_coroutine< int >::push_type & c)
+{
+ c( 3);
+ c( 7);
+}
+
+void f5( coro::asymmetric_coroutine< std::string >::push_type & c)
+{
+ std::string res("abc");
+ c( res);
+ res = "xyz";
+ c( res);
+}
+
+void f6( coro::asymmetric_coroutine< int >::pull_type & c)
+{ value1 = c.get(); }
+
+void f7( coro::asymmetric_coroutine< std::string >::pull_type & c)
+{ value2 = c.get(); }
+
+void f8( coro::asymmetric_coroutine< boost::tuple< double, double > >::pull_type & 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::asymmetric_coroutine< int * >::pull_type & c)
+{ value5 = c.get(); }
+
+void f91( coro::asymmetric_coroutine< int const* >::pull_type & c)
+{ value5 = const_cast< int * >( c.get() ); }
+
+void f10( coro::asymmetric_coroutine< int & >::pull_type & c)
+{
+ int const& i = c.get();
+ value5 = const_cast< int * >( & i);
+}
+
+void f101( coro::asymmetric_coroutine< int const& >::pull_type & c)
+{
+ int const& i = c.get();
+ value5 = const_cast< int * >( & i);
+}
+
+void f11( coro::asymmetric_coroutine< boost::tuple< int, int > >::pull_type & c)
+{
+ boost::tie( value8, value9) = c.get();
+}
+
+void f12( coro::asymmetric_coroutine< void >::pull_type & c)
+{
+ X x_;
+ c();
+ c();
+}
+
+template< typename E >
+void f14( coro::asymmetric_coroutine< void >::pull_type &, E const& e)
+{ throw e; }
+
+void f16( coro::asymmetric_coroutine< int >::push_type & c)
+{
+ c( 1);
+ c( 2);
+ c( 3);
+ c( 4);
+ c( 5);
+}
+
+void f17( coro::asymmetric_coroutine< int >::pull_type & c, std::vector< int > & vec)
+{
+ int x = c.get();
+ while ( 5 > x)
+ {
+ vec.push_back( x);
+ x = c().get();
+ }
+}
+
+void f19( coro::asymmetric_coroutine< int* >::push_type & c, std::vector< int * > & vec)
+{
+ BOOST_FOREACH( int * ptr, vec)
+ { c( ptr); }
+}
+
+void f20( coro::asymmetric_coroutine< int >::push_type &)
+{}
+
+void f21( coro::asymmetric_coroutine< int >::pull_type & c)
+{
+ while ( c)
+ {
+ value1 = c.get();
+ c();
+ }
+}
+
+void test_move()
+{
+ {
+ coro::asymmetric_coroutine< void >::pull_type coro1;
+ coro::asymmetric_coroutine< void >::pull_type coro2( f1);
+ BOOST_CHECK( ! coro1);
+ BOOST_CHECK( coro2);
+ coro2();
+ coro1 = boost::move( coro2);
+ BOOST_CHECK( coro1);
+ coro1();
+ BOOST_CHECK( ! coro2);
+ }
+
+ {
+ value3 = false;
+ copyable cp( 3);
+ BOOST_CHECK( cp.state);
+ BOOST_CHECK( ! value3);
+ coro::asymmetric_coroutine< int >::pull_type coro( cp);
+ BOOST_CHECK( cp.state);
+ BOOST_CHECK( value3);
+ }
+
+ {
+ value3 = false;
+ moveable mv( 7);
+ BOOST_CHECK( mv.state);
+ BOOST_CHECK( ! value3);
+ coro::asymmetric_coroutine< int >::pull_type coro( boost::move( mv) );
+ BOOST_CHECK( ! mv.state);
+ BOOST_CHECK( value3);
+ }
+}
+
+void test_complete()
+{
+ value1 = 0;
+
+ coro::asymmetric_coroutine< void >::pull_type coro( f2);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( ( int)1, value1);
+}
+
+void test_jump()
+{
+ value1 = 0;
+
+ coro::asymmetric_coroutine< void >::pull_type 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::asymmetric_coroutine< int >::pull_type 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::asymmetric_coroutine< std::string >::pull_type 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::asymmetric_coroutine< int >::push_type coro( f6);
+ BOOST_CHECK( coro);
+ coro( 3);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( 3, value1);
+}
+
+void test_arg_string()
+{
+ value2 = "";
+
+ coro::asymmetric_coroutine< std::string >::push_type 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::asymmetric_coroutine< boost::tuple< double, double > >::push_type 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::asymmetric_coroutine< int * >::push_type 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::asymmetric_coroutine< int const* >::push_type coro( f91);
+ BOOST_CHECK( coro);
+ coro( & a);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( & a, value5);
+}
+
+void test_ref()
+{
+ value5 = 0;
+
+ int a = 3;
+ coro::asymmetric_coroutine< int & >::push_type 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::asymmetric_coroutine< int const& >::push_type 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::asymmetric_coroutine< boost::tuple< int, int > >::push_type 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::asymmetric_coroutine< void >::push_type 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::asymmetric_coroutine< void >::push_type coro(
+ f12,
+ coro::attributes(
+ coro::stack_allocator::traits_type::default_size(),
+ 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::asymmetric_coroutine< void >::push_type 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_input_iterator()
+{
+ {
+ std::vector< int > vec;
+ coro::asymmetric_coroutine< int >::pull_type 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::asymmetric_coroutine< int >::pull_type coro( f16);
+ coro::asymmetric_coroutine< int >::pull_type::iterator e = boost::end( coro);
+ for (
+ coro::asymmetric_coroutine< int >::pull_type::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< int* > vec_in;
+ vec_in.push_back( & i1);
+ vec_in.push_back( & i2);
+ vec_in.push_back( & i3);
+ std::vector< int* > vec_out;
+ coro::asymmetric_coroutine< int* >::pull_type coro( boost::bind( f19, _1, boost::ref( vec_in) ) );
+ coro::asymmetric_coroutine< int* >::pull_type::iterator e = boost::end( coro);
+ for (
+ coro::asymmetric_coroutine< int* >::pull_type::iterator i = boost::begin( coro);
+ i != e; ++i)
+ {
+ int * p = * i;
+ vec_out.push_back( p);
+ }
+ 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_output_iterator()
+{
+ int counter = 0;
+ std::vector< int > vec;
+ coro::asymmetric_coroutine< int >::push_type coro(
+ boost::bind( f17, _1, boost::ref( vec) ) );
+ coro::asymmetric_coroutine< int >::push_type::iterator e( boost::end( coro) );
+ for ( coro::asymmetric_coroutine< int >::push_type::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] );
+}
+
+void test_invalid_result()
+{
+ bool catched = false;
+ coro::asymmetric_coroutine< int >::pull_type coro( f20);
+ BOOST_CHECK( ! coro);
+ try
+ {
+ int i = coro.get();
+ (void)i;
+ }
+ catch ( coro::invalid_result const&)
+ {
+ catched = true;
+ }
+ BOOST_CHECK( catched);
+}
+void test_move_coro()
+{
+ value1 = 0;
+
+ coro::asymmetric_coroutine< int >::push_type coro1( f21);
+ coro::asymmetric_coroutine< int >::push_type coro2;
+ BOOST_CHECK( coro1);
+ BOOST_CHECK( ! coro2);
+
+ coro1( 1);
+ BOOST_CHECK_EQUAL( ( int)1, value1);
+
+ coro2 = boost::move( coro1);
+ BOOST_CHECK( ! coro1);
+ BOOST_CHECK( coro2);
+
+ coro2( 2);
+ BOOST_CHECK_EQUAL( ( int)2, value1);
+
+ coro1 = boost::move( coro2);
+ BOOST_CHECK( coro1);
+ BOOST_CHECK( ! coro2);
+
+ coro1( 3);
+ BOOST_CHECK_EQUAL( ( int)3, value1);
+
+ coro2 = boost::move( coro1);
+ BOOST_CHECK( ! coro1);
+ BOOST_CHECK( coro2);
+
+ coro2( 4);
+ BOOST_CHECK_EQUAL( ( int)4, value1);
+}
+
+void foo( coro::asymmetric_coroutine< int >::push_type & yield)
+{
+ yield( 1);
+}
+
+coro::asymmetric_coroutine< int >::pull_type make_range()
+{
+ return coro::asymmetric_coroutine< int >::pull_type( foo);
+}
+
+template< typename Range >
+void const_func( Range const& r)
+{
+ begin( r);
+}
+
+void test_range()
+{
+ const_func( make_range() );
+}
+
+boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
+{
+ boost::unit_test::test_suite * test =
+ BOOST_TEST_SUITE("Boost.coroutine: asymmetric coroutine test suite");
+
+ 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_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) );
+ test->add( BOOST_TEST_CASE( & test_invalid_result) );
+ 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) );
+ test->add( BOOST_TEST_CASE( & test_exceptions) );
+ test->add( BOOST_TEST_CASE( & test_input_iterator) );
+ test->add( BOOST_TEST_CASE( & test_output_iterator) );
+ test->add( BOOST_TEST_CASE( & test_range) );
+
+ return test;
+}
diff --git a/src/boost/libs/coroutine/test/test_symmetric_coroutine.cpp b/src/boost/libs/coroutine/test/test_symmetric_coroutine.cpp
new file mode 100644
index 000000000..55015ceec
--- /dev/null
+++ b/src/boost/libs/coroutine/test/test_symmetric_coroutine.cpp
@@ -0,0 +1,604 @@
+
+// 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)
+
+#include <boost/coroutine/symmetric_coroutine.hpp>
+
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include <cstdio>
+
+#include <boost/assert.hpp>
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/move/move.hpp>
+#include <boost/range.hpp>
+#include <boost/ref.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/utility.hpp>
+
+namespace coro = boost::coroutines;
+
+bool value1 = false;
+int value2 = 0;
+std::string value3;
+
+typedef void( * coro_fn_void)(coro::symmetric_coroutine< void* >::yield_type &);
+
+coro::symmetric_coroutine< void >::call_type * term_coro = 0;
+
+struct X
+{
+ int i;
+
+ X() :
+ i( 0)
+ {}
+
+ X( int i_) :
+ i( i_)
+ {}
+};
+
+X * p = 0;
+
+struct Y
+{
+ Y()
+ { value2 = 7; }
+
+ ~Y()
+ { value2 = 0; }
+};
+
+template< typename X, typename I >
+void trampoline( coro::symmetric_coroutine< void* >::yield_type & yield)
+{
+ void * vp = yield.get();
+ X * x = static_cast< X * >( vp);
+ I i( yield);
+ x->d = & i;
+ i.suspend();
+ i.run();
+}
+
+struct B
+{
+ virtual ~B() {}
+
+ virtual void foo() = 0;
+};
+
+class D : public B
+{
+public:
+ int count;
+ coro::symmetric_coroutine< void* >::call_type call;
+ coro::symmetric_coroutine< void* >::yield_type * yield;
+
+ D( coro::symmetric_coroutine< void* >::yield_type & yield_) :
+ B(),
+ count( 0),
+ call(),
+ yield( & yield_)
+ {}
+
+ void foo() {}
+
+ void resume()
+ { call( 0); }
+
+ void suspend()
+ { ( *yield)(); }
+
+ void run()
+ {
+ while ( yield && * yield)
+ {
+ ++count;
+ suspend();
+ }
+ }
+};
+
+struct T
+{
+ D * d;
+
+ T() :
+ d( 0)
+ {}
+};
+
+class copyable
+{
+public:
+ bool state;
+
+ copyable() :
+ state( false)
+ {}
+
+ copyable( int) :
+ state( true)
+ {}
+
+ void operator()( coro::symmetric_coroutine< bool >::yield_type & yield)
+ {
+ if ( yield)
+ value1 = yield.get();
+ }
+};
+
+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::symmetric_coroutine< int >::yield_type &)
+ { value1 = state; }
+};
+
+void empty( coro::symmetric_coroutine< void >::yield_type &) {}
+
+void f2( coro::symmetric_coroutine< void >::yield_type &)
+{ ++value2; }
+
+void f3( coro::symmetric_coroutine< X >::yield_type & yield)
+{ value2 = yield.get().i; }
+
+void f4( coro::symmetric_coroutine< X& >::yield_type & yield)
+{
+ X & x = yield.get();
+ p = & x;
+}
+
+void f5( coro::symmetric_coroutine< X* >::yield_type & yield)
+{ p = yield.get(); }
+
+void f6( coro::symmetric_coroutine< void >::yield_type & yield)
+{
+ Y y;
+ yield( *term_coro);
+}
+
+void f7( coro::symmetric_coroutine< int >::yield_type & yield)
+{
+ value2 = yield.get();
+ yield( *term_coro);
+ value2 = yield.get();
+}
+
+template< typename E >
+void f9( coro::symmetric_coroutine< void >::yield_type &, E const& e)
+{ throw e; }
+
+void f10( coro::symmetric_coroutine< int >::yield_type & yield,
+ coro::symmetric_coroutine< int >::call_type & other)
+{
+ int i = yield.get();
+ yield( other, i);
+ value2 = yield.get();
+}
+
+void f101( coro::symmetric_coroutine< int >::yield_type & yield)
+{ value2 = yield.get(); }
+
+void f11( coro::symmetric_coroutine< void >::yield_type & yield,
+ coro::symmetric_coroutine< void >::call_type & other)
+{
+ yield( other);
+ value2 = 7;
+}
+
+void f111( coro::symmetric_coroutine< void >::yield_type &)
+{ value2 = 3; }
+
+void f12( coro::symmetric_coroutine< X& >::yield_type & yield,
+ coro::symmetric_coroutine< X& >::call_type & other)
+{
+ yield( other, yield.get());
+ p = & yield.get();
+}
+
+void f121( coro::symmetric_coroutine< X& >::yield_type & yield)
+{ p = & yield.get(); }
+
+void f14( coro::symmetric_coroutine< int >::yield_type & yield,
+ coro::symmetric_coroutine< std::string >::call_type & other)
+{
+ std::string str( boost::lexical_cast< std::string >( yield.get() ) );
+ yield( other, str);
+ value2 = yield.get();
+}
+
+void f141( coro::symmetric_coroutine< std::string >::yield_type & yield)
+{ value3 = yield.get(); }
+
+void f15( coro::symmetric_coroutine< int >::yield_type & yield,
+ int offset,
+ coro::symmetric_coroutine< int >::call_type & other)
+{
+ int x = yield.get();
+ value2 += x + offset;
+ yield( other, x);
+ x = yield.get();
+ value2 += x + offset;
+ yield( other, x);
+}
+
+void f151( coro::symmetric_coroutine< int >::yield_type & yield,
+ int offset)
+{
+ int x = yield.get();
+ value2 += x + offset;
+ yield();
+ x = yield.get();
+ value2 += x + offset;
+}
+
+void f16( coro::symmetric_coroutine< int >::yield_type & yield)
+{
+ while ( yield)
+ {
+ value2 = yield.get();
+ yield();
+ }
+}
+
+void test_move()
+{
+ {
+ coro::symmetric_coroutine< void >::call_type coro1;
+ coro::symmetric_coroutine< void >::call_type coro2( empty);
+ BOOST_CHECK( ! coro1);
+ BOOST_CHECK( coro2);
+ coro1 = boost::move( coro2);
+ BOOST_CHECK( coro1);
+ BOOST_CHECK( ! coro2);
+ }
+
+ {
+ value1 = false;
+ copyable cp( 3);
+ BOOST_CHECK( cp.state);
+ BOOST_CHECK( ! value1);
+ coro::symmetric_coroutine< bool >::call_type coro( cp);
+ coro( true);
+ BOOST_CHECK( cp.state);
+ BOOST_CHECK( value1);
+ }
+
+ {
+ value1 = false;
+ moveable mv( 7);
+ BOOST_CHECK( mv.state);
+ BOOST_CHECK( ! value1);
+ coro::symmetric_coroutine< int >::call_type coro( boost::move( mv) );
+ coro( 7);
+ BOOST_CHECK( ! mv.state);
+ BOOST_CHECK( value1);
+ }
+}
+
+void test_complete()
+{
+ value2 = 0;
+
+ coro::symmetric_coroutine< void >::call_type coro( f2);
+ BOOST_CHECK( coro);
+ coro();
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( ( int)1, value2);
+}
+
+void test_yield()
+{
+ value2 = 0;
+
+ coro::symmetric_coroutine< int >::call_type coro3(
+ boost::bind( f151, _1, 3) );
+ BOOST_CHECK( coro3);
+ coro::symmetric_coroutine< int >::call_type coro2(
+ boost::bind( f15, _1, 2, boost::ref( coro3) ) );
+ BOOST_CHECK( coro2);
+ coro::symmetric_coroutine< int >::call_type coro1(
+ boost::bind( f15, _1, 1, boost::ref( coro2) ) );
+ BOOST_CHECK( coro1);
+
+ BOOST_CHECK_EQUAL( ( int)0, value2);
+ coro1( 1);
+ BOOST_CHECK( coro3);
+ BOOST_CHECK( coro2);
+ BOOST_CHECK( coro1);
+ BOOST_CHECK_EQUAL( ( int)9, value2);
+ coro1( 2);
+ BOOST_CHECK( ! coro3);
+ BOOST_CHECK( coro2);
+ BOOST_CHECK( coro1);
+ BOOST_CHECK_EQUAL( ( int)21, value2);
+}
+
+void test_pass_value()
+{
+ value2 = 0;
+
+ X x(7);
+ BOOST_CHECK_EQUAL( ( int)7, x.i);
+ BOOST_CHECK_EQUAL( 0, value2);
+ coro::symmetric_coroutine< X >::call_type coro( f3);
+ BOOST_CHECK( coro);
+ coro(7);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( ( int)7, x.i);
+ BOOST_CHECK_EQUAL( 7, value2);
+}
+
+void test_pass_reference()
+{
+ p = 0;
+
+ X x;
+ coro::symmetric_coroutine< X& >::call_type coro( f4);
+ BOOST_CHECK( coro);
+ coro( x);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK( p == & x);
+}
+
+void test_pass_pointer()
+{
+ p = 0;
+
+ X x;
+ coro::symmetric_coroutine< X* >::call_type coro( f5);
+ BOOST_CHECK( coro);
+ coro( & x);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK( p == & x);
+}
+
+void test_unwind()
+{
+ value2 = 0;
+ {
+ coro::symmetric_coroutine< void >::call_type coro( f6);
+ coro::symmetric_coroutine< void >::call_type coro_e( empty);
+ BOOST_CHECK( coro);
+ BOOST_CHECK( coro_e);
+ term_coro = & coro_e;
+ BOOST_CHECK_EQUAL( ( int) 0, value2);
+ coro();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( int) 7, value2);
+ }
+ BOOST_CHECK_EQUAL( ( int) 0, value2);
+}
+
+void test_no_unwind()
+{
+ value2 = 0;
+ {
+ coro::symmetric_coroutine< void >::call_type coro( f6,
+ coro::attributes(
+ coro::stack_allocator::traits_type::default_size(),
+ coro::no_stack_unwind) );
+ coro::symmetric_coroutine< void >::call_type coro_e( empty);
+ BOOST_CHECK( coro);
+ BOOST_CHECK( coro_e);
+ term_coro = & coro_e;
+ BOOST_CHECK_EQUAL( ( int) 0, value2);
+ coro();
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( int) 7, value2);
+ }
+ BOOST_CHECK_EQUAL( ( int) 7, value2);
+}
+
+void test_termination()
+{
+ value2 = 0;
+
+ coro::symmetric_coroutine< int >::call_type coro( f7);
+ coro::symmetric_coroutine< void >::call_type coro_e( empty);
+ BOOST_CHECK( coro);
+ BOOST_CHECK( coro_e);
+ term_coro = & coro_e;
+ BOOST_CHECK_EQUAL( ( int) 0, value2);
+ coro(3);
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( int) 3, value2);
+ coro(7);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( ( int) 7, value2);
+}
+
+void test_yield_to_void()
+{
+ value2 = 0;
+
+ coro::symmetric_coroutine< void >::call_type coro_other( f111);
+ coro::symmetric_coroutine< void >::call_type coro( boost::bind( f11, _1, boost::ref( coro_other) ) );
+ BOOST_CHECK( coro_other);
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( int) 0, value2);
+ coro();
+ BOOST_CHECK( ! coro_other);
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( int) 3, value2);
+ coro();
+ BOOST_CHECK( ! coro_other);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( ( int) 7, value2);
+}
+
+void test_yield_to_int()
+{
+ value2 = 0;
+
+ coro::symmetric_coroutine< int >::call_type coro_other( f101);
+ coro::symmetric_coroutine< int >::call_type coro( boost::bind( f10, _1, boost::ref( coro_other) ) );
+ BOOST_CHECK( coro_other);
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( int) 0, value2);
+ coro(3);
+ BOOST_CHECK( ! coro_other);
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( int) 3, value2);
+ coro(7);
+ BOOST_CHECK( ! coro_other);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( ( int) 7, value2);
+}
+
+void test_yield_to_ref()
+{
+ p = 0;
+
+ coro::symmetric_coroutine< X& >::call_type coro_other( f121);
+ coro::symmetric_coroutine< X& >::call_type coro( boost::bind( f12, _1, boost::ref( coro_other) ) );
+ BOOST_CHECK( coro_other);
+ BOOST_CHECK( coro);
+ BOOST_CHECK( 0 == p);
+ X x1(3);
+ coro( x1);
+ BOOST_CHECK( ! coro_other);
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( p->i, x1.i);
+ BOOST_CHECK( p == & x1);
+ X x2(7);
+ coro(x2);
+ BOOST_CHECK( ! coro_other);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( p->i, x2.i);
+ BOOST_CHECK( p == & x2);
+}
+
+void test_yield_to_different()
+{
+ value2 = 0;
+ value3 = "";
+
+ coro::symmetric_coroutine< std::string >::call_type coro_other( f141);
+ coro::symmetric_coroutine< int >::call_type coro( boost::bind( f14, _1, boost::ref( coro_other) ) );
+ BOOST_CHECK( coro_other);
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( ( int) 0, value2);
+ BOOST_CHECK( value3.empty() );
+ coro(3);
+ BOOST_CHECK( ! coro_other);
+ BOOST_CHECK( coro);
+ BOOST_CHECK_EQUAL( "3", value3);
+ coro(7);
+ BOOST_CHECK( ! coro_other);
+ BOOST_CHECK( ! coro);
+ BOOST_CHECK_EQUAL( ( int) 7, value2);
+}
+
+void test_move_coro()
+{
+ value2 = 0;
+
+ coro::symmetric_coroutine< int >::call_type coro1( f16);
+ coro::symmetric_coroutine< int >::call_type coro2;
+ BOOST_CHECK( coro1);
+ BOOST_CHECK( ! coro2);
+
+ coro1( 1);
+ BOOST_CHECK_EQUAL( ( int)1, value2);
+
+ coro2 = boost::move( coro1);
+ BOOST_CHECK( ! coro1);
+ BOOST_CHECK( coro2);
+
+ coro2( 2);
+ BOOST_CHECK_EQUAL( ( int)2, value2);
+
+ coro1 = boost::move( coro2);
+ BOOST_CHECK( coro1);
+ BOOST_CHECK( ! coro2);
+
+ coro1( 3);
+ BOOST_CHECK_EQUAL( ( int)3, value2);
+
+ coro2 = boost::move( coro1);
+ BOOST_CHECK( ! coro1);
+ BOOST_CHECK( coro2);
+
+ coro2( 4);
+ BOOST_CHECK_EQUAL( ( int)4, value2);
+}
+
+void test_vptr()
+{
+ D * d = 0;
+ T t;
+ coro_fn_void fn = trampoline< T, D >;
+ coro::symmetric_coroutine< void* >::call_type call( fn);
+ call( & t);
+ d = t.d;
+ BOOST_CHECK( 0 != d);
+ d->call = boost::move( call);
+
+ BOOST_CHECK_EQUAL( ( int) 0, d->count);
+ d->resume();
+ BOOST_CHECK_EQUAL( ( int) 1, d->count);
+ d->resume();
+ BOOST_CHECK_EQUAL( ( int) 2, d->count);
+}
+
+boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
+{
+ boost::unit_test::test_suite * test =
+ BOOST_TEST_SUITE("Boost.coroutine: symmetric coroutine test suite");
+
+ test->add( BOOST_TEST_CASE( & test_move) );
+ test->add( BOOST_TEST_CASE( & test_complete) );
+ test->add( BOOST_TEST_CASE( & test_yield) );
+ test->add( BOOST_TEST_CASE( & test_pass_value) );
+ test->add( BOOST_TEST_CASE( & test_pass_reference) );
+ test->add( BOOST_TEST_CASE( & test_pass_pointer) );
+ test->add( BOOST_TEST_CASE( & test_termination) );
+ test->add( BOOST_TEST_CASE( & test_unwind) );
+ test->add( BOOST_TEST_CASE( & test_no_unwind) );
+ test->add( BOOST_TEST_CASE( & test_yield_to_void) );
+ test->add( BOOST_TEST_CASE( & test_yield_to_int) );
+ test->add( BOOST_TEST_CASE( & test_yield_to_ref) );
+ test->add( BOOST_TEST_CASE( & test_yield_to_different) );
+ test->add( BOOST_TEST_CASE( & test_move_coro) );
+ test->add( BOOST_TEST_CASE( & test_vptr) );
+
+ return test;
+}