Compare commits

...

2 Commits

Author SHA1 Message Date
Jarred Sumner
cd2249d65b more careful 2024-12-19 01:58:34 -08:00
Jarred Sumner
27a3ea51da Handle eintr in kqueue/epoll better related to timers 2024-12-19 00:30:31 -08:00
6 changed files with 75 additions and 25 deletions

View File

@@ -33,7 +33,8 @@ void Bun__internal_dispatch_ready_poll(void* loop, void* poll);
#include <string.h> // memset
#endif
void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout);
void us_loop_run_bun_tick(struct us_loop_t *loop, struct timespec* timeout, void* timeout_update_ctx);
extern int Bun__updateTimeoutAfterEINTR(void* timeout_update_ctx, struct timespec *timeout);
/* Pointer tags are used to indicate a Bun pointer versus a uSockets pointer */
#define UNSET_BITS_49_UNTIL_64 0x0000FFFFFFFFFFFF
@@ -128,8 +129,7 @@ static int has_epoll_pwait2 = -1;
extern ssize_t sys_epoll_pwait2(int epfd, struct epoll_event* events, int maxevents,
const struct timespec* timeout, const sigset_t* sigmask);
static int bun_epoll_pwait2(int epfd, struct epoll_event *events, int maxevents, const struct timespec *timeout) {
static int bun_epoll_pwait2(int epfd, struct epoll_event *events, int maxevents, struct timespec *timeout, void* timeout_update_ctx) {
int ret;
sigset_t mask;
sigemptyset(&mask);
@@ -137,7 +137,21 @@ static int bun_epoll_pwait2(int epfd, struct epoll_event *events, int maxevents,
if (has_epoll_pwait2 != 0) {
do {
ret = sys_epoll_pwait2(epfd, events, maxevents, timeout, &mask);
} while (ret == -EINTR);
if (ret == -EINTR) {
if (timeout_update_ctx && timeout) {
if (!Bun__updateTimeoutAfterEINTR(timeout_update_ctx, timeout)) {
timeout = NULL;
}
if (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0) {
ret = 0;
break;
}
}
continue;
}
break;
} while (1);
if (LIKELY(ret != -ENOSYS && ret != -EPERM && ret != -EOPNOTSUPP)) {
return ret;
@@ -153,7 +167,22 @@ static int bun_epoll_pwait2(int epfd, struct epoll_event *events, int maxevents,
do {
ret = epoll_pwait(epfd, events, maxevents, timeoutMs, &mask);
} while (IS_EINTR(ret));
if (ret == -1 && errno == EINTR) {
if (timeout_update_ctx && timeout) {
if (!Bun__updateTimeoutAfterEINTR(timeout_update_ctx, timeout)) {
timeout = NULL;
}
if (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0) {
ret = 0;
break;
}
}
continue;
}
break;
} while (1);
return ret;
}
@@ -199,7 +228,7 @@ void us_loop_run(struct us_loop_t *loop) {
/* Fetch ready polls */
#ifdef LIBUS_USE_EPOLL
loop->num_ready_polls = bun_epoll_pwait2(loop->fd, loop->ready_polls, 1024, NULL);
loop->num_ready_polls = bun_epoll_pwait2(loop->fd, loop->ready_polls, 1024, NULL, NULL);
#else
do {
loop->num_ready_polls = kevent64(loop->fd, NULL, 0, loop->ready_polls, 1024, 0, NULL);
@@ -250,7 +279,7 @@ void us_loop_run(struct us_loop_t *loop) {
extern int Bun__JSC_onBeforeWait(void*);
extern void Bun__JSC_onAfterWait(void*);
void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout) {
void us_loop_run_bun_tick(struct us_loop_t *loop, struct timespec* timeout, void* timeout_update_ctx) {
if (loop->num_polls == 0)
return;
@@ -272,12 +301,29 @@ void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout
/* Fetch ready polls */
#ifdef LIBUS_USE_EPOLL
loop->num_ready_polls = bun_epoll_pwait2(loop->fd, loop->ready_polls, 1024, timeout);
loop->num_ready_polls = bun_epoll_pwait2(loop->fd, loop->ready_polls, 1024, timeout, timeout_update_ctx);
#else
do {
loop->num_ready_polls = kevent64(loop->fd, NULL, 0, loop->ready_polls, 1024, 0, timeout);
} while (IS_EINTR(loop->num_ready_polls));
int rc = kevent64(loop->fd, NULL, 0, loop->ready_polls, 1024, 0, timeout);
if (UNLIKELY(rc == -1 && errno == EINTR)) {
if (timeout_update_ctx && timeout) {
if (!Bun__updateTimeoutAfterEINTR(timeout_update_ctx, timeout)) {
timeout = NULL;
}
if (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0) {
loop->num_ready_polls = 0;
break;
}
}
continue;
}
loop->num_ready_polls = rc;
break;
} while (1);
#endif
if (needs_after_wait) {

View File

@@ -151,6 +151,7 @@ const JSC::GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = {
INHERIT_HOOK_METHOD(deriveShadowRealmGlobalObject),
INHERIT_HOOK_METHOD(codeForEval),
INHERIT_HOOK_METHOD(canCompileStrings),
INHERIT_HOOK_METHOD(trustedScriptStructure),
};
GlobalObject* GlobalObject::create(JSC::VM& vm, JSC::Structure* structure,

View File

@@ -129,6 +129,14 @@ pub const All = struct {
return VirtualMachine.get().timer.last_id;
}
pub export fn Bun__updateTimeoutAfterEINTR(this: *VirtualMachine, timeout: *timespec) i32 {
if (!this.timer.getTimeout(timeout)) {
return 0;
}
return 1;
}
pub fn getTimeout(this: *const All, spec: *timespec) bool {
if (this.active_timer_count == 0) {
return false;

View File

@@ -1408,7 +1408,7 @@ pub const EventLoop = struct {
var event_loop_sleep_timer = if (comptime Environment.isDebug) std.time.Timer.start() catch unreachable else {};
// for the printer, this is defined:
var timespec: bun.timespec = if (Environment.isDebug) .{ .sec = 0, .nsec = 0 } else undefined;
loop.tickWithTimeout(if (ctx.timer.getTimeout(&timespec)) &timespec else null);
loop.tickWithTimeout(if (ctx.timer.getTimeout(&timespec)) &timespec else null, ctx);
if (comptime Environment.isDebug) {
log("tick {}, timeout: {}", .{ bun.fmt.fmtDuration(event_loop_sleep_timer.read()), bun.fmt.fmtDuration(timespec.ns()) });
@@ -1492,8 +1492,7 @@ pub const EventLoop = struct {
if (loop.isActive()) {
this.processGCTimer();
var timespec: bun.timespec = undefined;
loop.tickWithTimeout(if (ctx.timer.getTimeout(&timespec)) &timespec else null);
loop.tickWithTimeout(if (ctx.timer.getTimeout(&timespec)) &timespec else null, ctx);
} else {
loop.tickWithoutIdle();
}

View File

@@ -1651,7 +1651,7 @@ pub const VirtualMachine = struct {
}
}
this.uwsLoop().tickWithTimeout(&deadline);
this.uwsLoop().tickWithTimeout(&deadline, this);
if (comptime Environment.enable_logs)
log("waited: {}", .{bun.fmt.fmtDuration(@intCast(@as(i64, @truncate(std.time.nanoTimestamp() - bun.CLI.start_time))))});

View File

@@ -2543,19 +2543,19 @@ pub const PosixLoop = extern struct {
pub const wake = wakeup;
pub fn tick(this: *PosixLoop) void {
us_loop_run_bun_tick(this, null);
us_loop_run_bun_tick(this, null, null);
}
pub fn tickWithoutIdle(this: *PosixLoop) void {
const timespec = bun.timespec{ .sec = 0, .nsec = 0 };
us_loop_run_bun_tick(this, &timespec);
us_loop_run_bun_tick(this, &timespec, null);
}
pub fn tickWithTimeout(this: *PosixLoop, timespec: ?*const bun.timespec) void {
us_loop_run_bun_tick(this, timespec);
pub fn tickWithTimeout(this: *PosixLoop, timespec: ?*bun.timespec, timeout_update_ctx: ?*anyopaque) void {
us_loop_run_bun_tick(this, timespec, timeout_update_ctx);
}
extern fn us_loop_run_bun_tick(loop: ?*Loop, timouetMs: ?*const bun.timespec) void;
extern fn us_loop_run_bun_tick(loop: ?*Loop, timouetMs: ?*const bun.timespec, timeout_update_ctx: ?*anyopaque) void;
pub fn nextTick(this: *PosixLoop, comptime UserType: type, user_data: UserType, comptime deferCallback: fn (ctx: UserType) void) void {
const Handler = struct {
@@ -2598,10 +2598,6 @@ pub const PosixLoop = extern struct {
.loop = this,
};
}
pub fn run(this: *PosixLoop) void {
us_loop_run(this);
}
};
extern fn uws_loop_defer(loop: *Loop, ctx: *anyopaque, cb: *const (fn (ctx: *anyopaque) callconv(.C) void)) void;
@@ -4286,7 +4282,7 @@ pub const WindowsLoop = extern struct {
pub const wake = wakeup;
pub fn tickWithTimeout(this: *WindowsLoop, _: ?*const bun.timespec) void {
pub fn tickWithTimeout(this: *WindowsLoop, _: ?*const bun.timespec, _: ?*anyopaque) void {
us_loop_run(this);
}