X-Git-Url: http://git.madism.org/?a=blobdiff_plain;f=common%2Fserver.c;h=6053408ca7030e916e49ab09d9d16a30b7e87eac;hb=a195f9a648c32226b3b2ec4bb44a69a44ff5e51d;hp=78af625e31432882b7b4cec0e25a19f5a6fd6917;hpb=d25cf39d7cb4d2df2d7e2fa307c1c8f14bb018cc;p=apps%2Fpfixtools.git diff --git a/common/server.c b/common/server.c index 78af625..6053408 100644 --- a/common/server.c +++ b/common/server.c @@ -35,40 +35,67 @@ #include "server.h" #include "epoll.h" +#include "common.h" -static server_t *listeners[1024]; -static int listener_count = 0; - +static PA(server_t) listeners = ARRAY_INIT; +static PA(server_t) server_pool = ARRAY_INIT; static server_t* server_new(void) { server_t* server = p_new(server_t, 1); - server->fd = -1; + server->fd = -1; + server->fd2 = -1; return server; } +static void server_wipe(server_t *server) +{ + server->listener = server->event = false; + if (server->fd > 0) { + epoll_modify(server->fd, 0, NULL); + close(server->fd); + server->fd = -1; + } + if (server->fd2 > 0) { + close(server->fd2); + server->fd2 = -1; + } + if (server->data && server->clear_data) { + server->clear_data(&server->data); + } +} + static void server_delete(server_t **server) { if (*server) { - if ((*server)->fd >= 0) { - close((*server)->fd); - } - if ((*server)->data && (*server)->clear_data) { - (*server)->clear_data(&(*server)->data); - } buffer_wipe(&(*server)->ibuf); buffer_wipe(&(*server)->obuf); + server_wipe(*server); p_delete(server); } } -static void server_shutdown(void) +static server_t* server_acquire(void) { - for (int i = 0 ; i < listener_count ; ++i) { - server_delete(&listeners[i]); + if (server_pool.len != 0) { + return array_elt(server_pool, --server_pool.len); + } else { + return server_new(); } } +static void server_release(server_t *server) +{ + server_wipe(server); + array_add(server_pool, server); +} + +static void server_shutdown(void) +{ + array_deep_wipe(listeners, server_delete); + array_deep_wipe(server_pool, server_delete); +} + module_exit(server_shutdown); int start_server(int port, start_listener_t starter, delete_client_t deleter) @@ -95,13 +122,13 @@ int start_server(int port, start_listener_t starter, delete_client_t deleter) } } - tmp = server_new(); + tmp = server_acquire(); tmp->fd = sock; tmp->listener = true; tmp->data = data; tmp->clear_data = deleter; epoll_register(sock, EPOLLIN, tmp); - listeners[listener_count++] = tmp; + array_add(listeners, tmp); return 0; } @@ -126,7 +153,7 @@ static int start_client(server_t *server, start_client_t starter, } } - tmp = server_new(); + tmp = server_acquire(); tmp->fd = sock; tmp->data = data; tmp->clear_data = deleter; @@ -134,8 +161,59 @@ static int start_client(server_t *server, start_client_t starter, return 0; } +event_t event_register(int fd, void *data) +{ + int fds[2]; + if (fd == -1) { + if (pipe(fds) != 0) { + UNIXERR("pipe"); + return NULL; + } + if (setnonblock(fds[0]) != 0) { + close(fds[0]); + close(fds[1]); + return NULL; + } + } + + server_t *tmp = server_acquire(); + tmp->event = true; + tmp->fd = fd == -1 ? fds[0] : fd; + tmp->fd2 = fd == -1 ? fds[1] : -1; + tmp->data = data; + epoll_register(fds[0], EPOLLIN, tmp); + return tmp; +} + +bool event_fire(event_t event) +{ + static const char *data = ""; + if (event->fd2 == -1) { + return false; + } + return write(event->fd2, data, 1) == 0; +} + +static bool event_cancel(event_t event) +{ + char buff[32]; + while (true) { + ssize_t res = read(event->fd, buff, 32); + if (res == -1 && errno != EAGAIN && errno != EINTR) { + UNIXERR("read"); + return false; + } else if (res == -1 && errno == EINTR) { + continue; + } else if (res != 32) { + return true; + } + } +} + int server_loop(start_client_t starter, delete_client_t deleter, - run_client_t runner, refresh_t refresh, void* config) { + run_client_t runner, event_handler_t handler, + refresh_t refresh, void* config) +{ info("entering processing loop"); while (!sigint) { struct epoll_event evts[1024]; @@ -166,18 +244,29 @@ int server_loop(start_client_t starter, delete_client_t deleter, if (d->listener) { (void)start_client(d, starter, deleter); continue; + } else if (d->event) { + if (!event_cancel(d)) { + server_release(d); + continue; + } + if (handler) { + if (!handler(d, config)) { + server_release(d); + } + } + continue; } if (evts[n].events & EPOLLIN) { if (runner(d, config) < 0) { - server_delete(&d); + server_release(d); continue; } } if ((evts[n].events & EPOLLOUT) && d->obuf.len) { if (buffer_write(&d->obuf, d->fd) < 0) { - server_delete(&d); + server_release(d); continue; } if (!d->obuf.len) {