Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions packages/bun-usockets/src/eventing/epoll_kqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ void Bun__internal_dispatch_ready_poll(void* loop, void* poll);
#include <stdint.h>
#include <errno.h>
#include <string.h> // memset
#include <mimalloc.h>
#endif

void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout, uint64_t now_ns);
Expand Down Expand Up @@ -391,6 +392,22 @@ void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout
if (will_idle_inside_event_loop && loop->data.jsc_vm)
Bun__JSC_onBeforeWait(loop->data.jsc_vm, now_ns);

/* The scavenger sweeps our heaps while we are in the kernel. Must come after
* Bun__JSC_onBeforeWait, which allocates: nothing may touch our heaps until the matching
* _end. mimalloc paces the sweep itself, so this costs a compare-and-swap per tick.
* With no scavenger to hand off to, fall back to sweeping inline -- but only on a tick that
* really parks, and rate-limited, because doing it between ticks is what we are avoiding. */
const int handed_off = mi_on_thread_idle_start();
if (!handed_off && will_idle_inside_event_loop) {
static const uint64_t idle_sweep_interval_ns = 100 * 1000000ULL;
static _Thread_local uint64_t last_idle_sweep_ns = 0;
const uint64_t sweep_now_ns = now_ns ? now_ns : us_internal_monotonic_ns();
if (sweep_now_ns >= last_idle_sweep_ns + idle_sweep_interval_ns) {
last_idle_sweep_ns = sweep_now_ns;
mi_on_thread_idle();
}
}

/* Fetch ready polls */
#ifdef LIBUS_USE_EPOLL
/* A zero timespec already has a fast path in ep_poll (fs/eventpoll.c):
Expand All @@ -411,6 +428,10 @@ void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout
} while (IS_EINTR(loop->num_ready_polls));
#endif

/* Before anything can allocate again. */
if (handed_off)
mi_on_thread_idle_end();

us_internal_dispatch_ready_polls(loop);
us_internal_drain_ready_polls(loop);
us_internal_sweep_if_due(loop);
Expand Down
2 changes: 1 addition & 1 deletion scripts/build/deps/mimalloc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

import type { Dependency, DirectBuild } from "../source.ts";

const MIMALLOC_COMMIT = "13eecae8f35a73c16bdcded9291d9b56b7fc0fca";
const MIMALLOC_COMMIT = "24211c6e7610ae7c4ec06040758ec90bd21a1c83";

export const mimalloc: Dependency = {
name: "mimalloc",
Expand Down
10 changes: 5 additions & 5 deletions src/jsc/bindings/BunJSCEventLoop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,16 +82,16 @@
vm->heap.stopIfNecessary();
vm->didEnterVM = false;

#if USE(MIMALLOC)
#if USE(MIMALLOC) && OS(WINDOWS)
// Collect retired pages, punch free-block holes, hand the arena purge to
// the scavenger. Rate-limited; nowNs is the tick's shared reading (0 = take
// one), compared by addition so an out-of-order reading cannot underflow.
//
// Windows only: everywhere else `us_loop_run_bun_tick` hands the heaps to the
// scavenger across the poll instead, so this thread never does the sweep itself.
// The libuv loop has no handoff yet, so it keeps paying for it here.

Check warning on line 92 in src/jsc/bindings/BunJSCEventLoop.cpp

View check run for this annotation

Claude / Claude Code Review

Dead code/comment left after gating sweep to Windows-only

Gating this block to `OS(WINDOWS)` and deleting the `if (nowNs == 0) nowNs = us_internal_monotonic_ns();` fallback leaves stale artifacts: the comment's "(0 = take one)" clause now describes code that no longer exists (Windows always passes a reading, and if it passed 0 the sweep would be *skipped*, not "taken"), and the `us_internal_monotonic_ns` extern + its 3-line comment at the top of the file is now unreferenced (as is `mi_on_thread_idle` on non-Windows, and the `nowNs` parameter itself). P
Comment on lines +85 to +92

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Gating this block to OS(WINDOWS) and deleting the if (nowNs == 0) nowNs = us_internal_monotonic_ns(); fallback leaves stale artifacts: the comment's "(0 = take one)" clause now describes code that no longer exists (Windows always passes a reading, and if it passed 0 the sweep would be skipped, not "taken"), and the us_internal_monotonic_ns extern + its 3-line comment at the top of the file is now unreferenced (as is mi_on_thread_idle on non-Windows, and the nowNs parameter itself). Per the landing rules, dead code should be deleted in the same PR that makes it dead — drop the parenthetical, remove the #if !OS(WINDOWS) extern block, and gate the mi_on_thread_idle extern to OS(WINDOWS).

Extended reasoning...

What's stale

This PR made two changes to the #if USE(MIMALLOC) block in Bun__JSC_onBeforeWait:

  1. Tightened the guard from #if USE(MIMALLOC) to #if USE(MIMALLOC) && OS(WINDOWS).
  2. Deleted the fallback that used to live inside it:
    #if !OS(WINDOWS)
    if (nowNs == 0)
        nowNs = us_internal_monotonic_ns();
    #endif

Two pieces of surrounding text/code described that fallback and were not updated.

(a) The "(0 = take one)" comment clause

The comment above the rate-limit check still reads:

Rate-limited; nowNs is the tick's shared reading (0 = take one), compared by addition so an out-of-order reading cannot underflow.

"0 = take one" was accurate before this PR: on POSIX, nowNs == 0 triggered nowNs = us_internal_monotonic_ns(). That line is now deleted, and the block only compiles on Windows — where the fallback never existed in the first place (the extern comment at the top of the file explicitly says "Windows always passes a reading, so it needs no fallback", and libuv.c:226 confirms it: Bun__JSC_onBeforeWait(loop->data.jsc_vm, (uint64_t) uv_now(loop->uv_loop) * 1000000ULL)).

Step-by-step: if Windows ever did pass nowNs = 0, the check would be 0 >= lastIdleSweepNs + 100000000. With lastIdleSweepNs starting at 0, that's 0 >= 100000000 → false → sweep skipped. It would not "take one". The parenthetical now describes behavior that exists nowhere in the codebase. The PR touched this exact comment (added the "Windows only:" paragraph right below it), so this isn't pre-existing drift — the stale clause was left in a block the author edited.

(b) Dead extern declarations at the top of the file

#if USE(MIMALLOC)
extern "C" void mi_on_thread_idle(void) noexcept;
#if !OS(WINDOWS)
// uSockets' CLOCK_MONOTONIC reading (packages/bun-usockets/src/loop.c). Must be
// the same clock the caller's `nowNs` came from, or the rate limit below
// compares two epochs. Windows always passes a reading, so it needs no fallback.
extern "C" uint64_t us_internal_monotonic_ns(void);
#endif
#endif
  • us_internal_monotonic_ns is guarded #if !OS(WINDOWS). Its only call site in this TU was the deleted fallback. The declaration and its 3-line explanatory comment are now completely unreferenced — the symbol is never mentioned again in this file.
  • mi_on_thread_idle is declared under #if USE(MIMALLOC) (all platforms) but is now only called under #if USE(MIMALLOC) && OS(WINDOWS), so on Linux/macOS it's an unused extern declaration.
  • The nowNs function parameter is now unread on non-Windows builds.

Impact

None at runtime. Unused extern declarations emit no code and create no link dependency; a stale comment doesn't execute. This is purely about the repo's landing rule (CLAUDE.md → "Delete dead code in the same PR that makes it dead (required scope)" and "Comments carry only durable non-obvious content") — the PR itself made these dead, so cleanup belongs in the same change.

Fix

  • Drop "(0 = take one)" from the comment (e.g. "Rate-limited; nowNs is the tick's shared reading, compared by addition so an out-of-order reading cannot underflow.").
  • Delete the #if !OS(WINDOWS) extern block for us_internal_monotonic_ns entirely (declaration + 3-line comment).
  • Tighten the mi_on_thread_idle extern guard to #if USE(MIMALLOC) && OS(WINDOWS) to match its only remaining call site.
  • Optionally (void)nowNs; on non-Windows if the build treats unused parameters as errors here.

static constexpr uint64_t idleSweepIntervalNs = 100 * 1000000ULL;
static thread_local uint64_t lastIdleSweepNs = 0;
#if !OS(WINDOWS)
if (nowNs == 0)
nowNs = us_internal_monotonic_ns();
#endif
if (nowNs >= lastIdleSweepNs + idleSweepIntervalNs) {
lastIdleSweepNs = nowNs;
mi_on_thread_idle();
Expand Down
Loading