Libevent R3: Working with an event loop: Difference between revisions

From 탱이의 잡동사니
Jump to navigation Jump to search
No edit summary
No edit summary
Line 140: Line 140:
<references />
<references />


[[catetory:libevent]]
[[category:libevent]]

Revision as of 16:34, 28 January 2015

Overview

원문은 이곳<ref>http://www.wangafu.net/~nickm/libevent-book/Ref3_eventloop.html</ref>에서 볼 수 있다.

Running the loop

event_base 에 이벤트를 등록시켰다면(등록과 관련해서는 다음 장을 참고하도록 하자), Libevent 통해서 등록한 이벤트의 대기/알람을 할 수 있다.

  • Interface

<source lang=c>

  1. define EVLOOP_ONCE 0x01
  2. define EVLOOP_NONBLOCK 0x02
  3. define EVLOOP_NO_EXIT_ON_EMPTY 0x04

int event_base_loop(struct event_base *base, int flags); </source> 기본적으로 event_base_loop() 는 event_base에 더이상 등록된 이벤트가 없을 때까지 동작한다. event_base_loop() 는 루프를 돌면서 event_base 에 등록된 이벤트 중, 현재 triggered 된 이벤트가 있는지를 계속해서 확인한다.(예를 들면 read 이벤트가 등록된 file descriptor 가 read 준비가 되었을 때, 혹은 timeout 으로 등록된 이벤트가 expire 되었을 때). triggered 된 이벤트가 있다면, 해당 이벤트를 "active" 상태로 표시하고 해당 이벤트를 실행한다.

event_base_loop() 의 동작방식은 인자값 flag 를 통해서 변경할 수 있다.

EVLOOP_ONCE를 설정하면 event_base 에 등록된 이벤트들이 "active" 될 때까지 대기를 한다. 이후 active 된 이벤트를 실행한다. 이 일을 반복하면서 등록된 이벤트가 하나도 없을때까지 계속한다. 등록된 이벤트가 더이상 없을 때 Loop 를 중단하고 리턴한다.

EVLOOP_NONBLOCK 으로 설정하게 되면, event_base 에 등록된 이벤트가 "trigger" 될 때까지 대기하다가, trigger 된 이벤트에 등록된 Callback 함수를 실행시킨다.

일반적으로 evnet_base 에 등록된 이벤트가 하나도 없을 경우, event_base_loop() 는 종료된다. 그런데 EVLOOP_NO_EXIT_ON_EMPTY 를 설정하면 이를 변경할 수 있다. 만약 다른 스레드로부터 이벤트를 등록 받는 경우, 등록된 이벤트가 하나도 없더라도 계속해서 루프를 돌아야 하는데, 이런경우에 EVLOOP_NO_EXIT_ON_EMPTY 를 설정하게 되면 event_base_loopbreak(), event_base_loopexit() 를 호출하거나 에러가 발생하지 않는 이상, 계속해서 루프를 돌게 된다.

루프가 종료되면 event_base_loop() 는 정상 종료일 경우 0, 에러가 발생했을 경우 -1을 리턴한다. 그리고 등록된 이벤트가 없어서 종료된 경우, 1을 리턴한다.

이해를 돕기 위해서 다음의 의사코드를 보도록 하자.

  • Pseudocode

<source lang=c> while(any events are registered with the loop,

       or EVLOOP_NO_EXIT_ON_EMPTY was set)

{

   if(EVLOOP_NONBLOCK was set, or any events are already active)
       If any registered events have triggered, mark them active.
   else
       Wait until at least one event has triggered, and mark it active.
   
   for(p = 0; p < n_priorities; ++p)
   {
       if(any event with priority of p is active)
       {
           Run all active events with priority of p.
           break;  /* Do not run any events of a less important priority */
       }
   }
   
   if(EVLOOP_ONCE was wet or EVLOOP_NONBLOCK was set)
   {
       break;
   }

} </source>

혹은 간편하게 다음과 같이 호출할 수도 있다.

  • Interface

<source lang=c> int event_base_dispatch(struct event_base *base) </source> event_base_dispatch() 함수는 event_base_loop() 를 아무 옵션없이 실행한 것과 같다. 더이상 등록된 이벤트가 없을 때까지, event_base_loopbreak() 혹은 event_base_loopexit() 가 호출될 때 까지 계속해서 루프를 돈다.

Stopping the loop

현재 동작중인 이벤트 루프를 중지시키고 싶다면 다음과 같은 함수를 사용할 수 있다. <source lang=c> int event_base_loopexit(struct event_base *base, const struct timeval *tv); int event_base_loopbreak(struct event_base *base); </source> event_base_loopexit() 함수는 인자로 넘겨진 시간 뒤에 종료하고 싶을 때 사용한다. 만약 tv 인자값으로 NULL 이 오게되면 딜레이 없이 바로 종료된다. 만약 현재 active 로 표시된 이벤트 들이 있다면 현재 표시된 active 이벤트 등리 모두 실행된 다음에 종료된다.

event_base_loopbreak() 함수는 루프를 즉시 종료하는 함수이다. event_base_loopexit() 와 다른 점은, 현재 active로 표시된 이벤트들이 있다고 하더라도, process 중인 이벤트 중료 후 바로 종료를 한다는 점이다.

그리고 등록된 이벤트가 하나도 없는 상태에서도 다르게 동작한다. event_base_loopexit() 는 다음번 루프 확인 스케쥴에서 종료가 되지만, event_base_loopbreak() 는 스케쥴링 없이 바로 종료가 된다.

두 함수 모두 성공시 0, 실패시 -1을 리턴한다.

  • Example: Shut down immediately

<source lang=c>

  1. include <event2/event.h>

/* Here's a callback function that calls loopbreak */ void cb(int sock, short what, void *arg) {

   struct event_base *base = arg;
   event_base_loopbreak(base);

}

void main_loop(struct event_base *base, evutil_socket_t watchdog_fd) {

   struct event *watchdog_event;
   
   /* Construct a new event to trigger whenever there are any bytes to
    * read from a watchdog socket. When that happens, we'll call the
    * cb function, which will make the lop exit immediately without
    * running any other active events at all.
    */
    watchdog_event = event_new(base, watchdog_fd, EV_READ, cb, base);
    
    event_add(watchdog_event, NULL);
    
    event_base_dispatch(base);
}

</source>

  • Example: Run an event loop for 10 seconds, then exit.

<source lang=c>

  1. include <event2/event.h>

void run_base_with_ticks(struct event_base *base) {

   struct timeval ten_sec;
   
   ten_sec.tv_sec = 10;
   ten_sec.tv_usec = 0;
   
   /* Now we run the event_base for a series of 10-second intervals, printing
    * "Tick" after each. For a much better way to implement a 10-second
    * timer, see the section below about persistent timer evetns. */
   while(1) {
       /* This scehdules an exit ten secods from now. */
       event_base_loopexit(base, &ten_sec);
        
       event_base_dispatch(base);
       puts("Tick");
   }

} </source>

event_base_dispatch() 혹은 event_base_loop() 가 종료되었을 때, event_base_loopxexit() 혹은 event_base_break() 중 어느 것에 의해 종료되었는지 알고 싶을 때가 있다. 이런 경우, 다음의 함수를 사용하면 된다.

  • Interface

<source lang=c> int event_base_got_exit(struct event_base *base); int event_base_got_break(struct event_base *base); </source> 이 둘 함수 모두 함수의 이름대로 event_base_loopexit() 혹은 event_base_break() 에 의해 종료 되었을 경우, true 을 리턴한다. 반대의 경우 false 를 리턴한다. 결과 값은 다음번 이벤트 루프를 실행하게 되면 초기화된다.

Re-checking for events

References

<references />