aboutsummaryrefslogtreecommitdiff
path: root/utils.c
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2014-10-28 02:39:37 +0100
committerPřemysl Janouch <p.janouch@gmail.com>2014-10-28 02:39:37 +0100
commit74965b0f66f1907346df49c1eebb07169d26129d (patch)
treecab8e1e5745db920685b3ff28f112d89971c0821 /utils.c
parent606c5f43af3b9b7a5f1484540e7455346bba31c9 (diff)
downloadneetdraw-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.c91
1 files changed, 91 insertions, 0 deletions
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