diff options
author | Přemysl Janouch <p.janouch@gmail.com> | 2014-10-28 02:39:37 +0100 |
---|---|---|
committer | Přemysl Janouch <p.janouch@gmail.com> | 2014-10-28 02:39:37 +0100 |
commit | 74965b0f66f1907346df49c1eebb07169d26129d (patch) | |
tree | cab8e1e5745db920685b3ff28f112d89971c0821 /utils.c | |
parent | 606c5f43af3b9b7a5f1484540e7455346bba31c9 (diff) | |
download | neetdraw-74965b0f66f1907346df49c1eebb07169d26129d.tar.gz neetdraw-74965b0f66f1907346df49c1eebb07169d26129d.tar.xz neetdraw-74965b0f66f1907346df49c1eebb07169d26129d.zip |
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.
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 |