aboutsummaryrefslogtreecommitdiffstats
path: root/serve/serve.c
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-10-04 15:36:51 +0100
committereunhhu <[email protected]>2026-10-04 15:36:51 +0100
commit90c8edece941f26cd280686c7063a7c9149a2212 (patch)
treea78a569fc76ac89c2aa782482e7f744872a0206f /serve/serve.c
parent872e3a60829744a231c6efdb3208d339cdb9e9d8 (diff)
downloadpure-90c8edece941f26cd280686c7063a7c9149a2212.tar.gz
pure-90c8edece941f26cd280686c7063a7c9149a2212.zip
Watch a subscriber for writing only while it keeps output, and measure freshness by push and polling (019)
Diffstat (limited to 'serve/serve.c')
-rw-r--r--serve/serve.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/serve/serve.c b/serve/serve.c
index fb84425..4e62d3d 100644
--- a/serve/serve.c
+++ b/serve/serve.c
@@ -2369,6 +2369,15 @@ static char *copied(const char *bytes, size_t size) {
return copy;
}
+/* A subscriber's socket in the epoll set: told when it can be read (it
+ * closed), and when it can be written only while it keeps something to
+ * send (otherwise every acknowledgment would wake the thread). */
+static void watch_subscriber(Host *host, Subscriber *s, int op) {
+ struct epoll_event event = {.events = EPOLLIN | EPOLLRDHUP | EPOLLET | (s->out ? EPOLLOUT : 0),
+ .data.u64 = (uintptr_t)s | 1u};
+ if (epoll_ctl(host->epoll, op, s->fd, &event)) abort();
+}
+
/* An event to a subscriber: sent now as far as its socket takes it, the
* rest kept; while one is kept, the newest waits after it, replacing what
* waited. False when its socket failed. */
@@ -2389,12 +2398,14 @@ static bool subscriber_send(Host *host, Subscriber *s, const char *event, size_t
s->out_size = size - (size_t)n;
s->out_at = 0;
s->stalled = host->now;
+ watch_subscriber(host, s, EPOLL_CTL_MOD); /* and now when it can be written */
}
return true;
}
/* What a subscriber kept, sent as far as its socket takes it. False when its socket failed. */
static bool subscriber_flush(Host *host, Subscriber *s) {
+ bool kept = s->out != NULL;
while (s->out && s->writable) {
ssize_t n = send(s->fd, s->out + s->out_at, s->out_size - s->out_at, MSG_NOSIGNAL | MSG_DONTWAIT);
if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) return false;
@@ -2406,6 +2417,7 @@ static bool subscriber_flush(Host *host, Subscriber *s) {
s->out = s->waiting, s->out_size = s->waiting_size, s->out_at = 0;
s->waiting = NULL;
}
+ if (kept && !s->out) watch_subscriber(host, s, EPOLL_CTL_MOD); /* all sent: no more told when it can be written */
return true;
}
@@ -2589,8 +2601,7 @@ static void subscribe(Connection *c, const Route *route, const char *raw, size_t
if ((s->token = c->bearer_given && c->hashed_valid)) memcpy(s->digest, c->hashed_digest, sizeof(s->digest));
s->next = g->first;
g->first = s;
- struct epoll_event event = {.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET, .data.u64 = (uintptr_t)s | 1u};
- if (epoll_ctl(host->epoll, EPOLL_CTL_MOD, s->fd, &event)) abort();
+ watch_subscriber(host, s, EPOLL_CTL_MOD);
c->fd = -1; /* the socket is the subscriber's now */
close_connection(c);
atomic_fetch_add_explicit(&route->app->owner.published.subscribers, 1, memory_order_relaxed);