From b6ddaa5f1c397b369d6523f87df831843a3efc9e Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Mon, 4 Jan 2010 22:07:26 +0100 Subject: [PATCH] sock_man_t API complete --- include/yaz/sock_man.h | 15 +++++- src/Makefile.am | 2 +- src/nanohttp.c | 52 ++++---------------- src/sock_man.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 148 insertions(+), 49 deletions(-) diff --git a/include/yaz/sock_man.h b/include/yaz/sock_man.h index 75bc841..0efc9b1 100644 --- a/include/yaz/sock_man.h +++ b/include/yaz/sock_man.h @@ -47,11 +47,24 @@ YAZ_EXPORT void yaz_sock_man_destroy(yaz_sock_man_t man); YAZ_EXPORT -yaz_sock_chan_t yaz_sock_chan_new(yaz_sock_man_t srv, int fd, void *data); +yaz_sock_chan_t yaz_sock_chan_new(yaz_sock_man_t srv, int fd, void *data, + unsigned mask); YAZ_EXPORT void yaz_sock_chan_destroy(yaz_sock_man_t srv, yaz_sock_chan_t p); +YAZ_EXPORT +void yaz_sock_chan_set_mask(yaz_sock_chan_t chan, unsigned mask); + +YAZ_EXPORT +void yaz_sock_chan_set_max_idle(yaz_sock_chan_t chan, int max_idle); + +YAZ_EXPORT +unsigned yaz_sock_get_mask(yaz_sock_chan_t chan); + +YAZ_EXPORT +void *yaz_sock_chan_get_data(yaz_sock_chan_t chan); + YAZ_END_CDECL #endif diff --git a/src/Makefile.am b/src/Makefile.am index 0eefdf0..96ad379 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -103,7 +103,7 @@ libyaz_la_SOURCES=version.c options.c log.c \ copy_types.c match_glob.c poll.c daemon.c \ iconv_encode_marc8.c iconv_encode_iso_8859_1.c iconv_encode_wchar.c \ iconv_decode_marc8.c iconv_decode_iso5426.c iconv_decode_danmarc.c sc.c \ - sock_man.c + sock_man.c nanohttp.c libyaz_la_LDFLAGS=-version-info $(YAZ_VERSION_INFO) diff --git a/src/nanohttp.c b/src/nanohttp.c index 3c0e945..259ffb4 100644 --- a/src/nanohttp.c +++ b/src/nanohttp.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include typedef struct yaz_nano_srv_s *yaz_nano_srv_t; @@ -29,7 +29,7 @@ struct yaz_nano_srv_s { COMSTACK *cs_listeners; size_t num_listeners; NMEM nmem; - struct yaz_poll_fd *fds; + yaz_sock_man_t sock_man; }; void yaz_nano_srv_destroy(yaz_nano_srv_t p) @@ -40,6 +40,7 @@ void yaz_nano_srv_destroy(yaz_nano_srv_t p) for (i = 0; i < p->num_listeners; i++) if (p->cs_listeners[i]) cs_close(p->cs_listeners[i]); + yaz_sock_man_destroy(p->sock_man); nmem_destroy(p->nmem); } } @@ -52,8 +53,6 @@ yaz_nano_srv_t yaz_nano_srv_create(const char **listeners_str) for (i = 0; listeners_str[i]; i++) ; p->nmem = nmem; - p->chan_list = 0; - p->free_list = 0; p->num_listeners = i; p->cs_listeners = nmem_malloc(nmem, p->num_listeners * sizeof(*p->cs_listeners)); @@ -82,6 +81,8 @@ yaz_nano_srv_t yaz_nano_srv_create(const char **listeners_str) p->cs_listeners[i] = l; /* success */ } } + p->sock_man = yaz_sock_man_new(); + /* check if all are OK */ for (i = 0; i < p->num_listeners; i++) if (!p->cs_listeners[i]) @@ -92,10 +93,11 @@ yaz_nano_srv_t yaz_nano_srv_create(const char **listeners_str) for (i = 0; i < p->num_listeners; i++) { - struct socket_chan *chan = - socket_chan_new(p, cs_fileno(p->cs_listeners[i]), - p->cs_listeners + i); - socket_chan_set_mask(chan, yaz_poll_read | yaz_poll_except); + yaz_sock_chan_t chan; + + chan = yaz_sock_chan_new(p->sock_man, cs_fileno(p->cs_listeners[i]), + p->cs_listeners + i, + yaz_poll_read | yaz_poll_except); } return p; } @@ -122,40 +124,6 @@ int yaz_nano_pkg_listener_id(yaz_nano_pkg_t pkg) yaz_nano_pkg_t yaz_nano_srv_get_pkg(yaz_nano_srv_t p) { - size_t i; - int ret; - int num_fds = 0; - struct yaz_poll_fd *fds; - struct socket_chan *chan = p->chan_list; - for (chan = p->chan_list; chan; chan = chan->next) - num_fds++; - fds = xmalloc(num_fds * sizeof(*fds)); - for (i = 0, chan = p->chan_list; chan; chan = chan->next) - { - fds[i].input_mask = chan->mask; - fds[i].fd = chan->fd; - fds[i].client_data = chan; - } - ret = yaz_poll(fds, num_fds, 0, 0); - if (ret == -1) - { - yaz_log(YLOG_WARN, "yaz_poll error"); - } - else if (ret == 0) - { - yaz_log(YLOG_LOG, "yaz_poll timeout"); - } - else - { - for (i = 0, chan = p->chan_list; chan; chan = chan->next) - { - if (fds[i].output_mask) - { - yaz_log(YLOG_LOG, "event on chan=%p", chan); - } - } - } - xfree(fds); return 0; } diff --git a/src/sock_man.c b/src/sock_man.c index 725a901..90e6810 100644 --- a/src/sock_man.c +++ b/src/sock_man.c @@ -3,14 +3,20 @@ #include #include #include +#include struct yaz_sock_man_s { yaz_sock_chan_t chan_list; yaz_sock_chan_t free_list; + yaz_sock_chan_t timeout_list; NMEM nmem; int epoll_handle; int maxevents; - yaz_sock_chan_t *events; + int event_no; + int event_ret; + int timeout; + int rescan; + struct epoll_event *events; }; struct yaz_sock_chan_s { @@ -18,7 +24,10 @@ struct yaz_sock_chan_s { yaz_sock_chan_t prev; int fd; unsigned mask; + unsigned output_mask; + int max_idle; void *data; + yaz_sock_man_t man; }; yaz_sock_man_t yaz_sock_man_new(void) @@ -28,8 +37,13 @@ yaz_sock_man_t yaz_sock_man_new(void) man->nmem = nmem; man->chan_list = 0; man->free_list = 0; + man->timeout_list = 0; man->epoll_handle = epoll_create(100); man->maxevents = 30; + man->event_no = 0; + man->event_ret = 0; + man->timeout = 0; + man->rescan = 0; man->events = nmem_malloc(nmem, man->maxevents * sizeof(*man->events)); if (man->epoll_handle == -1) { @@ -50,7 +64,25 @@ void yaz_sock_man_destroy(yaz_sock_man_t man) } } -yaz_sock_chan_t yaz_sock_chan_new(yaz_sock_man_t srv, int fd, void *data) +static void poll_ctl(int op, yaz_sock_chan_t p) +{ + struct epoll_event event; + + event.events = 0; + if (p->mask & yaz_poll_read) + event.events |= EPOLLIN; + if (p->mask & yaz_poll_write) + event.events |= EPOLLOUT; + if (p->mask & yaz_poll_except) + event.events |= EPOLLERR; + + event.data.ptr = p; + epoll_ctl(p->man->epoll_handle, op, p->fd, &event); + +} + +yaz_sock_chan_t yaz_sock_chan_new(yaz_sock_man_t srv, int fd, void *data, + unsigned mask) { yaz_sock_chan_t p; if (srv->free_list) @@ -69,9 +101,27 @@ yaz_sock_chan_t yaz_sock_chan_new(yaz_sock_man_t srv, int fd, void *data) p->fd = fd; p->mask = 0; p->data = data; + p->max_idle = 0; + p->man = srv; + + poll_ctl(EPOLL_CTL_ADD, p); return p; } +static void rescan_timeout(yaz_sock_man_t man) +{ + if (man->rescan) + { + int timeout = 0; + yaz_sock_chan_t p; + for (p = man->chan_list; p; p = p->next) + if (p->max_idle && (timeout == 0 || p->max_idle < timeout)) + timeout = p->max_idle; + man->timeout = timeout; + man->rescan = 0; + } +} + void yaz_sock_chan_destroy(yaz_sock_man_t srv, yaz_sock_chan_t p) { if (p->prev) @@ -84,20 +134,88 @@ void yaz_sock_chan_destroy(yaz_sock_man_t srv, yaz_sock_chan_t p) if (p->next) p->next->prev = p->prev; - + + poll_ctl(EPOLL_CTL_DEL, p); + p->next = srv->free_list; p->prev = 0; srv->free_list = p; + + srv->rescan = 1; } yaz_sock_chan_t yaz_sock_man_wait(yaz_sock_man_t man) { - return 0; + struct epoll_event *ev; + yaz_sock_chan_t chan = 0; + + if (man->timeout_list) + { /* possibly timeout events not returned */ + for (chan = man->timeout_list; chan; chan = chan->next) + if (chan->max_idle == man->timeout) + break; + if (chan) + { + man->timeout_list = chan->next; + chan->output_mask = yaz_poll_timeout; + return chan; + } + man->timeout_list = 0; /* no more timeout events */ + } + assert(man->timeout_list = 0); + assert(man->event_no <= man->event_ret); + if (man->event_no == man->event_ret) + { /* must wait again */ + rescan_timeout(man); + man->event_no = 0; + man->event_ret = epoll_wait(man->epoll_handle, man->events, + man->maxevents, man->timeout); + if (man->event_ret == 0) + { + /* timeout */ + for (chan = man->chan_list; chan; chan = chan->next) + if (chan->max_idle == man->timeout) + break; + assert(chan); /* there must be one chan in a timeout state */ + man->timeout_list = chan->next; + chan->output_mask = yaz_poll_timeout; + return chan; + } + else if (man->event_ret < 0) + { + /* error */ + return 0; + } + } + ev = man->events + man->event_no; + chan = ev->data.ptr; + chan->output_mask = 0; + if (ev->events & EPOLLIN) + chan->output_mask |= yaz_poll_read; + if (ev->events & EPOLLOUT) + chan->output_mask |= yaz_poll_write; + if (ev->events & EPOLLERR) + chan->output_mask |= yaz_poll_except; + man->event_no++; + return chan; } void yaz_sock_chan_set_mask(yaz_sock_chan_t chan, unsigned mask) { - chan->mask = mask; + if (chan->mask != mask) + { + chan->mask = mask; + poll_ctl(EPOLL_CTL_MOD, chan); + } +} + +void yaz_sock_chan_set_max_idle(yaz_sock_chan_t chan, int max_idle) +{ + if (chan->max_idle != max_idle) + { + chan->max_idle = max_idle; + chan->man->rescan = 1; + } } unsigned yaz_sock_get_mask(yaz_sock_chan_t chan) -- 1.7.10.4