From 457eff90e3920d27d9d3806d2f44fa40de7af7dc Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Fri, 19 Sep 2014 23:27:25 +0200 Subject: Rework the poller It's about time we stopped fucking ourselves in the butt. The scanning should be much faster now. Thanks to libuv for inspiration. --- ponymap.c | 128 ++++++++++++------------ utils.c | 326 ++++++++++++++++++++++++++++++++------------------------------ 2 files changed, 232 insertions(+), 222 deletions(-) diff --git a/ponymap.c b/ponymap.c index f620deb..c1a19a3 100644 --- a/ponymap.c +++ b/ponymap.c @@ -225,6 +225,9 @@ struct unit struct str read_buffer; ///< Unprocessed input struct str write_buffer; ///< Output yet to be sent out + struct poller_timer timeout_event; ///< Timeout event + struct poller_fd fd_event; ///< FD event + bool aborted; ///< Scan has been aborted bool success; ///< Service has been found struct str_vector info; ///< Info resulting from the scan @@ -270,6 +273,8 @@ struct transport struct indicator { + struct poller_timer timer; ///< The animation timer + unsigned position; ///< The current animation character const char *frames; ///< All the characters size_t frames_len; ///< The number of characters @@ -278,17 +283,7 @@ struct indicator char *status; ///< The status text }; -static void -indicator_init (struct indicator *self) -{ - static const char frames[] = "-\\|/"; - self->position = 0; - self->frames = frames; - self->frames_len = sizeof frames - 1; - - self->status = NULL; - self->shown = false; -} +static void indicator_init (struct indicator *self, struct poller *poller); static void indicator_free (struct indicator *self) @@ -362,7 +357,7 @@ app_context_init (struct app_context *self) str_map_init (&self->svc_list); str_map_init (&self->services); - indicator_init (&self->indicator); + indicator_init (&self->indicator, &self->poller); // Ignoring the generator so far poller_init (&self->poller); @@ -400,17 +395,18 @@ app_context_free (struct app_context *self) // --- Progress indicator ------------------------------------------------------ -// TODO: rework the poller so that we don't have to use a reference to -// `struct app_context' to make changes to the animation timer. // TODO: make it so that the indicator is hidden while printing messages to // the same terminal -> wrapper for log_message_stdio(). -static void indicator_set_timer (struct app_context *ctx); +static void +indicator_set_timer (struct indicator *self) +{ + poller_timer_set (&self->timer, INDICATOR_INTERVAL); +} static void -on_indicator_tick (struct app_context *ctx) +on_indicator_tick (struct indicator *self) { - struct indicator *self = &ctx->indicator; if (!self->shown) return; @@ -420,20 +416,28 @@ on_indicator_tick (struct app_context *ctx) tputs (cursor_left, 1, putchar); putchar (self->frames[self->position]); fflush (stdout); - indicator_set_timer (ctx); + indicator_set_timer (self); } static void -indicator_set_timer (struct app_context *ctx) +indicator_init (struct indicator *self, struct poller *poller) { - poller_timers_add (&ctx->poller.timers, - (poller_timer_fn) on_indicator_tick, ctx, INDICATOR_INTERVAL); + poller_timer_init (&self->timer, poller); + self->timer.dispatcher = (poller_timer_fn) on_indicator_tick; + self->timer.user_data = self; + + static const char frames[] = "-\\|/"; + self->position = 0; + self->frames = frames; + self->frames_len = sizeof frames - 1; + + self->status = NULL; + self->shown = false; } static void -indicator_show (struct app_context *ctx) +indicator_show (struct indicator *self) { - struct indicator *self = &ctx->indicator; if (self->shown || !g_terminal.initialized || !g_terminal.stdout_is_tty) return; @@ -441,15 +445,14 @@ indicator_show (struct app_context *ctx) printf ("%s... %c", self->status, self->frames[self->position]); tputs (clr_eol, 1, putchar); fflush (stdout); - indicator_set_timer (ctx); self->shown = true; + indicator_set_timer (self); } static void -indicator_hide (struct app_context *ctx) +indicator_hide (struct indicator *self) { - struct indicator *self = &ctx->indicator; if (!self->shown) return; @@ -457,24 +460,20 @@ indicator_hide (struct app_context *ctx) tputs (clr_eol, 1, putchar); fflush (stdout); - ssize_t i = poller_timers_find - (&ctx->poller.timers, (poller_timer_fn) on_indicator_tick, ctx); - if (i != -1) - poller_timers_remove_at_index (&ctx->poller.timers, i); + poller_timer_reset (&self->timer); } static void -indicator_set_status (struct app_context *ctx, char *status) +indicator_set_status (struct indicator *self, char *status) { - struct indicator *self = &ctx->indicator; bool refresh = self->shown; - indicator_hide (ctx); + indicator_hide (self); free (self->status); self->status = status; if (refresh) - indicator_show (ctx); + indicator_show (self); } // --- Scan units -------------------------------------------------------------- @@ -513,13 +512,8 @@ unit_abort (struct unit *u) if (u->service->on_aborted) u->service->on_aborted (u->service_data, u); - ssize_t i; - struct app_context *ctx = u->target->ctx; - struct poller *poller = &ctx->poller; - if ((i = poller_find_by_fd (poller, u->socket_fd)) != -1) - poller_remove_at_index (poller, i); - while ((i = poller_timers_find_by_data (&poller->timers, u)) != -1) - poller_timers_remove_at_index (&poller->timers, i); + poller_timer_reset (&u->timeout_event); + poller_fd_reset (&u->fd_event); u->transport->cleanup (u); u->service->scan_free (u->service_data); @@ -533,7 +527,7 @@ unit_abort (struct unit *u) LIST_UNLINK (u->target->running_units, u); // We might have made it possible to launch new units - while (generator_step (ctx)) + while (generator_step (u->target->ctx)) ; if (u->success) @@ -554,8 +548,7 @@ unit_update_poller (struct unit *u, const struct pollfd *pfd) hard_assert (new_events != 0); if (!pfd || pfd->events != new_events) - poller_set (&u->target->ctx->poller, u->socket_fd, new_events, - (poller_dispatcher_fn) on_unit_ready, u); + poller_fd_set (&u->fd_event, new_events); } static void @@ -608,9 +601,8 @@ end: static void unit_start_scan (struct unit *u) { - struct app_context *ctx = u->target->ctx; - poller_timers_add (&ctx->poller.timers, - (poller_timer_fn) unit_abort, u, ctx->scan_timeout); + poller_timer_set (&u->timeout_event, u->target->ctx->scan_timeout); + u->fd_event.dispatcher = (poller_fd_fn) on_unit_ready; unit_update_poller (u, NULL); } @@ -618,12 +610,8 @@ static void on_unit_connected (const struct pollfd *pfd, struct unit *u) { (void) pfd; - struct app_context *ctx = u->target->ctx; - ssize_t i = poller_timers_find (&ctx->poller.timers, - (poller_timer_fn) unit_abort, u); - hard_assert (i != -1); - poller_timers_remove_at_index (&ctx->poller.timers, i); + poller_timer_reset (&u->timeout_event); int error; socklen_t error_len = sizeof error; @@ -666,6 +654,14 @@ unit_new (struct target *target, int socket_fd, uint16_t port, return NULL; } + poller_timer_init (&u->timeout_event, &target->ctx->poller); + u->timeout_event.dispatcher = (poller_timer_fn) unit_abort; + u->timeout_event.user_data = u; + + poller_fd_init (&u->fd_event, &target->ctx->poller, socket_fd); + u->fd_event.dispatcher = (poller_fd_fn) on_unit_connected; + u->fd_event.user_data = u; + u->service_data = service->scan_init (u); LIST_PREPEND (target->running_units, u); return u; @@ -718,11 +714,10 @@ unit_make (struct target *target, uint32_t ip, uint16_t port, unit_start_scan (u); else { - poller_timers_add (&ctx->poller.timers, - (poller_timer_fn) unit_abort, u, ctx->connect_timeout); - poller_set (&ctx->poller, u->socket_fd, POLLOUT, - (poller_dispatcher_fn) on_unit_connected, u); + poller_timer_set (&u->timeout_event, ctx->connect_timeout); + poller_fd_set (&u->fd_event, POLLOUT); } + return UNIT_MAKE_OK; } @@ -739,7 +734,7 @@ static void initiate_quit (struct app_context *ctx) { ctx->quitting = true; - indicator_set_status (ctx, xstrdup ("Quitting")); + indicator_set_status (&ctx->indicator, xstrdup ("Quitting")); // Abort all running units struct target *t_iter, *t_next; @@ -1292,7 +1287,7 @@ target_dump_json (struct target *self, struct target_dump_data *data) static void target_dump_terminal (struct target *self, struct target_dump_data *data) { - indicator_hide (self->ctx); + indicator_hide (&self->ctx->indicator); struct str tmp; str_init (&tmp); @@ -1333,7 +1328,7 @@ target_dump_terminal (struct target *self, struct target_dump_data *data) node_delete (root); putchar ('\n'); - indicator_show (self->ctx); + indicator_show (&self->ctx->indicator); } static int @@ -1389,10 +1384,10 @@ target_update_indicator (struct target *self) char *status = xstrdup_printf ("Scanning %s", buf); struct indicator *indicator = &self->ctx->indicator; if (!indicator->status || strcmp (status, indicator->status)) - indicator_set_status (self->ctx, status); + indicator_set_status (&self->ctx->indicator, status); else free (status); - indicator_show (self->ctx); + indicator_show (&self->ctx->indicator); } static struct target * @@ -1424,7 +1419,7 @@ target_unref (struct target *self) struct app_context *ctx = self->ctx; LIST_UNLINK_WITH_TAIL (ctx->running_targets, ctx->running_tail, self); if (!ctx->running_targets) - indicator_hide (ctx); + indicator_hide (&ctx->indicator); else if (!ctx->quitting && ctx->running_targets) target_update_indicator (ctx->running_targets); @@ -1922,8 +1917,11 @@ main (int argc, char *argv[]) exit (EXIT_FAILURE); } - poller_set (&ctx.poller, g_signal_pipe[0], POLLIN, - (poller_dispatcher_fn) on_signal_pipe_readable, &ctx); + struct poller_fd signal_event; + poller_fd_init (&signal_event, &ctx.poller, g_signal_pipe[0]); + signal_event.dispatcher = (poller_fd_fn) on_signal_pipe_readable; + signal_event.user_data = &ctx; + poller_fd_set (&signal_event, POLLIN); if (!load_plugins (&ctx)) exit (EXIT_FAILURE); @@ -1961,6 +1959,8 @@ main (int argc, char *argv[]) merge_ip_ranges (&ctx); // Initate the scan: generate as many units as possible + // FIXME: this appears to be quite slow: either make it run faster, + // or limit the number of units spawned at a time generator_init (&ctx); while (generator_step (&ctx)) ; diff --git a/utils.c b/utils.c index f7dd1b6..209af08 100644 --- a/utils.c +++ b/utils.c @@ -840,42 +840,48 @@ xclose (int fd) break; } -// --- Polling ----------------------------------------------------------------- +// --- Event loop -------------------------------------------------------------- // Basically the poor man's GMainLoop/libev/libuv. It might make some sense // to instead use those tested and proven libraries but we don't need much // and it's interesting to implement. -// At the moment the FD's are stored in an unsorted array. This is not ideal -// complexity-wise but I don't think I have much of a choice with poll(), -// and neither with epoll for that matter. -// -// unsorted array sorted array -// search O(n) O(log n) [O(log log n)] -// insert by fd O(n) O(n) -// delete by fd O(n) O(n) -// -// Insertion in the unsorted array can be reduced to O(1) if I maintain a -// bitmap of present FD's but that's still not a huge win. -// -// I don't expect this to be much of an issue, as there are typically not going -// to be that many FD's to watch, and the linear approach is cache-friendly. +// Actually it mustn't be totally shitty as scanning exercises it quite a bit. +// We sacrifice some memory to allow for O(1) and O(log n) operations. -typedef void (*poller_dispatcher_fn) (const struct pollfd *, void *); +typedef void (*poller_fd_fn) (const struct pollfd *, void *); typedef void (*poller_timer_fn) (void *); #define POLLER_MIN_ALLOC 16 -struct poller_timer_info +struct poller_timer { + struct poller_timers *timers; ///< The timers part of our poller + ssize_t index; ///< Where we are in the array, or -1 + int64_t when; ///< When is the timer to expire + poller_timer_fn dispatcher; ///< Event dispatcher void *user_data; ///< User data }; +struct poller_fd +{ + struct poller *poller; ///< Our poller + ssize_t index; ///< Where we are in the array, or -1 + + int fd; ///< Our file descriptor + short events; ///< The poll() events we registered for + + poller_fd_fn dispatcher; ///< Event dispatcher + void *user_data; ///< User data +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + struct poller_timers { - struct poller_timer_info *info; ///< Min-heap of timers + struct poller_timer **heap; ///< Min-heap of timers size_t len; ///< Number of scheduled timers size_t alloc; ///< Number of timers allocated }; @@ -885,13 +891,13 @@ poller_timers_init (struct poller_timers *self) { self->alloc = POLLER_MIN_ALLOC; self->len = 0; - self->info = xmalloc (self->alloc * sizeof *self->info); + self->heap = xmalloc (self->alloc * sizeof *self->heap); } static void poller_timers_free (struct poller_timers *self) { - free (self->info); + free (self->heap); } static int64_t @@ -911,28 +917,30 @@ poller_timers_get_current_time (void) static void poller_timers_heapify_down (struct poller_timers *self, size_t index) { - typedef struct poller_timer_info info_t; - info_t *end = self->info + self->len; + typedef struct poller_timer *timer_t; + timer_t *end = self->heap + self->len; while (true) { - info_t *parent = self->info + index; - info_t *left = self->info + 2 * index + 1; - info_t *right = self->info + 2 * index + 2; + timer_t *parent = self->heap + index; + timer_t *left = self->heap + 2 * index + 1; + timer_t *right = self->heap + 2 * index + 2; - info_t *largest = parent; - if (left < end && left->when > largest->when) + timer_t *largest = parent; + if (left < end && (*left) ->when > (*largest)->when) largest = left; - if (right < end && right->when > largest->when) + if (right < end && (*right)->when > (*largest)->when) largest = right; if (parent == largest) break; - info_t tmp = *parent; + timer_t tmp = *parent; *parent = *largest; *largest = tmp; - index = largest - self->info; + (*parent) ->index = parent - self->heap; + (*largest)->index = largest - self->heap; + index = largest - self->heap; } } @@ -940,10 +948,12 @@ static void poller_timers_remove_at_index (struct poller_timers *self, size_t index) { hard_assert (index < self->len); + self->heap[index]->index = -1; if (index == --self->len) return; - self->info[index] = self->info[self->len]; + self->heap[index] = self->heap[self->len]; + self->heap[index]->index = index; poller_timers_heapify_down (self, index); } @@ -951,11 +961,11 @@ static void poller_timers_dispatch (struct poller_timers *self) { int64_t now = poller_timers_get_current_time (); - while (self->len && self->info->when <= now) + while (self->len && self->heap[0]->when <= now) { - struct poller_timer_info info = *self->info; + struct poller_timer *timer = self->heap[0]; poller_timers_remove_at_index (self, 0); - info.dispatcher (info.user_data); + timer->dispatcher (timer->user_data); } } @@ -965,49 +975,35 @@ poller_timers_heapify_up (struct poller_timers *self, size_t index) while (index != 0) { size_t parent = (index - 1) / 2; - if (self->info[parent].when <= self->info[index].when) + if (self->heap[parent]->when <= self->heap[index]->when) break; - struct poller_timer_info tmp = self->info[parent]; - self->info[parent] = self->info[index]; - self->info[index] = tmp; + struct poller_timer *tmp = self->heap[parent]; + self->heap[parent] = self->heap[index]; + self->heap[index] = tmp; + self->heap[parent]->index = parent; + self->heap[index] ->index = index; index = parent; } } -static ssize_t -poller_timers_find (struct poller_timers *self, - poller_timer_fn dispatcher, void *data) -{ - // NOTE: there may be duplicates. - for (size_t i = 0; i < self->len; i++) - if (self->info[i].dispatcher == dispatcher - && self->info[i].user_data == data) - return i; - return -1; -} - -static ssize_t -poller_timers_find_by_data (struct poller_timers *self, void *data) -{ - for (size_t i = 0; i < self->len; i++) - if (self->info[i].user_data == data) - return i; - return -1; -} - static void -poller_timers_add (struct poller_timers *self, - poller_timer_fn dispatcher, void *data, int timeout_ms) +poller_timers_set (struct poller_timers *self, struct poller_timer *timer) { - if (self->len == self->alloc) - self->info = xreallocarray (self->info, - self->alloc <<= 1, sizeof *self->info); + hard_assert (timer->timers == self); + if (timer->index != -1) + { + poller_timers_heapify_down (self, timer->index); + poller_timers_heapify_up (self, timer->index); + return; + } - self->info[self->len] = (struct poller_timer_info) { - .when = poller_timers_get_current_time () + timeout_ms, - .dispatcher = dispatcher, .user_data = data }; + if (self->len == self->alloc) + self->heap = xreallocarray (self->heap, + self->alloc <<= 1, sizeof *self->heap); + self->heap[self->len] = timer; + timer->index = self->len; poller_timers_heapify_up (self, self->len++); } @@ -1017,7 +1013,7 @@ poller_timers_get_poll_timeout (struct poller_timers *self) if (!self->len) return -1; - int64_t timeout = self->info->when - poller_timers_get_current_time (); + int64_t timeout = self->heap[0]->when - poller_timers_get_current_time (); if (timeout <= 0) return 0; if (timeout > INT_MAX) @@ -1025,24 +1021,15 @@ poller_timers_get_poll_timeout (struct poller_timers *self) return timeout; } -#ifdef __linux__ - -// I don't really need this, I've basically implemented this just because I can. +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +#ifdef __linux__ #include -struct poller_info -{ - int fd; ///< Our file descriptor - short events; ///< The poll() events we registered for - poller_dispatcher_fn dispatcher; ///< Event dispatcher - void *user_data; ///< User data -}; - struct poller { int epoll_fd; ///< The epoll FD - struct poller_info **info; ///< Information associated with each FD + struct poller_fd **fds; ///< Information associated with each FD struct epoll_event *revents; ///< Output array for epoll_wait() size_t len; ///< Number of polled descriptors size_t alloc; ///< Number of entries allocated @@ -1065,7 +1052,7 @@ poller_init (struct poller *self) self->len = 0; self->alloc = POLLER_MIN_ALLOC; - self->info = xcalloc (self->alloc, sizeof *self->info); + self->fds = xcalloc (self->alloc, sizeof *self->fds); self->revents = xcalloc (self->alloc, sizeof *self->revents); poller_timers_init (&self->timers); @@ -1079,28 +1066,18 @@ poller_free (struct poller *self) { for (size_t i = 0; i < self->len; i++) { - struct poller_info *info = self->info[i]; + struct poller_fd *fd = self->fds[i]; hard_assert (epoll_ctl (self->epoll_fd, - EPOLL_CTL_DEL, info->fd, (void *) "") != -1); - free (info); + EPOLL_CTL_DEL, fd->fd, (void *) "") != -1); } poller_timers_free (&self->timers); xclose (self->epoll_fd); - free (self->info); + free (self->fds); free (self->revents); } -static ssize_t -poller_find_by_fd (struct poller *self, int fd) -{ - for (size_t i = 0; i < self->len; i++) - if (self->info[i]->fd == fd) - return i; - return -1; -} - static void poller_ensure_space (struct poller *self) { @@ -1112,8 +1089,8 @@ poller_ensure_space (struct poller *self) self->revents = xreallocarray (self->revents, sizeof *self->revents, self->alloc); - self->info = xreallocarray - (self->info, sizeof *self->info, self->alloc); + self->fds = xreallocarray + (self->fds, sizeof *self->fds, self->alloc); } static short @@ -1141,41 +1118,33 @@ poller_poll_to_epoll_events (short events) } static void -poller_set (struct poller *self, int fd, short events, - poller_dispatcher_fn dispatcher, void *data) +poller_set (struct poller *self, struct poller_fd *fd) { - ssize_t index = poller_find_by_fd (self, fd); + hard_assert (fd->poller == self); bool modifying = true; - if (index == -1) + if (fd->index == -1) { poller_ensure_space (self); - self->info[index = self->len++] = xcalloc (1, sizeof **self->info); + self->fds[fd->index = self->len++] = fd; modifying = false; } - struct poller_info *info = self->info[index]; - info->fd = fd; - info->events = events; - info->dispatcher = dispatcher; - info->user_data = data; - struct epoll_event event; - event.events = poller_poll_to_epoll_events (events); - event.data.ptr = info; + event.events = poller_poll_to_epoll_events (fd->events); + event.data.ptr = fd; hard_assert (epoll_ctl (self->epoll_fd, - modifying ? EPOLL_CTL_MOD : EPOLL_CTL_ADD, fd, &event) != -1); + modifying ? EPOLL_CTL_MOD : EPOLL_CTL_ADD, fd->fd, &event) != -1); } static void -poller_remove_from_dispatch (struct poller *self, - const struct poller_info *info) +poller_remove_from_dispatch (struct poller *self, const struct poller_fd *fd) { if (!self->dispatch_total) return; int i; for (i = self->dispatch_next; i < self->dispatch_total; i++) - if (self->revents[i].data.ptr == info) + if (self->revents[i].data.ptr == fd) break; if (i == self->dispatch_total) return; @@ -1188,15 +1157,18 @@ static void poller_remove_at_index (struct poller *self, size_t index) { hard_assert (index < self->len); - struct poller_info *info = self->info[index]; + struct poller_fd *fd = self->fds[index]; + fd->index = -1; - poller_remove_from_dispatch (self, info); + poller_remove_from_dispatch (self, fd); hard_assert (epoll_ctl (self->epoll_fd, - EPOLL_CTL_DEL, info->fd, (void *) "") != -1); + EPOLL_CTL_DEL, fd->fd, (void *) "") != -1); - free (info); if (index != --self->len) - self->info[index] = self->info[self->len]; + { + self->fds[index] = self->fds[self->len]; + self->fds[index]->index = index; + } } static void @@ -1222,15 +1194,15 @@ poller_run (struct poller *self) while (self->dispatch_next < self->dispatch_total) { struct epoll_event *revents = self->revents + self->dispatch_next; - struct poller_info *info = revents->data.ptr; + struct poller_fd *fd = revents->data.ptr; struct pollfd pfd; - pfd.fd = info->fd; + pfd.fd = fd->fd; pfd.revents = poller_epoll_to_poll_events (revents->events); - pfd.events = info->events; + pfd.events = fd->events; self->dispatch_next++; - info->dispatcher (&pfd, info->user_data); + fd->dispatcher (&pfd, fd->user_data); } self->dispatch_next = 0; @@ -1239,16 +1211,10 @@ poller_run (struct poller *self) #else // !__linux__ -struct poller_info -{ - poller_dispatcher_fn dispatcher; ///< Event dispatcher - void *user_data; ///< User data -}; - struct poller { struct pollfd *fds; ///< Polled descriptors - struct poller_info *fds_info; ///< Additional information for each FD + struct poller_fd **fds_data; ///< Additional information for each FD size_t len; ///< Number of polled descriptors size_t alloc; ///< Number of entries allocated @@ -1262,7 +1228,7 @@ poller_init (struct poller *self) self->alloc = POLLER_MIN_ALLOC; self->len = 0; self->fds = xcalloc (self->alloc, sizeof *self->fds); - self->fds_info = xcalloc (self->alloc, sizeof *self->fds_info); + self->fds_data = xcalloc (self->alloc, sizeof *self->fds_data); poller_timers_init (&self->timers); self->dispatch_next = -1; } @@ -1271,19 +1237,10 @@ static void poller_free (struct poller *self) { free (self->fds); - free (self->fds_info); + free (self->fds_data); poller_timers_free (&self->timers); } -static ssize_t -poller_find_by_fd (struct poller *self, int fd) -{ - for (size_t i = 0; i < self->len; i++) - if (self->fds[i].fd == fd) - return i; - return -1; -} - static void poller_ensure_space (struct poller *self) { @@ -1292,33 +1249,33 @@ poller_ensure_space (struct poller *self) self->alloc <<= 1; self->fds = xreallocarray (self->fds, sizeof *self->fds, self->alloc); - self->fds_info = xreallocarray - (self->fds_info, sizeof *self->fds_info, self->alloc); + self->fds_data = xreallocarray + (self->fds_data, sizeof *self->fds_data, self->alloc); } static void -poller_set (struct poller *self, int fd, short events, - poller_dispatcher_fn dispatcher, void *data) +poller_set (struct poller *self, struct poller_fd *fd) { - ssize_t index = poller_find_by_fd (self, fd); - if (index == -1) + hard_assert (fd->poller == self); + if (fd->index == -1) { poller_ensure_space (self); - index = self->len++; + self->fds_data[fd->index = self->len++] = fd; } - struct pollfd *new_entry = self->fds + index; + struct pollfd *new_entry = self->fds + fd->index; memset (new_entry, 0, sizeof *new_entry); - new_entry->fd = fd; - new_entry->events = events; - - self->fds_info[index] = (struct poller_info) { dispatcher, data }; + new_entry->fd = fd->fd; + new_entry->events = fd->events; } static void poller_remove_at_index (struct poller *self, size_t index) { hard_assert (index < self->len); + struct poller_fd *fd = self->fds_data[index]; + fd->index = -1; + if (index == --self->len) return; @@ -1327,14 +1284,18 @@ poller_remove_at_index (struct poller *self, size_t index) { memmove (self->fds + index, self->fds + index + 1, (self->len - index) * sizeof *self->fds); - memmove (self->fds_info + index, self->fds_info + index + 1, - (self->len - index) * sizeof *self->fds_info); + memmove (self->fds_data + index, self->fds_data + index + 1, + (self->len - index) * sizeof *self->fds_data); + for (size_t i = index; i < self->len; i++) + self->fds_data[i]->index = i; + self->dispatch_next--; } else { - self->fds[index] = self->fds[self->len]; - self->fds_info[index] = self->fds_info[self->len]; + self->fds[index] = self->fds [self->len]; + self->fds_data[index] = self->fds_data[self->len]; + self->fds_data[index]->index = index; } } @@ -1358,10 +1319,10 @@ poller_run (struct poller *self) for (int i = 0; i < (int) self->len; ) { struct pollfd pfd = self->fds[i]; - struct poller_info *info = self->fds_info + i; + struct poller_fd *fd = self->fds_data[i]; self->dispatch_next = ++i; if (pfd.revents) - info->dispatcher (&pfd, info->user_data); + fd->dispatcher (&pfd, fd->user_data); i = self->dispatch_next; } @@ -1370,6 +1331,55 @@ poller_run (struct poller *self) #endif // !__linux__ +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +static void +poller_timer_init(struct poller_timer *self, struct poller *poller) +{ + memset (self, 0, sizeof *self); + self->timers = &poller->timers; + self->index = -1; +} + +static void +poller_timer_set(struct poller_timer *self, int timeout_ms) +{ + self->when = poller_timers_get_current_time () + timeout_ms; + poller_timers_set (self->timers, self); +} + +static void +poller_timer_reset(struct poller_timer *self) +{ + if (self->index != -1) + poller_timers_remove_at_index (self->timers, self->index); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +static void +poller_fd_init(struct poller_fd *self, struct poller *poller, int fd) +{ + memset (self, 0, sizeof *self); + self->poller = poller; + self->index = -1; + self->fd = fd; +} + +static void +poller_fd_set(struct poller_fd *self, short events) +{ + self->events = events; + poller_set (self->poller, self); +} + +static void +poller_fd_reset(struct poller_fd *self) +{ + if (self->index != -1) + poller_remove_at_index (self->poller, self->index); +} + // --- Utilities --------------------------------------------------------------- static void -- cgit v1.2.3-70-g09d2