#include <yaz/comstack.h>
#include <yaz/nmem.h>
#include <yaz/log.h>
-#include <yaz/poll.h>
+#include <yaz/sock_man.h>
#include <assert.h>
typedef struct yaz_nano_srv_s *yaz_nano_srv_t;
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)
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);
}
}
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));
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])
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;
}
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;
}
#include <yaz/nmem.h>
#include <assert.h>
#include <sys/epoll.h>
+#include <unistd.h>
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 {
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)
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)
{
}
}
-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)
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)
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)