Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
fa2e27a
threading: make GuardedLock \!Send/\!Sync like MutexGuard
alii Jun 2, 2026
7934b18
fetch: make ignore_data atomic, mirror is_http2 for lock-free reads, …
alii Jun 2, 2026
0093fb3
fetch: partition FetchTasklet into JsState and HttpHandoff (rename-only)
alii Jun 2, 2026
561266a
fetch: start FetchTasklet refcount at 2 and name each ref release
alii Jun 2, 2026
fb8ad8a
fetch: document FetchTasklet's cross-thread ref and lock protocol
alii Jun 2, 2026
92e88ed
fetch: convert FetchTasklet's mutex to Guarded<HttpHandoff> with spli…
alii Jun 2, 2026
b21b592
fetch: make Weak::create_ptr unsafe so callers must prove ctx liveness
alii Jun 3, 2026
92ec278
Merge origin/main (resolve TODO-sweep conflicts in FetchTasklet.rs)
robobun Jun 4, 2026
08158a0
fetch: cover process.exit() with in-flight requests (release_at_shutd…
robobun Jun 4, 2026
bee55b6
fetch: balance streaming-upload refs in release_at_shutdown
robobun Jun 4, 2026
eab71d3
[autofix.ci] apply automated fixes
autofix-ci[bot] Jun 4, 2026
2ceb902
test: drop stale ASAN stderr filter in fetch-exit-in-flight
robobun Jun 4, 2026
0d2ddc2
fetch: balance sink/drain refs in callback's shutdown branch too
robobun Jun 4, 2026
2bb34e8
fetch: take streaming-upload exit refs atomically across all three paths
robobun Jun 4, 2026
a09b295
test: document why fetch-exit-in-flight overrides the default timeout
robobun Jun 4, 2026
4722a5a
ci: retrigger
robobun Jun 4, 2026
cbd7951
Merge branch 'main' into ali/fetch-lifetime-clarity
alii Jun 4, 2026
e6abfab
fetch: take streaming exit refs in on_progress_update's shutdown path…
robobun Jun 4, 2026
acde789
fetch: claim streaming-upload ref releases against exit-window takes
alii Jun 4, 2026
e1254e6
test: suppress macOS ParkingLot one-time leak in exit-in-flight tests
alii Jun 4, 2026
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
24 changes: 23 additions & 1 deletion src/jsc/Weak.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,36 @@ impl<T> Weak<T> {
global_this: &JSGlobalObject,
ref_type: WeakRefType,
ctx: &mut T,
) -> Self {
// SAFETY: `ctx` is derived from a live `&mut T`, so it satisfies the
// liveness contract at creation; the caller's `&mut T` is the same
// proof `create` has always demanded.
unsafe { Self::create_ptr(value, global_this, ref_type, NonNull::from(ctx)) }
}

/// Like [`create`](Self::create), but takes `ctx` as a raw pointer for
/// callers that cannot form `&mut T` (e.g. while disjoint field borrows of
/// the owner are live).
///
/// # Safety
///
/// `ctx` must point to a live `T` and remain valid for as long as the
/// weak ref's finalize callback can fire — the GC finalizer dereferences
/// it. (`create` enforces this via `&mut T`; here the caller must prove
/// liveness instead.)
pub unsafe fn create_ptr(
value: JSValue,
global_this: &JSGlobalObject,
ref_type: WeakRefType,
ctx: NonNull<T>,
) -> Self {
if !value.is_empty() {
return Self {
r#ref: Some(WeakImpl::init(
global_this,
value,
ref_type,
Some(NonNull::from(ctx).cast::<c_void>()),
Some(ctx.cast::<c_void>()),
)),
global_this: Some(global_this.into()),
_ctx: PhantomData,
Expand Down
8 changes: 4 additions & 4 deletions src/runtime/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1184,16 +1184,16 @@ pub(crate) fn __bun_release_task_at_shutdown(task: bun_event_loop::Task) -> bool
use bun_event_loop::task_tag;
match task.tag {
// `callback` (HTTP thread) won the `has_schedule_callback` CAS and
// posted this entry, then deref'd its own +1 if final; the JS-side
// +1 it expected `on_progress_update` to drop is the one we release
// here. Runs on the JS thread, so the plain `deref` (→ `deinit` on
// posted this entry, then released its own ref if final; the JS-side
// ref it expected `on_progress_update` to drop is the one we release
// here. Runs on the JS thread, so `release_js_ref` (→ `deinit` on
// 1→0) is the right teardown path; the HTTP daemon is already
// parked (`shutdown_for_exit` precedes `destroy`), so the
// `Box<AsyncHTTP>` and any `metadata` it owns are exclusively ours.
task_tag::FetchTasklet => {
// SAFETY: `task.ptr` is the live heap `FetchTasklet`; HTTP daemon is
// already parked so we hold the sole reference.
FetchTasklet::deref(task.ptr.cast::<FetchTasklet>());
FetchTasklet::release_js_ref(task.ptr.cast::<FetchTasklet>());
Comment thread
robobun marked this conversation as resolved.
Outdated
true
}
// `AsyncFSTask`s are `Box::leak`'d in `create()` and freed by
Expand Down
Loading
Loading