dimanche 29 août 2021

Is it possible to implement a 'clone( )' function using boost::context?

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