diff options
Diffstat (limited to 'utils.c')
-rw-r--r-- | utils.c | 91 |
1 files changed, 91 insertions, 0 deletions
@@ -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 |