My Shiny Weblog!

programming, photography and lifestyle

Събитиино програмиране с Libevent

От няколко месеца, работейки директно с POSIX интерфейса се натъкнах на някой добре познати стари проблеми:

  • Имаме големи ограничения какво може да се пише в signal handler.
  • Асинхронната работа с ядрото изисква сложна обработка на сигнали.
  • Спазвайки стандарта (select(2)) работата с множество файлови дескриптори има сложност O(n).
  • Нишките са реализирани по различни начини на различните операционни системи.

Използвайки libevent можем да си спестим всички тези главоболия. Поне аз успях да го направя. Тъй като примерите придружаващи библиотеката хич не ми харесаха, реших да напиша няколко собствени.

Работа със сигнали, обработване на SIGTERM:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <event.h>
#include <stdio.h>
#include <signal.h>

void handler()
{
   printf("SIGTERM received\n");
}

int main()
{
   struct event ev_signal;

   event_init();
   event_set(&ev_signal, SIGTERM, EV_SIGNAL, handler, NULL);
   event_add(&ev_signal, NULL);
   event_dispatch();
}

  • В handler() може да има всичко, не само async-signal safe неща.
  • Библиотеката се грижи за приспиването и събуждането на процеса.

Работа с часовници, извикване на функция през определено време:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <event.h>
#include <stdio.h>

#define TIMEOUT 5

void handler(int fd, short event, void *arg)
{
   struct event *ev = arg;
   struct timeval tv;
   tv.tv_sec = TIMEOUT;
   event_add(ev, &tv);

   printf("Alarm\n");
}

int main()
{
   struct event ev_time;
   struct timeval tv;

   event_init();
   evtimer_set(&ev_time, handler, &ev_time);
   tv.tv_sec = TIMEOUT;
   event_add(&ev_time, &tv);
   event_dispatch();
}

  • Функцията може да си задава различен интервал за всяко следващо извикване.
  • Можем да добавяме и махаме събития и callback функции навсякъде в програмата.

И най-интересната част – работа с файлови дескриптори:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <event.h>
#include <stdio.h>

#define BUFSIZE 128

void handler(int fd, short event, void *arg)
{
   int ret;
   char buf[BUFSIZE];
   ret = read(fd, buf, BUFSIZE);
   printf("%d bytes read\n", ret);
}

int main()
{
   int fd;
   struct event ev_fd;

   event_init();
   event_set(&ev_fd, 0, EV_READ | EV_PERSIST, handler, &ev_fd);
   event_add(&ev_fd, NULL);
   event_dispatch();
}

  • Работата с множество файлови дескриптори има сложност O(1) при работа на някои операционни системи – FreeBSD kqueue(), Linux epoll()
  • Handler функциите могат да се задават за постоянно или за едно извикване

UPDATE: Оказа се, че поради някакви причини последната програма не работи на Mac OS X с libevent 1.4.2. Може би бъг в библиотеката?