diff options
| author | Přemysl Janouch <p.janouch@gmail.com> | 2014-09-19 23:27:25 +0200 | 
|---|---|---|
| committer | Přemysl Janouch <p.janouch@gmail.com> | 2014-09-19 23:44:00 +0200 | 
| commit | 457eff90e3920d27d9d3806d2f44fa40de7af7dc (patch) | |
| tree | ed6567ad07c4d87d276cff6113c8743b3968eef8 | |
| parent | 6f1bc52711b12b670b3b4bbd5d52a1c029603612 (diff) | |
| download | ponymap-457eff90e3920d27d9d3806d2f44fa40de7af7dc.tar.gz ponymap-457eff90e3920d27d9d3806d2f44fa40de7af7dc.tar.xz ponymap-457eff90e3920d27d9d3806d2f44fa40de7af7dc.zip | |
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.
| -rw-r--r-- | ponymap.c | 128 | ||||
| -rw-r--r-- | utils.c | 326 | 
2 files changed, 232 insertions, 222 deletions
| @@ -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))  		; @@ -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 <sys/epoll.h> -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 | 
