mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
fix(usockets) fix last_write_failed flag (#25496)
https://github.com/oven-sh/bun/pull/25361 needs to be merged before this PR ## Summary - Move `last_write_failed` flag from loop-level to per-socket flag for correctness ## Changes - Move `last_write_failed` from `loop->data` to `socket->flags` - More semantically correct since write status is per-socket, not per-loop 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -417,8 +417,7 @@ void us_internal_update_handshake(struct us_internal_ssl_socket_t *s) {
|
||||
}
|
||||
s->handshake_state = HANDSHAKE_PENDING;
|
||||
s->ssl_write_wants_read = 1;
|
||||
s->s.context->loop->data.last_write_failed = 1;
|
||||
|
||||
s->s.flags.last_write_failed = 1;
|
||||
return;
|
||||
}
|
||||
// success
|
||||
|
||||
@@ -71,7 +71,7 @@ void us_poll_init(struct us_poll_t *p, LIBUS_SOCKET_DESCRIPTOR fd,
|
||||
}
|
||||
|
||||
void us_poll_free(struct us_poll_t *p, struct us_loop_t *loop) {
|
||||
// poll was adopted and dont own uv_poll_t anymore
|
||||
// poll was resized and dont own uv_poll_t anymore
|
||||
if(!p->uv_p) {
|
||||
free(p);
|
||||
return;
|
||||
|
||||
@@ -176,6 +176,8 @@ struct us_socket_flags {
|
||||
bool adopted: 1;
|
||||
/* If true, the socket is a TLS socket */
|
||||
bool is_tls: 1;
|
||||
/* If true, the last write to this socket failed (would block) */
|
||||
bool last_write_failed: 1;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ struct us_internal_loop_data_t {
|
||||
struct us_timer_t *sweep_timer;
|
||||
int sweep_timer_count;
|
||||
struct us_internal_async *wakeup_async;
|
||||
int last_write_failed;
|
||||
struct us_socket_context_t *head;
|
||||
struct us_socket_context_t *iterator;
|
||||
struct us_socket_context_t *closed_context_head;
|
||||
|
||||
@@ -391,14 +391,12 @@ void us_internal_dispatch_ready_poll(struct us_poll_t *p, int error, int eof, in
|
||||
/* The context can change after calling a callback but the loop is always the same */
|
||||
struct us_loop_t* loop = s->context->loop;
|
||||
if (events & LIBUS_SOCKET_WRITABLE && !error) {
|
||||
/* Note: if we failed a write as a socket of one loop then adopted
|
||||
* to another loop, this will be wrong. Absurd case though */
|
||||
loop->data.last_write_failed = 0;
|
||||
s->flags.last_write_failed = 0;
|
||||
#ifdef LIBUS_USE_KQUEUE
|
||||
/* Kqueue is one-shot so is not writable anymore */
|
||||
p->state.poll_type = us_internal_poll_type(p) | ((events & LIBUS_SOCKET_READABLE) ? POLL_TYPE_POLLING_IN : 0);
|
||||
#endif
|
||||
|
||||
|
||||
s = s->context->on_writable(s);
|
||||
/* After socket adoption, track the new socket; the old one becomes invalid */
|
||||
if(s && s->flags.adopted && s->prev) {
|
||||
@@ -410,7 +408,7 @@ void us_internal_dispatch_ready_poll(struct us_poll_t *p, int error, int eof, in
|
||||
}
|
||||
|
||||
/* If we have no failed write or if we shut down, then stop polling for more writable */
|
||||
if (!loop->data.last_write_failed || us_socket_is_shut_down(0, s)) {
|
||||
if (!s->flags.last_write_failed || us_socket_is_shut_down(0, s)) {
|
||||
us_poll_change(&s->p, loop, us_poll_events(&s->p) & LIBUS_SOCKET_READABLE);
|
||||
} else {
|
||||
#ifdef LIBUS_USE_KQUEUE
|
||||
|
||||
@@ -370,7 +370,7 @@ int us_socket_write(int ssl, struct us_socket_t *s, const char *data, int length
|
||||
|
||||
int written = bsd_send(us_poll_fd(&s->p), data, length);
|
||||
if (written != length) {
|
||||
s->context->loop->data.last_write_failed = 1;
|
||||
s->flags.last_write_failed = 1;
|
||||
us_poll_change(&s->p, s->context->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE);
|
||||
}
|
||||
|
||||
@@ -407,7 +407,7 @@ int us_socket_ipc_write_fd(struct us_socket_t *s, const char* data, int length,
|
||||
int sent = bsd_sendmsg(us_poll_fd(&s->p), &msg, 0);
|
||||
|
||||
if (sent != length) {
|
||||
s->context->loop->data.last_write_failed = 1;
|
||||
s->flags.last_write_failed = 1;
|
||||
us_poll_change(&s->p, s->context->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE);
|
||||
}
|
||||
|
||||
|
||||
@@ -1701,7 +1701,7 @@ size_t uws_req_get_header(uws_req_t *res, const char *lower_case_header,
|
||||
{
|
||||
us_socket_r s = (us_socket_t *)res;
|
||||
if(us_socket_is_closed(s->flags.is_tls, s)) return;
|
||||
s->context->loop->data.last_write_failed = 1;
|
||||
s->flags.last_write_failed = 1;
|
||||
us_poll_change(&s->p, s->context->loop,
|
||||
LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE);
|
||||
}
|
||||
@@ -1866,7 +1866,7 @@ __attribute__((callback (corker, ctx)))
|
||||
|
||||
void us_socket_sendfile_needs_more(us_socket_r s) {
|
||||
if(us_socket_is_closed(s->flags.is_tls, s)) return;
|
||||
s->context->loop->data.last_write_failed = 1;
|
||||
s->flags.last_write_failed = 1;
|
||||
us_poll_change(&s->p, s->context->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ pub const InternalLoopData = extern struct {
|
||||
sweep_timer: ?*Timer,
|
||||
sweep_timer_count: i32,
|
||||
wakeup_async: ?*us_internal_async,
|
||||
last_write_failed: i32,
|
||||
head: ?*SocketContext,
|
||||
iterator: ?*SocketContext,
|
||||
closed_context_head: ?*SocketContext,
|
||||
|
||||
Reference in New Issue
Block a user