aboutsummaryrefslogtreecommitdiff
path: root/utils.c
diff options
context:
space:
mode:
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