🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: pl.comp.os.linux.programowanie
2 messages
2 total messages Started by Borneq Wed, 20 Aug 2014 22:14
Przełączanie kontekstu
#72705
Author: Borneq
Date: Wed, 20 Aug 2014 22:14
10 lines
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
#72706
Author: Borneq
Date: Thu, 21 Aug 2014 18:48
147 lines
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