blob: a959408513560619ddc4fa30778e5253831f816d [file] [log] [blame]
// See PR94359, we will need either a general solution to this, or at least
// some hook for targets to opt in, for now the test will work on targets that
// can do the tailcall (which would normally be available for O2+)
// { dg-do run { target { i?86-*-linux-gnu x86_64-*-linux-gnu *-*-darwin* } } }
// { dg-additional-options "-O2" }
#if __has_include(<coroutine>)
#include <coroutine>
namespace coro = std;
#elif __has_include(<experimental/coroutine>)
#include <experimental/coroutine>
namespace coro = std::experimental;
#endif
#if __clang__
# include <utility>
#endif
#include <chrono>
#include <thread>
#include <cstdio>
template <typename T>
struct Loopy {
struct promise_type;
using handle_type = coro::coroutine_handle<Loopy::promise_type>;
handle_type handle;
struct promise_type {
// Cause the Loopy object to be created from the handle.
auto get_return_object () {
return handle_type::from_promise (*this);
}
coro::suspend_never yield_value(T value) {
//fprintf (stderr, "%s yields %d\n", me, value);
current_value = value;
return coro::suspend_never{};
}
coro::suspend_always initial_suspend() { return {}; }
coro::suspend_always final_suspend() noexcept { return {}; }
void unhandled_exception() { /*std::terminate();*/ }
void return_void() {}
void set_peer (handle_type _p) { peer = _p; }
void set_me (const char *m) { me = m; }
T get_value () {return current_value;}
T current_value;
handle_type peer;
const char *me;
};
Loopy () : handle(0) {}
Loopy (handle_type _handle) : handle(_handle) {}
Loopy (const Loopy &) = delete;
Loopy (Loopy &&s) : handle(s.handle) { s.handle = nullptr; }
~Loopy() { if ( handle ) handle.destroy(); }
struct loopy_awaiter {
handle_type p;
bool await_ready () { return false; }
/* continue the peer. */
handle_type await_suspend (handle_type h) {
p = h.promise().peer;
return p;
}
T await_resume () { return p.promise().get_value (); }
};
};
Loopy<int>
pingpong (const char *id)
{
int v = 0;
Loopy<int>::loopy_awaiter aw{};
for (;;)
{
co_yield (v+1);
//std::this_thread::sleep_for(std::chrono::milliseconds(500));
if (v > 10'000'000)
break;
v = co_await aw;
//fprintf (stderr, "%s = %d\n", id, v);
}
//fprintf (stderr, "%s = %d\n", id, v);
}
int main ()
{
// identify for fun..
const char *ping_id = "ping";
const char *pong_id = "pong";
auto ping = pingpong (ping_id); // created suspended.
auto pong = pingpong (pong_id);
// point them at each other...
ping.handle.promise().set_peer (pong.handle);
pong.handle.promise().set_peer (ping.handle);
ping.handle.promise().set_me (ping_id);
pong.handle.promise().set_me (pong_id);
// and start them ...
ping.handle.resume ();
pong.handle.resume ();
}