Thread View: pl.comp.os.linux.programowanie
2 messages
2 total messages
Started by Borneq
Wed, 20 Aug 2014 22:14
Przełączanie kontekstu
Author: Borneq
Date: Wed, 20 Aug 2014 22:14
Date: Wed, 20 Aug 2014 22:14
10 lines
1320 bytes
1320 bytes
Jak system obsługuje coroutiny? W Windows jest coś takiego jak Fiber, obsługa np. https://github.com/erikfrey/coroutine/blob/master/boost/coroutine/detail/context_windows.hpp natomiast w Linuxie https://github.com/erikfrey/coroutine/blob/master/boost/coroutine/detail/context_linux.hpp to kod w assemblerze GCC. Czy są jakieś funkcje do tego? widzę że są http://www.unix.com/man-page/linux/3/swapcontext/ http://en.wikipedia.org/wiki/Setcontext czy konteksty mają własne stosy, które mogą niezależnie rosnąć?
Re: Przełączanie kontekstu
Author: Borneq
Date: Thu, 21 Aug 2014 18:48
Date: Thu, 21 Aug 2014 18:48
147 lines
3962 bytes
3962 bytes
W dniu 2014-08-21 o 00:14, Borneq pisze:
> czy konteksty mają własne stosy, które mogą niezależnie rosnąć?
Czy jest coś takiego jak zwalnianie kontekstu? Nigdzie nie znalazłem
czegoś takiego jak FreeContext. Czy też zwalniany jest gdy główna
funkcja się kończy?
Ale należy pamiętać, że w kontekście przydzielamy bajty dla stosu, które
w destruktorze zwalniam.
Chcę napisać klasę obsługująca konteksty, na razie mam:
#include <ucontext.h>
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
struct fiber_t
{
ucontext_t fib;
jmp_buf jmp;
};
struct fiber_ctx_t
{
void(* fnc)(void*);
void* ctx;
jmp_buf* cur;
ucontext_t* prv;
};
class Coroutine{
private:
fiber_t fib;
public:
virtual void execute() =0;
void yield(Coroutine *next=NULL);
void attach();
Coroutine(long stackSize);
virtual ~Coroutine();
};
static void fiber_start_fnc(void* p)
{
fiber_ctx_t* ctx = (fiber_ctx_t*)p;
void* uctx = ctx->ctx;
if (_setjmp(*ctx->cur) == 0)
{
ucontext_t tmp;
swapcontext(&tmp, ctx->prv);
}
Coroutine *coroutine = (Coroutine *)uctx;
coroutine->execute();
}
inline void create_fiber(fiber_t* fib, void* uctx)
{
getcontext(&fib->fib);
size_t const stack_size = 64*1024;
fib->fib.uc_stack.ss_sp = (::malloc)(stack_size);
fib->fib.uc_stack.ss_size = stack_size;
fib->fib.uc_link = 0;
ucontext_t tmp;
fiber_ctx_t ctx = {NULL, uctx, &fib->jmp, &tmp};
makecontext(&fib->fib, (void(*)())fiber_start_fnc, 1, &ctx);
swapcontext(&tmp, &fib->fib);
}
inline void switch_to_fiber(fiber_t& fiber, fiber_t& prevfiber)
{
if (_setjmp(prevfiber.jmp) == 0)
_longjmp(fiber.jmp, 1);
}
__thread fiber_t fibmain;
__thread bool initialized_fibmain = false;
void Coroutine::yield(Coroutine *next)
{
if (next==NULL)
switch_to_fiber(fibmain, fib);
else
switch_to_fiber(next->fib, fib);
}
void Coroutine::attach()
{
switch_to_fiber(fib, fibmain);
}
Coroutine::Coroutine(long stackSize)
{
if (!initialized_fibmain)
{
create_fiber(&fibmain, NULL);
initialized_fibmain = true;
}
create_fiber(&fib, this);
}
Coroutine::~Coroutine()
{
free(fib.fib.uc_stack.ss_sp);
}
Coroutine *A,*B;
class CoroutineA : public Coroutine{
public:
CoroutineA(): Coroutine(8*1024){};
void execute()
{
printf("CoroutineA\n");
for (int i=0; i<100; i++)
{
printf("i=%d\n",i);
yield(B);
}
printf("after yield CoroutineA\n");
}
};
class CoroutineB : public Coroutine{
public:
CoroutineB(): Coroutine(8*1024){};
void execute()
{
printf("CoroutineB\n");
for (int i=0; i<100; i++)
{
printf("i=%d\n",i);
yield(A);
}
printf("after yield CoroutineB\n");
}
};
int main()
{
A = new CoroutineA();
B = new CoroutineB();
A->attach();
delete A;
delete B;
return 0;
}
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads