I'm playing around with boost::context
a bit, making a little task scheduler. A minimal proof of concept.
After being able to create tasks and have them run according to the scheduler, it occurred to me to add the clone( )
functionality, using setjmp( )
. However, when I try to run the cloned task, I get a nice 'SIGSEGV` error:
#include <boost/context/continuation.hpp>
#include <csetjmp>
#include <iostream>
namespace ctx = boost::context;
enum CoroState {
Finish = 0,
Ready
};
using EntryPoint = void (*)( );
struct Coro {
~Coro( ) {
if( next != this ) {
prev->next = next;
next->prev = prev;
}
}
Coro( EntryPoint ep ) :
state( CoroState::Ready ),
entryPoint( ep ),
clone( false ),
next( this ),
prev( this ) {
}
Coro( EntryPoint ep, Coro *curr ) :
state( CoroState::Ready ),
entryPoint( ep ),
clone( false )
{
next = curr;
prev = curr->prev;
curr->prev = this;
prev->next = this;
}
Coro( Coro *origin ) :
Coro( origin->entryPoint, origin )
{
clone = true;
}
CoroState state;
EntryPoint entryPoint;
bool clone;
Coro *next;
Coro *prev;
std::string name;
jmp_buf jmpBuf;
ctx::continuation continuation;
};
static Coro *ActiveCoro = nullptr;
static ctx::continuation wrapper( ctx::continuation &&sink ) {
ActiveCoro->continuation = std::move( sink );
if( ActiveCoro->clone ) {
std::longjmp( ActiveCoro->jmpBuf, 1 );
} else {
ActiveCoro->entryPoint( );
}
ActiveCoro->state = CoroState::Finish;
return std::move( ActiveCoro->continuation );
}
static void yield( ) {
ActiveCoro->continuation = ActiveCoro->continuation.resume( );
}
static Coro &createCoro( EntryPoint ep ) {
Coro *result;
if( !ActiveCoro ) {
ActiveCoro = new Coro( ep );
result = ActiveCoro;
} else {
result = new Coro( ep, ActiveCoro );
}
return *result;
}
bool clone( ) {
auto newCoro = new Coro( ActiveCoro );
return setjmp( newCoro->jmpBuf );
}
void runLoop( ) {
while( ActiveCoro ) {
if( ActiveCoro->continuation ) {
ActiveCoro->continuation = ActiveCoro->continuation.resume( );
} else {
ActiveCoro->continuation = ctx::callcc( wrapper );
}
if( ActiveCoro->state == CoroState::Finish ) {
if( ActiveCoro->next == ActiveCoro ) {
delete ActiveCoro;
break;
} else {
auto toDelete = ActiveCoro;
ActiveCoro = ActiveCoro->next;
toDelete->prev->next = toDelete->next;
toDelete->next->prev = toDelete->prev;
delete toDelete;
}
}
ActiveCoro = ActiveCoro->next;
}
}
static void Worker( ) {
for( int idx = 0; idx < 5; ++idx ) {
std::cout << ActiveCoro->name << ", idx " << idx << std::endl;
yield( );
}
std::cout << ActiveCoro->name << " terminado.\n";
}
static void Master( ) {
std::cout << "Entrando en Master.\n";
createCoro( Worker ).name = "Worker 1";
createCoro( Worker ).name = "Worker 2";
createCoro( Worker ).name = "Worker 3";
std::cout << "Master ha creado los hijos. Esperando.\n";
if( clone( ) ) {
std::cout << "Clon de Master terminado\n";
} else {
std::cout << "Master terminado.\n";
}
}
int main( ) {
std::ios::sync_with_stdio( false );
createCoro( Master ).name = "Master";
runLoop( );
std::cout << std::endl;
return 0;
}
The problem is unique to the clone( )
functionality. If I comment this part:
/*
if( clone( ) ) {
std::cout << "Clon de Master terminado\n";
} else {
std::cout << "Master terminado.\n";
}
*/
everything works fine again.
- Is it possible to get the
clone( )
functionality in this way ? - How to it ?
Aucun commentaire:
Enregistrer un commentaire