Introduction
Introduction Statistics Contact Development Disclaimer Help
Prepare http_send_buf() http_recv_header() for blocking I/O - quark - quark web…
git clone git://git.suckless.org/quark
Log
Files
Refs
LICENSE
---
commit 4d3a6c5297015285f88a56cc47f6a53c372b1506
parent 5d0221dd68c0d2b8796479d06b602be666d0f4c6
Author: Laslo Hunhold <[email protected]>
Date: Sun, 1 Nov 2020 00:10:54 +0100
Prepare http_send_buf() http_recv_header() for blocking I/O
Signed-off-by: Laslo Hunhold <[email protected]>
Diffstat:
M http.c | 27 +++++++++++++++++++++++----
A queue.c | 177 +++++++++++++++++++++++++++++…
A queue.h | 32 +++++++++++++++++++++++++++++…
3 files changed, 232 insertions(+), 4 deletions(-)
---
diff --git a/http.c b/http.c
@@ -109,7 +109,17 @@ http_send_buf(int fd, struct buffer *buf)
while (buf->len > 0) {
if ((r = write(fd, buf->data, buf->len)) <= 0) {
- return S_REQUEST_TIMEOUT;
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ /*
+ * socket is blocking, return normally.
+ * given the buffer still contains data,
+ * this indicates to the caller that we
+ * have been interrupted.
+ */
+ return 0;
+ } else {
+ return S_REQUEST_TIMEOUT;
+ }
}
memmove(buf->data, buf->data + r, buf->len - r);
buf->len -= r;
@@ -145,8 +155,17 @@ http_recv_header(int fd, struct buffer *buf, int *done)
while (1) {
if ((r = read(fd, buf->data + buf->len,
sizeof(buf->data) - buf->len)) <= 0) {
- s = S_REQUEST_TIMEOUT;
- goto err;
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ /*
+ * socket is drained, return normally,
+ * but set done to zero
+ */
+ *done = 0;
+ return 0;
+ } else {
+ s = S_REQUEST_TIMEOUT;
+ goto err;
+ }
}
buf->len += r;
@@ -181,7 +200,7 @@ http_parse_header(const char *h, struct request *req)
const char *p, *q;
char *m, *n;
- /* empty all fields */
+ /* empty the request struct */
memset(req, 0, sizeof(*req));
/*
diff --git a/queue.c b/queue.c
@@ -0,0 +1,177 @@
+/* See LICENSE file for copyright and license details. */
+#include <stddef.h>
+
+#ifdef __linux__
+ #include <sys/epoll.h>
+#else
+ #include <sys/types.h>
+ #include <sys/event.h>
+ #include <sys/time.h>
+#endif
+
+#include "queue.h"
+#include "util.h"
+
+int
+queue_create(void)
+{
+ int qfd;
+
+ #ifdef __linux__
+ if ((qfd = epoll_create1(0)) < 0) {
+ warn("epoll_create1:");
+ }
+ #else
+
+ #endif
+
+ return qfd;
+}
+
+int
+queue_add_fd(int qfd, int fd, enum queue_event_type t, int shared,
+ const void *data)
+{
+ #ifdef __linux__
+ struct epoll_event e;
+
+ /* set event flag */
+ if (shared) {
+ /*
+ * if the fd is shared, "exclusive" is the only
+ * way to avoid spurious wakeups and "blocking"
+ * accept()'s.
+ */
+ e.events = EPOLLEXCLUSIVE;
+ } else {
+ /*
+ * if we have the fd for ourselves (i.e. only
+ * within the thread), we want to be
+ * edge-triggered, as our logic makes sure
+ * that the buffers are drained when we return
+ * to epoll_wait()
+ */
+ e.events = EPOLLET;
+ }
+
+ switch (t) {
+ case QUEUE_EVENT_IN:
+ e.events |= EPOLLIN;
+ break;
+ case QUEUE_EVENT_OUT:
+ e.events |= EPOLLOUT;
+ break;
+ }
+
+ /* set data */
+ if (data == NULL) {
+ /* the data is the fd itself */
+ e.data.fd = fd;
+ } else {
+ /* set data pointer */
+ e.data.ptr = (void *)data;
+ }
+
+ /* register fd in the interest list */
+ if (epoll_ctl(qfd, EPOLL_CTL_ADD, fd, &e) < 0) {
+ warn("epoll_ctl:");
+ return 1;
+ }
+ #else
+
+ #endif
+
+ return 0;
+}
+
+int
+queue_mod_fd(int qfd, int fd, enum queue_event_type t, const void *data)
+{
+ #ifdef __linux__
+ struct epoll_event e;
+
+ /* set event flag */
+ e.events = EPOLLET;
+ switch (t) {
+ case QUEUE_EVENT_IN:
+ e.events |= EPOLLIN;
+ break;
+ case QUEUE_EVENT_OUT:
+ e.events |= EPOLLOUT;
+ break;
+ }
+
+ /* set data */
+ if (data == NULL) {
+ /* the data is the fd itself */
+ e.data.fd = fd;
+ } else {
+ /* set data pointer */
+ e.data.ptr = (void *)data;
+ }
+
+ /* register fd in the interest list */
+ if (epoll_ctl(qfd, EPOLL_CTL_MOD, fd, &e) < 0) {
+ warn("epoll_ctl:");
+ return 1;
+ }
+ #else
+
+ #endif
+
+ return 0;
+}
+
+int
+queue_rem_fd(int qfd, int fd)
+{
+ #ifdef __linux__
+ struct epoll_event e;
+
+ if (epoll_ctl(qfd, EPOLL_CTL_DEL, fd, &e) < 0) {
+ warn("epoll_ctl:");
+ return 1;
+ }
+ #else
+
+ #endif
+
+ return 0;
+}
+
+ssize_t
+queue_wait(int qfd, queue_event *e, size_t elen)
+{
+ ssize_t nready;
+
+ #ifdef __linux__
+ if ((nready = epoll_wait(qfd, e, elen, -1)) < 0) {
+ warn("epoll_wait:");
+ return -1;
+ }
+ #else
+
+ #endif
+
+ return nready;
+}
+
+int
+queue_event_get_fd(const queue_event *e)
+{
+ #ifdef __linux__
+ return e->data.fd;
+ #else
+
+ #endif
+}
+
+void *
+queue_event_get_ptr(const queue_event *e)
+{
+ #ifdef __linux__
+ return e->data.ptr;
+ #else
+
+ #endif
+}
diff --git a/queue.h b/queue.h
@@ -0,0 +1,32 @@
+#ifndef QUEUE_H
+#define QUEUE_H
+
+#include <stddef.h>
+
+#ifdef __linux__
+ #include <sys/epoll.h>
+
+ typedef struct epoll_event queue_event;
+#else
+ #include <sys/types.h>
+ #include <sys/event.h>
+ #include <sys/time.h>
+
+ typedef struct kevent queue_event;
+#endif
+
+enum queue_event_type {
+ QUEUE_EVENT_IN,
+ QUEUE_EVENT_OUT,
+};
+
+int queue_create(void);
+int queue_add_fd(int, int, enum queue_event_type, int, const void *);
+int queue_mod_fd(int, int, enum queue_event_type, const void *);
+int queue_rem_fd(int, int);
+ssize_t queue_wait(int, queue_event *, size_t);
+
+int queue_event_get_fd(const queue_event *);
+void *queue_event_get_ptr(const queue_event *);
+
+#endif /* QUEUE_H */
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.