diff options
author | 2022-10-10 21:00:39 -0700 | |
---|---|---|
committer | 2022-10-10 21:00:39 -0700 | |
commit | 2292ef8d0e2c0f5ac5523dfb919c4156ad4ea4fb (patch) | |
tree | 769fdf7fa0f5fa78776277ba095495d6c39e9fe4 /src | |
parent | a114af4eea794e8b6a76b7cadc8f18730a52e8ad (diff) | |
download | bun-2292ef8d0e2c0f5ac5523dfb919c4156ad4ea4fb.tar.gz bun-2292ef8d0e2c0f5ac5523dfb919c4156ad4ea4fb.tar.zst bun-2292ef8d0e2c0f5ac5523dfb919c4156ad4ea4fb.zip |
Keep the process alive
Diffstat (limited to 'src')
-rw-r--r-- | src/bun.js/api/bun.classes.ts | 5 | ||||
-rw-r--r-- | src/bun.js/api/bun.zig | 2 | ||||
-rw-r--r-- | src/bun.js/api/bun/subprocess.zig | 35 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses.cpp | 43 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses.h | 5 | ||||
-rw-r--r-- | src/bun.js/event_loop.zig | 57 | ||||
-rw-r--r-- | src/bun.js/javascript.zig | 1 |
7 files changed, 62 insertions, 86 deletions
diff --git a/src/bun.js/api/bun.classes.ts b/src/bun.js/api/bun.classes.ts index bbb1df944..2f688bb9c 100644 --- a/src/bun.js/api/bun.classes.ts +++ b/src/bun.js/api/bun.classes.ts @@ -21,11 +21,11 @@ export default [ }, writable: { getter: "getStdin", - cache: true, + cache: "stdin", }, readable: { getter: "getStdout", - cache: true, + cache: "stdout", }, stderr: { getter: "getStderr", @@ -56,7 +56,6 @@ export default [ exited: { getter: "getExited", - cache: true, }, }, }), diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig index 9b50746c5..007538a6a 100644 --- a/src/bun.js/api/bun.zig +++ b/src/bun.js/api/bun.zig @@ -1522,7 +1522,7 @@ pub fn serve( exception: js.ExceptionRef, ) js.JSValueRef { var args = JSC.Node.ArgumentsSlice.from(ctx.bunVM(), arguments); - var config = JSC.API.ServerConfig.fromJS(ctx.ptr(), &args, exception); + const config = JSC.API.ServerConfig.fromJS(ctx.ptr(), &args, exception); if (exception.* != null) { return null; } diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig index 0c5d0ce2b..9fac2ee37 100644 --- a/src/bun.js/api/bun/subprocess.zig +++ b/src/bun.js/api/bun/subprocess.zig @@ -33,8 +33,13 @@ pub const Subprocess = struct { reffer: JSC.Ref = JSC.Ref.init(), poll_ref: JSC.PollRef = JSC.PollRef.init(), - exit_promise: JSValue = JSValue.zero, - this_jsvalue: JSValue = JSValue.zero, + exit_promise: JSC.Strong = .{}, + + /// Keep the JSValue alive until the process is done by default + /// Unless you call unref() + this_jsvalue: JSC.Strong = .{}, + + on_exit_callback: JSC.Strong = .{}, exit_code: ?u8 = null, waitpid_err: ?JSC.Node.Syscall.Error = null, @@ -49,14 +54,13 @@ pub const Subprocess = struct { globalThis: *JSC.JSGlobalObject, - on_exit_callback: JSC.Strong = .{}, - pub fn ref(this: *Subprocess) void { this.reffer.ref(this.globalThis.bunVM()); this.poll_ref.ref(this.globalThis.bunVM()); } pub fn unref(this: *Subprocess) void { + this.this_jsvalue.clear(); this.reffer.unref(this.globalThis.bunVM()); this.poll_ref.unref(this.globalThis.bunVM()); } @@ -279,7 +283,8 @@ pub const Subprocess = struct { this.stdin.close(); } - pub fn doRef(this: *Subprocess, _: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSValue { + pub fn doRef(this: *Subprocess, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue { + this.this_jsvalue.set(globalThis, callframe.this()); this.ref(); return JSC.JSValue.jsUndefined(); } @@ -349,6 +354,10 @@ pub const Subprocess = struct { return; } + if (comptime bun.Environment.allow_assert) { + // bun.assertNonBlocking(this.fd); + } + while (to_write.len > 0) { switch (JSC.Node.Syscall.write(this.fd, to_write)) { .err => |e| { @@ -700,11 +709,11 @@ pub const Subprocess = struct { return JSC.JSPromise.resolvedPromiseValue(globalThis, JSC.JSValue.jsNumber(code)); } - if (this.exit_promise == .zero) { - this.exit_promise = JSC.JSPromise.create(globalThis).asValue(globalThis); + if (!this.exit_promise.has()) { + this.exit_promise.set(globalThis, JSC.JSPromise.create(globalThis).asValue(globalThis)); } - return this.exit_promise; + return this.exit_promise.get().?; } pub fn getExitCode( @@ -1025,8 +1034,8 @@ pub const Subprocess = struct { subprocess.stdin.pipe.signal = JSC.WebCore.Signal.init(&subprocess.stdin); } - subprocess.this_jsvalue = subprocess.toJS(globalThis); - subprocess.this_jsvalue.ensureStillAlive(); + const out = subprocess.toJS(globalThis); + subprocess.this_jsvalue.set(globalThis, out); switch (globalThis.bunVM().poller.watch( @intCast(JSC.Node.FileDescriptor, pidfd), @@ -1064,7 +1073,7 @@ pub const Subprocess = struct { subprocess.stderr.pipe.buffer.readIfPossible(); } - return subprocess.this_jsvalue; + return out; } pub fn onExitNotification( @@ -1114,9 +1123,7 @@ pub const Subprocess = struct { } } - if (this.exit_promise != .zero) { - var promise = this.exit_promise; - this.exit_promise = .zero; + if (this.exit_promise.trySwap()) |promise| { if (this.exit_code) |code| { promise.asPromise().?.resolve(this.globalThis, JSValue.jsNumber(code)); } else if (this.waitpid_err) |err| { diff --git a/src/bun.js/bindings/ZigGeneratedClasses.cpp b/src/bun.js/bindings/ZigGeneratedClasses.cpp index ec53d56ba..c737103fc 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses.cpp +++ b/src/bun.js/bindings/ZigGeneratedClasses.cpp @@ -131,19 +131,12 @@ JSC_DEFINE_CUSTOM_GETTER(SubprocessPrototype__exitedGetterWrap, (JSGlobalObject Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); auto throwScope = DECLARE_THROW_SCOPE(vm); JSSubprocess* thisObject = jsCast<JSSubprocess*>(JSValue::decode(thisValue)); - JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); - - if (JSValue cachedValue = thisObject->m_exited.get()) - return JSValue::encode(cachedValue); - - JSC::JSValue result = JSC::JSValue::decode( - SubprocessPrototype__getExited(thisObject->wrapped(), globalObject) - ); + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + JSC::EncodedJSValue result = SubprocessPrototype__getExited(thisObject->wrapped(), globalObject); RETURN_IF_EXCEPTION(throwScope, {}); - thisObject->m_exited.set(vm, thisObject, result); - RELEASE_AND_RETURN(throwScope, JSValue::encode(result)); + RELEASE_AND_RETURN(throwScope, result); } - + JSC_DEFINE_HOST_FUNCTION(SubprocessPrototype__killCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) { @@ -196,14 +189,14 @@ JSC_DEFINE_CUSTOM_GETTER(SubprocessPrototype__readableGetterWrap, (JSGlobalObjec JSSubprocess* thisObject = jsCast<JSSubprocess*>(JSValue::decode(thisValue)); JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); - if (JSValue cachedValue = thisObject->m_readable.get()) + if (JSValue cachedValue = thisObject->m_stdout.get()) return JSValue::encode(cachedValue); JSC::JSValue result = JSC::JSValue::decode( SubprocessPrototype__getStdout(thisObject->wrapped(), globalObject) ); RETURN_IF_EXCEPTION(throwScope, {}); - thisObject->m_readable.set(vm, thisObject, result); + thisObject->m_stdout.set(vm, thisObject, result); RELEASE_AND_RETURN(throwScope, JSValue::encode(result)); } @@ -310,14 +303,14 @@ JSC_DEFINE_CUSTOM_GETTER(SubprocessPrototype__writableGetterWrap, (JSGlobalObjec JSSubprocess* thisObject = jsCast<JSSubprocess*>(JSValue::decode(thisValue)); JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); - if (JSValue cachedValue = thisObject->m_writable.get()) + if (JSValue cachedValue = thisObject->m_stdin.get()) return JSValue::encode(cachedValue); JSC::JSValue result = JSC::JSValue::decode( SubprocessPrototype__getStdin(thisObject->wrapped(), globalObject) ); RETURN_IF_EXCEPTION(throwScope, {}); - thisObject->m_writable.set(vm, thisObject, result); + thisObject->m_stdin.set(vm, thisObject, result); RELEASE_AND_RETURN(throwScope, JSValue::encode(result)); } @@ -422,7 +415,6 @@ JSSubprocess* JSSubprocess::create(JSC::VM& vm, JSC::JSGlobalObject* globalObjec return ptr; } - extern "C" void* Subprocess__fromJS(JSC::EncodedJSValue value) { JSSubprocess* object = JSC::jsDynamicCast<JSSubprocess*>(JSValue::decode(value)); if (!object) @@ -465,12 +457,10 @@ void JSSubprocess::visitChildrenImpl(JSCell* cell, Visitor& visitor) ASSERT_GC_OBJECT_INHERITS(thisObject, info()); Base::visitChildren(thisObject, visitor); - visitor.append(thisObject->m_exited); - visitor.append(thisObject->m_readable); + visitor.append(thisObject->m_stderr); visitor.append(thisObject->m_stdin); visitor.append(thisObject->m_stdout); - visitor.append(thisObject->m_writable); } DEFINE_VISIT_CHILDREN(JSSubprocess);extern "C" void* SHA1Class__construct(JSC::JSGlobalObject*, JSC::CallFrame*); @@ -673,7 +663,6 @@ JSSHA1* JSSHA1::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Stru return ptr; } - extern "C" void* SHA1__fromJS(JSC::EncodedJSValue value) { JSSHA1* object = JSC::jsDynamicCast<JSSHA1*>(JSValue::decode(value)); if (!object) @@ -907,7 +896,6 @@ JSMD5* JSMD5::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Struct return ptr; } - extern "C" void* MD5__fromJS(JSC::EncodedJSValue value) { JSMD5* object = JSC::jsDynamicCast<JSMD5*>(JSValue::decode(value)); if (!object) @@ -1141,7 +1129,6 @@ JSMD4* JSMD4::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Struct return ptr; } - extern "C" void* MD4__fromJS(JSC::EncodedJSValue value) { JSMD4* object = JSC::jsDynamicCast<JSMD4*>(JSValue::decode(value)); if (!object) @@ -1375,7 +1362,6 @@ JSSHA224* JSSHA224::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC:: return ptr; } - extern "C" void* SHA224__fromJS(JSC::EncodedJSValue value) { JSSHA224* object = JSC::jsDynamicCast<JSSHA224*>(JSValue::decode(value)); if (!object) @@ -1609,7 +1595,6 @@ JSSHA512* JSSHA512::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC:: return ptr; } - extern "C" void* SHA512__fromJS(JSC::EncodedJSValue value) { JSSHA512* object = JSC::jsDynamicCast<JSSHA512*>(JSValue::decode(value)); if (!object) @@ -1843,7 +1828,6 @@ JSSHA384* JSSHA384::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC:: return ptr; } - extern "C" void* SHA384__fromJS(JSC::EncodedJSValue value) { JSSHA384* object = JSC::jsDynamicCast<JSSHA384*>(JSValue::decode(value)); if (!object) @@ -2077,7 +2061,6 @@ JSSHA256* JSSHA256::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC:: return ptr; } - extern "C" void* SHA256__fromJS(JSC::EncodedJSValue value) { JSSHA256* object = JSC::jsDynamicCast<JSSHA256*>(JSValue::decode(value)); if (!object) @@ -2311,7 +2294,6 @@ JSSHA512_256* JSSHA512_256::create(JSC::VM& vm, JSC::JSGlobalObject* globalObjec return ptr; } - extern "C" void* SHA512_256__fromJS(JSC::EncodedJSValue value) { JSSHA512_256* object = JSC::jsDynamicCast<JSSHA512_256*>(JSValue::decode(value)); if (!object) @@ -2539,7 +2521,6 @@ JSTextDecoder* JSTextDecoder::create(JSC::VM& vm, JSC::JSGlobalObject* globalObj return ptr; } - extern "C" void* TextDecoder__fromJS(JSC::EncodedJSValue value) { JSTextDecoder* object = JSC::jsDynamicCast<JSTextDecoder*>(JSValue::decode(value)); if (!object) @@ -2582,6 +2563,7 @@ void JSTextDecoder::visitChildrenImpl(JSCell* cell, Visitor& visitor) ASSERT_GC_OBJECT_INHERITS(thisObject, info()); Base::visitChildren(thisObject, visitor); + visitor.append(thisObject->m_encoding); } @@ -3083,7 +3065,6 @@ JSRequest* JSRequest::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC return ptr; } - extern "C" void* Request__fromJS(JSC::EncodedJSValue value) { JSRequest* object = JSC::jsDynamicCast<JSRequest*>(JSValue::decode(value)); if (!object) @@ -3125,6 +3106,7 @@ void JSRequest::visitChildrenImpl(JSCell* cell, Visitor& visitor) JSRequest* thisObject = jsCast<JSRequest*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); Base::visitChildren(thisObject, visitor); + if (auto* ptr = thisObject->wrapped()) { visitor.reportExtraMemoryVisited(Request__estimatedSize(ptr)); } @@ -3574,7 +3556,6 @@ JSResponse* JSResponse::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, J return ptr; } - extern "C" void* Response__fromJS(JSC::EncodedJSValue value) { JSResponse* object = JSC::jsDynamicCast<JSResponse*>(JSValue::decode(value)); if (!object) @@ -3616,6 +3597,7 @@ void JSResponse::visitChildrenImpl(JSCell* cell, Visitor& visitor) JSResponse* thisObject = jsCast<JSResponse*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); Base::visitChildren(thisObject, visitor); + if (auto* ptr = thisObject->wrapped()) { visitor.reportExtraMemoryVisited(Response__estimatedSize(ptr)); } @@ -3938,7 +3920,6 @@ JSBlob* JSBlob::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Stru return ptr; } - extern "C" void* Blob__fromJS(JSC::EncodedJSValue value) { JSBlob* object = JSC::jsDynamicCast<JSBlob*>(JSValue::decode(value)); if (!object) diff --git a/src/bun.js/bindings/ZigGeneratedClasses.h b/src/bun.js/bindings/ZigGeneratedClasses.h index 7b2afdf2d..b51637efa 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses.h +++ b/src/bun.js/bindings/ZigGeneratedClasses.h @@ -66,12 +66,9 @@ class JSSubprocess final : public JSC::JSDestructibleObject { DECLARE_VISIT_CHILDREN; - mutable JSC::WriteBarrier<JSC::Unknown> m_exited; -mutable JSC::WriteBarrier<JSC::Unknown> m_readable; -mutable JSC::WriteBarrier<JSC::Unknown> m_stderr; + mutable JSC::WriteBarrier<JSC::Unknown> m_stderr; mutable JSC::WriteBarrier<JSC::Unknown> m_stdin; mutable JSC::WriteBarrier<JSC::Unknown> m_stdout; -mutable JSC::WriteBarrier<JSC::Unknown> m_writable; }; class JSSubprocessPrototype final : public JSC::JSNonFinalObject { public: diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index 331d939e2..b395e8377 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -226,7 +226,6 @@ pub const EventLoop = struct { waker: ?AsyncIO.Waker = null, start_server_on_next_tick: bool = false, defer_count: std.atomic.Atomic(usize) = std.atomic.Atomic(usize).init(0), - pending_processes_to_exit: std.AutoArrayHashMap(*JSC.Subprocess, void) = undefined, pub const Queue = std.fifo.LinearFifo(Task, .Dynamic); @@ -336,7 +335,7 @@ pub const EventLoop = struct { pub fn autoTick(this: *EventLoop) void { if (this.virtual_machine.uws_event_loop.?.num_polls > 0 or this.virtual_machine.uws_event_loop.?.active > 0) { this.virtual_machine.uws_event_loop.?.tick(); - this.afterUSocketsTick(); + // this.afterUSocketsTick(); } } @@ -433,16 +432,6 @@ pub const EventLoop = struct { } } - pub fn afterUSocketsTick(this: *EventLoop) void { - const processes = this.pending_processes_to_exit.keys(); - if (processes.len > 0) { - for (processes) |process| { - process.onExitNotification(); - } - this.pending_processes_to_exit.clearRetainingCapacity(); - } - } - pub fn enqueueTaskConcurrent(this: *EventLoop, task: *ConcurrentTask) void { JSC.markBinding(); @@ -476,10 +465,7 @@ pub const Poller = struct { var loader = ptr.as(JSC.Subprocess); loader.poll_ref.deactivate(loop); - - // kqueue sends the same notification multiple times in the same tick potentially - // so we have to dedupe it - _ = loader.globalThis.bunVM().eventLoop().pending_processes_to_exit.getOrPut(loader) catch unreachable; + loader.onExitNotification(); }, @field(Pollable.Tag, "BufferedInput") => { var loader = ptr.as(JSC.Subprocess.BufferedInput); @@ -523,9 +509,7 @@ pub const Poller = struct { var loader = ptr.as(JSC.Subprocess); loader.poll_ref.deactivate(loop); - // kqueue sends the same notification multiple times in the same tick potentially - // so we have to dedupe it - _ = loader.globalThis.bunVM().eventLoop().pending_processes_to_exit.getOrPut(loader) catch unreachable; + loader.onExitNotification(); }, @field(Pollable.Tag, "FileSink") => { var loader = ptr.as(JSC.WebCore.FileSink); @@ -611,7 +595,7 @@ pub const Poller = struct { .data = 0, .fflags = 0, .udata = @ptrToInt(Pollable.init(ctx).ptr()), - .flags = std.c.EV_ADD | std.c.EV_ENABLE | std.c.EV_ONESHOT, + .flags = std.c.EV_ADD | std.c.EV_ONESHOT, .ext = .{ 0, 0 }, }, .write => .{ @@ -620,7 +604,7 @@ pub const Poller = struct { .data = 0, .fflags = 0, .udata = @ptrToInt(Pollable.init(ctx).ptr()), - .flags = std.c.EV_ADD | std.c.EV_ENABLE | std.c.EV_ONESHOT, + .flags = std.c.EV_ADD | std.c.EV_ONESHOT, .ext = .{ 0, 0 }, }, .process => .{ @@ -629,7 +613,7 @@ pub const Poller = struct { .data = 0, .fflags = std.c.NOTE_EXIT, .udata = @ptrToInt(Pollable.init(ctx).ptr()), - .flags = std.c.EV_ADD | std.c.EV_ENABLE | std.c.EV_ONESHOT, + .flags = std.c.EV_ADD, .ext = .{ 0, 0 }, }, }; @@ -640,16 +624,24 @@ pub const Poller = struct { // The kevent() system call returns the number of events placed in // the eventlist, up to the value given by nevents. If the time // limit expires, then kevent() returns 0. - const rc = std.os.system.kevent64( - watcher_fd, - &changelist, - 1, - // The same array may be used for the changelist and eventlist. - &changelist, - 1, - KEVENT_FLAG_ERROR_EVENTS, - &timeout, - ); + const rc = rc: { + while (true) { + const rc = std.os.system.kevent64( + watcher_fd, + &changelist, + 1, + // The same array may be used for the changelist and eventlist. + &changelist, + 1, + KEVENT_FLAG_ERROR_EVENTS, + &timeout, + ); + + if (std.c.getErrno(rc) == .INTR) continue; + break :rc rc; + } + }; + // If an error occurs while // processing an element of the changelist and there is enough room // in the eventlist, then the event will be placed in the eventlist @@ -664,6 +656,7 @@ pub const Poller = struct { if (errno == .SUCCESS) { ctx.poll_ref.activate(this.loop.?); + return JSC.Maybe(void).success; } diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 8fccee097..6fc8984f8 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -577,7 +577,6 @@ pub const VirtualMachine = struct { VirtualMachine.vm.regular_event_loop.tasks = EventLoop.Queue.init( default_allocator, ); - VirtualMachine.vm.regular_event_loop.pending_processes_to_exit = std.AutoArrayHashMap(*JSC.Subprocess, void).init(allocator); VirtualMachine.vm.regular_event_loop.tasks.ensureUnusedCapacity(64) catch unreachable; VirtualMachine.vm.regular_event_loop.concurrent_tasks = .{}; VirtualMachine.vm.event_loop = &VirtualMachine.vm.regular_event_loop; |