From 74965b0f66f1907346df49c1eebb07169d26129d Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Tue, 28 Oct 2014 02:39:37 +0100 Subject: Rewrite to use libev libuv is too immature so far and I'm not in the mood to try and link it statically via some horrible hack (no CMake support). Also libev is much closer to my understanding of event loops. The messaging model stays for when/if I want to return to libuv. --- utils.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) (limited to 'utils.c') diff --git a/utils.c b/utils.c index df16559..23b95a4 100644 --- a/utils.c +++ b/utils.c @@ -104,6 +104,24 @@ xrealloc (void *o, size_t n) (link)->next->prev = (link)->prev; \ BLOCK_END +#define LIST_APPEND_WITH_TAIL(head, tail, link) \ + BLOCK_START \ + (link)->prev = (tail); \ + (link)->next = NULL; \ + if ((link)->prev) \ + (link)->prev->next = (link); \ + else \ + (head) = (link); \ + (tail) = (link); \ + BLOCK_END + +#define LIST_UNLINK_WITH_TAIL(head, tail, link) \ + BLOCK_START \ + if ((tail) == (link)) \ + (tail) = (link)->prev; \ + LIST_UNLINK ((head), (link)); \ + BLOCK_END + // --- Dynamically allocated strings ------------------------------------------- // Basically a string builder to abstract away manual memory management. @@ -236,11 +254,14 @@ static bool set_blocking (int fd, bool blocking) { int flags = fcntl (fd, F_GETFL); + bool prev = !(flags & O_NONBLOCK); if (blocking) flags &= ~O_NONBLOCK; else flags |= O_NONBLOCK; + + (void) fcntl (fd, F_SETFL, flags); return prev; } @@ -284,6 +305,76 @@ xstrtoul (unsigned long *out, const char *s, int base) return errno == 0 && !*end && end != s; } +// --- libuv-style write adaptor ----------------------------------------------- + +// Makes it possible to use iovec to write multiple data chunks at once. + +typedef struct write_req write_req_t; +struct write_req +{ + LIST_HEADER (write_req_t) + struct iovec data; ///< Data to be written +}; + +typedef struct write_queue write_queue_t; +struct write_queue +{ + write_req_t *head; ///< The head of the queue + write_req_t *tail; ///< The tail of the queue + size_t head_offset; ///< Offset into the head + size_t len; +}; + +static void +write_queue_init (struct write_queue *self) +{ + self->head = self->tail = NULL; + self->head_offset = 0; + self->len = 0; +} + +static void +write_queue_free (struct write_queue *self) +{ + for (write_req_t *iter = self->head, *next; iter; iter = next) + { + next = iter->next; + free (iter->data.iov_base); + free (iter); + } +} + +static void +write_queue_add (struct write_queue *self, write_req_t *req) +{ + LIST_APPEND_WITH_TAIL (self->head, self->tail, req); + self->len++; +} + +static void +write_queue_processed (struct write_queue *self, size_t len) +{ + while (self->head + && self->head_offset + len >= self->head->data.iov_len) + { + write_req_t *head = self->head; + len -= (head->data.iov_len - self->head_offset); + self->head_offset = 0; + + LIST_UNLINK_WITH_TAIL (self->head, self->tail, head); + self->len--; + free (head->data.iov_base); + free (head); + } + self->head_offset += len; +} + +static bool +write_queue_is_empty (struct write_queue *self) +{ + return self->head == NULL; +} + // --- Message reader ---------------------------------------------------------- struct msg_reader -- cgit v1.2.3-54-g00ecf