Skip to content

Commit

Permalink
Fix/re-enable coroutines!
Browse files Browse the repository at this point in the history
  • Loading branch information
terranpro committed Jan 14, 2016
1 parent 71692eb commit 3393eeb
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 56 deletions.
35 changes: 13 additions & 22 deletions async-task/Await.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,27 @@

namespace as {

void await_schedule(Executor& context, Task task)
// TODO: you can do this!! fighting brian~~* :D
template<class Ex, class Func, class... Args>
TaskFuture< decltype( std::declval<Func>()(std::declval<Args>()...) ) >
await(Ex& ex, Func&& func, Args&&... args)
{
context.Schedule( std::move(task) );
typedef decltype( std::declval<Func>()(std::declval<Args>()...) ) result_type;

while( !task.IsFinished() ) {

#ifdef AS_USE_COROUTINE_TASKS
if ( detail::this_task_stack.size() ) {
detail::this_task_stack[0]->Yield();
}
#endif // AS_USE_COROUTINE_TASKS
auto bound = std::bind( std::forward<Func>(func), std::forward<Args>(args)... );
// invocation<decltype(bound)> inv( std::move(bound) );

if ( context.IsCurrent() )
context.Iteration();
}
auto r = std::make_shared<AsyncResult<result_type>>();

}
auto c = build_chain( ex, std::move(bound), async_result_invocation<result_type>(r) );

template<class Func, class... Args>
decltype( std::declval<Func>()(std::declval<Args>()...) )
await(Executor& context, Func&& func, Args&&... args)
{
auto bound = std::bind( std::forward<Func>(func), std::forward<Args>(args)... );
invocation<decltype(bound)> inv( std::move(bound) );
typedef CoroutineTaskImpl< decltype(c) > coro_task_type;

CoroutineTaskImpl< decltype(inv) > ct{ std::move(inv) };
coro_task_type ct{ std::move(c) };

Task task{ true, std::move(ct) };
ex.schedule( std::move(ct) );

await_schedule( context, std::move(task) );
return{ std::move(r) };
}

template<class Func, class... Args>
Expand Down
120 changes: 102 additions & 18 deletions async-task/CoroutineTaskImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,22 @@
#include <boost/config.hpp>
#include <boost/context/detail/config.hpp>

#include <iostream>

#include "TaskImpl.hpp"

namespace as {

class CoroutineTask
{
public:
virtual TaskStatus Invoke() = 0;
virtual void Yield() = 0;
};

namespace detail {

// static thread_local std::vector< TaskImplBase * > this_task_stack{};
static thread_local std::vector< CoroutineTask * > this_task_stack{};

template< std::size_t Max, std::size_t Default, std::size_t Min >
class simple_stack_allocator
Expand Down Expand Up @@ -56,7 +65,7 @@ class simple_stack_allocator
BOOST_ASSERT( minimum_stacksize() <= size );
BOOST_ASSERT( maximum_stacksize() >= size );

void *limit = static_cast< char * >( vp) - size;
void *limit = static_cast< char * >( vp ) - size;
std::free( limit );
}
};
Expand Down Expand Up @@ -189,7 +198,7 @@ struct BoostContext
} // namespace v2

template<class TaskFunc>
class CoroutineTaskImpl
class CoroutineTaskPriv
{
typedef detail::simple_stack_allocator<
MAX_STACK_SIZE,
Expand All @@ -207,21 +216,28 @@ class CoroutineTaskImpl
private:
void deinitialize_context()
{
assert( stack );

alloc.deallocate( stack, stack_allocator::default_stacksize() );
// assert( stack );
if ( stack ) {
std::cout << "Deallocating coroutine stack...!\n";
alloc.deallocate( stack, stack_allocator::default_stacksize() );
}
}

static void entry_point( intptr_t p )
{
auto self = reinterpret_cast< CoroutineTaskImpl * >(p);
auto self = reinterpret_cast< CoroutineTaskPriv * >(p);

self->running = true;

std::cout << "self = " << self << "\n";
std::cout << "RUNNING = TRUE!\n";

self->on_entry();

self->running = false;

std::cout << "RUNNING = FALSE!\n";

self->bctxt.Init( self->stack, self->stack_size );
self->bctxt.Exit();
}
Expand All @@ -232,42 +248,68 @@ class CoroutineTaskImpl
}

public:
CoroutineTaskImpl()
CoroutineTaskPriv()
: alloc()
, stack_size( stack_allocator::default_stacksize() )
, stack( alloc.allocate( stack_size ) )
, bctxt( &CoroutineTaskImpl::entry_point,
, bctxt( &CoroutineTaskPriv::entry_point,
reinterpret_cast<intptr_t>(this) )
, running(false)
{
bctxt.Init( stack, stack_size );
}

CoroutineTaskImpl(typename invocation<TaskFunc>::func_type func)
CoroutineTaskPriv(typename invocation<TaskFunc>::func_type func)
: alloc()
, stack_size( stack_allocator::default_stacksize() )
, stack( alloc.allocate( stack_size ) )
, bctxt( &CoroutineTaskImpl::entry_point,
, bctxt( &CoroutineTaskPriv::entry_point,
reinterpret_cast<intptr_t>(this) )
, taskfunc( std::move(func) )
, running(false)
{
bctxt.Init( stack, stack_size );
}

~CoroutineTaskImpl()
~CoroutineTaskPriv()
{
deinitialize_context();
std::cout << "THIS = " << this << "\n";
std::cout << __PRETTY_FUNCTION__ << "\n";
if ( !running )
deinitialize_context();
}

CoroutineTaskPriv(CoroutineTaskPriv&& other)
: alloc( std::move(other.alloc) )
, stack_size( other.stack_size )
, stack( other.stack )
, bctxt( other.bctxt )
, taskfunc( std::move(other.taskfunc) )
, running( other.running )
{
if ( this == &other )
return;

std::cout << "THIS = " << this << "\n";

other.stack = nullptr;
other.running = false;
}

public:
TaskStatus Invoke()
{
// detail::this_task_stack.insert( std::begin(detail::this_task_stack), this );
// std::cout << "THIS = " << this << "\n";

// detail::this_task_stack.insert( std::begin(detail::this_task_stack), this );

bctxt.Invoke();

// detail::this_task_stack.erase( std::begin(detail::this_task_stack) );
// detail::this_task_stack.erase( std::begin(detail::this_task_stack) );

// std::cout << "THIS = " << this << "\n";

// std::cout << "RETURN: " << running << "\n";

return running ? TaskStatus::Repeat : TaskStatus::Finished;
}
Expand All @@ -281,14 +323,56 @@ class CoroutineTaskImpl
{}
};

template<class TaskFunc>
class CoroutineTaskImpl
: public CoroutineTask
{
std::unique_ptr< CoroutineTaskPriv<TaskFunc> > priv;

public:
CoroutineTaskImpl()
: priv( new CoroutineTaskPriv<TaskFunc>() )
{}

CoroutineTaskImpl(typename invocation<TaskFunc>::func_type func)
: priv( new CoroutineTaskPriv<TaskFunc>(std::move(func)) )
{}

public:
TaskStatus Invoke()
{
assert( priv );

detail::this_task_stack.insert( std::begin(detail::this_task_stack), this );

auto r = priv->Invoke();

detail::this_task_stack.erase( std::begin(detail::this_task_stack) );

return r;
}

void Yield()
{
assert( priv );

priv->Yield();
}

void Cancel()
{}
};

namespace this_task {

inline void yield()
{
// if ( detail::this_task_stack.size() == 0 )
// return;
// std::cout << "YIELD!\n";

if ( detail::this_task_stack.size() == 0 )
return;

// detail::this_task_stack[0]->Yield();
detail::this_task_stack[0]->Yield();
}

} // namespace as::ThisTask
Expand Down
18 changes: 9 additions & 9 deletions async-task/TaskImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,10 +315,10 @@ struct chain_invocation<Ex, First, Invokers...>

invocation<First> inv;
base_type next;
Ex ex;
Ex& ex;

template<class F, class... Is>
explicit chain_invocation(Ex ex, F&& i1, Is&&... invks)
explicit chain_invocation(Ex& ex, F&& i1, Is&&... invks)
: inv( std::forward<F>(i1) )
, next( ex, std::forward<Is>(invks)... )
, ex( ex )
Expand Down Expand Up @@ -349,8 +349,8 @@ struct chain_invocation<Ex, bound_invocation<FirstEx,First>, Invokers...>
executor_type ex;

template<class F, class... Is>
explicit chain_invocation(Ex ex, bound_invocation<FirstEx,F> i1, Is&&... invks)
: ex( std::move(i1.ex) )
explicit chain_invocation(Ex& ex, bound_invocation<FirstEx,F> i1, Is&&... invks)
: ex( i1.ex )
, inv( std::move(i1.inv) )
, next( ex, std::forward<Is>(invks)... )
{}
Expand Down Expand Up @@ -380,11 +380,11 @@ template<class Ex, class First>
struct chain_invocation<Ex, First>
{
invocation<First> inv;
Ex ex;
Ex& ex;

explicit chain_invocation(Ex ex, First&& f)
explicit chain_invocation(Ex& ex, First&& f)
: inv(std::move(f))
, ex(std::move(ex))
, ex(ex)
{}

template<class... Args>
Expand All @@ -408,9 +408,9 @@ struct chain_invocation<Ex, bound_invocation<FirstEx,First>>
invocation<First> inv;
executor_type ex;

explicit chain_invocation(Ex ex, bound_invocation<FirstEx,First> i1)
explicit chain_invocation(Ex& ex, bound_invocation<FirstEx,First> i1)
: inv(std::move(i1.inv))
, ex(std::move(i1.ex))
, ex(i1.ex)
{}

template<class... Args>
Expand Down
2 changes: 1 addition & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ CreateTest( post_performance_test.cpp )
CreateTest( thread_work_performance_test.cpp )
CreateTest( chain_test.cpp )
CreateTest( traits_test.cpp )
# CreateTest( await_test.cpp )
CreateTest( await_test.cpp )
CreateTest( sync_test.cpp )
3 changes: 2 additions & 1 deletion test/async_performance_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,8 @@ void async_cancel_test()
} );

auto fut = as::async( ex, []() {
std::cout << "This Should not Print!\n";
std::cout << "This Should NOT Print!\n";
assert( false );
} );

auto fut2 = as::async( ex, []() {
Expand Down
22 changes: 17 additions & 5 deletions test/await_test.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#define AS_USE_COROUTINE_TASKS

#include "Await.hpp"
#include "ThreadExecutor.hpp"

Expand All @@ -6,15 +8,16 @@ void coro_test()
// #ifdef AS_USE_COROUTINE_TASKS

auto& ctxt = as::ThreadExecutor::GetDefault();
as::ThreadExecutor other_ctxt;

auto mega_work_r =
as::async( ctxt, [&]() {
as::await( other_ctxt, [&]() {
int x = 50;
std::cout << "Doing mega work\n";
while( x-- ) {
std::cout << ".";
std::cout << "A";
std::cout.flush();
std::this_thread::sleep_for( std::chrono::milliseconds(1) );
std::this_thread::sleep_for( std::chrono::milliseconds(100) );
as::this_task::yield();
}
} );
Expand All @@ -24,12 +27,21 @@ void coro_test()

as::this_task::yield();

as::await( []() {
auto fut = as::await( other_ctxt, []() {
std::cout << "Start sleep...\n";
std::this_thread::sleep_for( std::chrono::seconds(2) );

for ( auto i = 1; i <= 20; ++i ) {
std::cout << "B";
std::cout.flush();
std::this_thread::sleep_for( std::chrono::milliseconds(100) );
as::this_task::yield();
}

std::cout << "Done!\n";
} );

fut.get();

std::cout << "Awaiting DONE...!\n";
} );

Expand Down
Loading

0 comments on commit 3393eeb

Please sign in to comment.