본문 바로가기

프로그래밍/API

Linux에서의 Coroutine...

Windows는 Fiber라는 우수한 coroutine 함수가 존재한다.

그렇지만, Linux에서는 이러한 함수가 없다. 즉, 구현을 해야 한다는 말이다.
일부에서는 이러한 처리를 위해 setjmp()함수의 REG값을 조작하여 처리하는 방식을 사용하기도 한다.

여기에서는 setjmp() 계열의 함수를 사용하는 것이 아니라, Windows의 GetThreadContext(), SetThreadContext() 와 유사한 함수를 사용한 방법을 소개 하도록 하겠다.

** setjmp에 관련된 처리는 인터넷을 통해 어렵지 않게 찾을수 있을 것이다.

리눅스에는

#include <ucontext.h>

void makecontext(ucontext_t *ucp, void (*func)(), int argc...);

int
swapcontext(ucontext_t *restrict oucp, const ucontext_t *restrict ucp);

int
getcontext(ucontext_t *ucp);
int setcontext(const ucontext_t *ucp);

의 함수가 존재한다.

바로 이 함수들이, 이번 구현에 사용될 함수 들이다.
그럼 실제 사용 방법에 대해서 순서대로 알아 보도록 하자.

1. 현재 상태를 저장
getcontext( &co);

2. 구동에 필요한 CONTEXT 생성
  mstack = PAGE_ALIGN(STACK_SIZE + 1) + sizeof(ucontext_t);
  if (!(stack = (void *)calloc( 1, mstack))) return NULL;
  u = (ucontext_t *)
((uintptr_t)((ucontext_t *)((char *)stack + mstack)) & ~(sizeof(uintptr_t) - 1));
  if (getcontext( (--u)) < 0)
   ;
  else {
    stack_t *stk = &u->uc_stack;
    stk->ss_size = ((char *)u - (char *)(stk->ss_sp = stack));
    u->uc_link = NULL;
    // CALL_FUNC( void *PARAM)
    makecontext( u, (void (*)())CALL_FUNC, 1, PARAM);
  } return u;

3. 이렇게 만들어진 CONTEXT를 전환하자.
swapcontext( SELF_CTX, TARGET_CTX)

이렇게 하여, 리눅스에서도 coroutine을 구현해 보았다.

** 각 부분에 대한 설명은 전에 소개된 Windows에서 Coroutine을 구현하는 방법을 참고하기  바란다.

coroutine을 setjmp()방식와 방금 설명한 방식으로 구현을 해 보면, 실제 구동 속도는 setjmp() 방식이 빠르다는
것을 느끼게 된다. -- 그 방식의 차이는 직접 확인해 보길 바란다^^;

필자가, 굳이 위의 방식을 사용하는 이유는 CPU별 호환성 부분에서 setjmp() 처리 방식보다 유연하게 대처가
가능하다는 장점이 크게 작용했다.