Skip to content

Instantly share code, notes, and snippets.

@zeldin
Created November 25, 2022 19:06
Show Gist options
  • Save zeldin/a381b786dbee1ad51504417c50ef4bbd to your computer and use it in GitHub Desktop.
Save zeldin/a381b786dbee1ad51504417c50ef4bbd to your computer and use it in GitHub Desktop.
// Copyright Oliver Kowalke 2016.
// 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)
// libcontext adaptation by Marcus Comstedt 2022
#include <cstdlib>
#include <iostream>
#include <memory>
#include <libcontext.h>
namespace ctx {
namespace detail {
template< typename T, typename U = T >
T exchange( T & t, U && nv) {
T ov = std::move( t);
t = std::forward< U >( nv);
return ov;
}
template< typename Fn, typename ... Args >
typename std::enable_if<
! std::is_member_pointer< typename std::decay< Fn >::type >::value,
typename std::result_of< Fn &&( Args && ... ) >::type
>::type
invoke( Fn && fn, Args && ... args) {
return std::forward< Fn >( fn)( std::forward< Args >( args) ... );
}
template< typename Ctx, typename Fn >
struct fiber_record {
typename std::decay< Fn >::type fn_;
fcontext_t chain;
fiber_record( Fn && fn) noexcept :
fn_( std::forward< Fn >( fn) ) {
}
fcontext_t run( fcontext_t fctx) {
Ctx c = invoke( fn_, Ctx{ fctx } );
return exchange( c.fctx_, nullptr);
}
};
template< typename Rec >
void fiber_entry( intptr_t arg ) noexcept {
Rec * rec = reinterpret_cast< Rec * >( arg );
fcontext_t chain;
intptr_t r = jump_fcontext(&chain, rec->chain,
reinterpret_cast<intptr_t>(&chain));
chain = rec->run(*reinterpret_cast<const fcontext_t *>(r));
jump_fcontext(&chain, chain, reinterpret_cast<intptr_t>(&chain));
std::cerr << "Resumed finished fiber!" << std::endl;
}
template< typename Ctx, typename Fn >
fcontext_t create_fiber(Fn && fn) {
fiber_record<Ctx, Fn> * record =
new fiber_record<Ctx, Fn>{std::forward<Fn>(fn)};
size_t stackSize = 2000000;
void* stack = malloc( stackSize );
void* sp = (void*) ( ( ( (ptrdiff_t) stack ) + stackSize - 0xf ) & ( ~0x0f ) );
stackSize -= ( (size_t) stack + stackSize - (size_t) sp );
const fcontext_t fctx =
make_fcontext( sp, stackSize,
&fiber_entry< fiber_record<Ctx, Fn> >);
intptr_t r = jump_fcontext(&record->chain, fctx,
reinterpret_cast<intptr_t>(record));
return *reinterpret_cast<const fcontext_t *>(r);
}
}
class fiber {
private:
template< typename Ctx, typename StackAlloc, typename Fn >
friend class detail::fiber_record;
fcontext_t fctx_{ nullptr };
fiber(fcontext_t fctx) noexcept :
fctx_{ fctx } {
}
public:
template< typename Fn >
fiber( Fn && fn) :
fiber{ detail::create_fiber<fiber, Fn>(std::forward< Fn >( fn )) } { }
fiber( fiber && other) noexcept {
swap( other);
}
fiber & operator=( fiber && other) noexcept {
if ( this != & other ) {
fiber tmp = std::move( other);
swap( tmp);
}
return * this;
}
fiber() noexcept = delete;
fiber( fiber const& other) noexcept = delete;
fiber & operator=( fiber const& other) noexcept = delete;
fiber resume() && {
fcontext_t chain;
intptr_t r = jump_fcontext(&chain, detail::exchange( fctx_, nullptr),
reinterpret_cast<intptr_t>(&chain));
return { *reinterpret_cast<const fcontext_t *>(r) };
}
void swap( fiber & other) noexcept {
std::swap( fctx_, other.fctx_);
}
};
}
int main() {
int a;
ctx::fiber f{
[&a](ctx::fiber && f){
a=0;
int b=1;
for(;;){
f = std::move( f).resume();
int next=a+b;
a=b;
b=next;
}
return std::move( f);
}};
for ( int j = 0; j < 10; ++j) {
f = std::move( f).resume();
std::cout << a << " ";
}
std::cout << std::endl;
std::cout << "main: done" << std::endl;
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment