aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-12-02 20:48:57 -0800
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-12-02 20:48:57 -0800
commitfe4f39fd17b8ffbb809871b9e4c6550063f15657 (patch)
tree94e3b98898cd9d8b62804cec72fc81776a841135
parent9cc03cd71a2e42b489b8b0c837cdb0d1b1d3fa0b (diff)
downloadbun-fe4f39fd17b8ffbb809871b9e4c6550063f15657.tar.gz
bun-fe4f39fd17b8ffbb809871b9e4c6550063f15657.tar.zst
bun-fe4f39fd17b8ffbb809871b9e4c6550063f15657.zip
Add `AbortSignal.timeout`
-rw-r--r--src/bun.js/bindings/ScriptExecutionContext.h9
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp6
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.h1
-rw-r--r--src/bun.js/bindings/webcore/AbortSignal.cpp26
-rw-r--r--src/bun.js/event_loop.zig14
-rw-r--r--src/bun.js/javascript.zig5
-rw-r--r--test/bun.js/abort-signal-timeout.test.js12
7 files changed, 60 insertions, 13 deletions
diff --git a/src/bun.js/bindings/ScriptExecutionContext.h b/src/bun.js/bindings/ScriptExecutionContext.h
index 1643820dd..5f6c56a90 100644
--- a/src/bun.js/bindings/ScriptExecutionContext.h
+++ b/src/bun.js/bindings/ScriptExecutionContext.h
@@ -132,6 +132,15 @@ public:
reinterpret_cast<Zig::GlobalObject*>(m_globalObject)->queueTask(task);
} // Executes the task on context's thread asynchronously.
+ void postTaskOnTimeout(EventLoopTask* task, Seconds timeout)
+ {
+ reinterpret_cast<Zig::GlobalObject*>(m_globalObject)->queueTaskOnTimeout(task, static_cast<int>(timeout.milliseconds()));
+ } // Executes the task on context's thread asynchronously.
+ void postTaskOnTimeout(Function<void(ScriptExecutionContext&)>&& lambda, Seconds timeout)
+ {
+ auto* task = new EventLoopTask(WTFMove(lambda));
+ postTaskOnTimeout(task, timeout);
+ }
template<typename... Arguments>
void postCrossThreadTask(Arguments&&... arguments)
{
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index 50a07f06e..775382d82 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -3368,6 +3368,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
}
extern "C" void Bun__queueTask(JSC__JSGlobalObject*, WebCore::EventLoopTask* task);
+extern "C" void Bun__queueTaskWithTimeout(JSC__JSGlobalObject*, WebCore::EventLoopTask* task, int timeout);
extern "C" void Bun__queueTaskConcurrently(JSC__JSGlobalObject*, WebCore::EventLoopTask* task);
extern "C" void Bun__performTask(Zig::GlobalObject* globalObject, WebCore::EventLoopTask* task)
{
@@ -3379,6 +3380,11 @@ void GlobalObject::queueTask(WebCore::EventLoopTask* task)
Bun__queueTask(this, task);
}
+void GlobalObject::queueTaskOnTimeout(WebCore::EventLoopTask* task, int timeout)
+{
+ Bun__queueTaskWithTimeout(this, task, timeout);
+}
+
void GlobalObject::queueTaskConcurrently(WebCore::EventLoopTask* task)
{
Bun__queueTaskConcurrently(this, task);
diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h
index bcc6cb804..90d67d34f 100644
--- a/src/bun.js/bindings/ZigGlobalObject.h
+++ b/src/bun.js/bindings/ZigGlobalObject.h
@@ -149,6 +149,7 @@ public:
WebCore::ScriptExecutionContext* scriptExecutionContext() const;
void queueTask(WebCore::EventLoopTask* task);
+ void queueTaskOnTimeout(WebCore::EventLoopTask* task, int timeout);
void queueTaskConcurrently(WebCore::EventLoopTask* task);
JSDOMStructureMap& structures() WTF_REQUIRES_LOCK(m_gcLock) { return m_structures; }
diff --git a/src/bun.js/bindings/webcore/AbortSignal.cpp b/src/bun.js/bindings/webcore/AbortSignal.cpp
index 822595064..aa4143ebd 100644
--- a/src/bun.js/bindings/webcore/AbortSignal.cpp
+++ b/src/bun.js/bindings/webcore/AbortSignal.cpp
@@ -59,19 +59,19 @@ Ref<AbortSignal> AbortSignal::abort(JSDOMGlobalObject& globalObject, ScriptExecu
Ref<AbortSignal> AbortSignal::timeout(ScriptExecutionContext& context, uint64_t milliseconds)
{
auto signal = adoptRef(*new AbortSignal(&context));
- // signal->setHasActiveTimeoutTimer(true);
- // auto action = [signal](ScriptExecutionContext& context) mutable {
- // signal->setHasActiveTimeoutTimer(false);
-
- // auto* globalObject = JSC::jsCast<JSDOMGlobalObject*>(context.globalObject());
- // if (!globalObject)
- // return;
-
- // auto& vm = globalObject->vm();
- // Locker locker { vm.apiLock() };
- // signal->signalAbort(toJS(globalObject, globalObject, DOMException::create(TimeoutError)));
- // };
- // DOMTimer::install(context, WTFMove(action), Seconds::fromMilliseconds(milliseconds), true);
+ signal->setHasActiveTimeoutTimer(true);
+ auto action = [signal](ScriptExecutionContext& context) mutable {
+ signal->setHasActiveTimeoutTimer(false);
+
+ auto* globalObject = JSC::jsCast<JSDOMGlobalObject*>(context.jsGlobalObject());
+ if (!globalObject)
+ return;
+
+ auto& vm = globalObject->vm();
+ Locker locker { vm.apiLock() };
+ signal->signalAbort(toJS(globalObject, globalObject, DOMException::create(TimeoutError)));
+ };
+ context.postTaskOnTimeout(WTFMove(action), Seconds::fromMilliseconds(milliseconds));
return signal;
}
diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig
index 0e2d16486..6f7f18f0a 100644
--- a/src/bun.js/event_loop.zig
+++ b/src/bun.js/event_loop.zig
@@ -566,6 +566,20 @@ pub const EventLoop = struct {
this.tasks.writeItem(task) catch unreachable;
}
+ pub fn enqueueTaskWithTimeout(this: *EventLoop, task: Task, timeout: i32) void {
+ // TODO: make this more efficient!
+ var loop = this.virtual_machine.uws_event_loop orelse @panic("EventLoop.enqueueTaskWithTimeout: uSockets event loop is not initialized");
+ var timer = uws.Timer.createFallthrough(loop, task.ptr());
+ timer.set(task.ptr(), callTask, timeout, 0);
+ }
+
+ pub fn callTask(timer: *uws.Timer) callconv(.C) void {
+ var task = Task.from(timer.as(*anyopaque));
+ timer.deinit();
+
+ JSC.VirtualMachine.vm.enqueueTask(task);
+ }
+
pub fn ensureWaker(this: *EventLoop) void {
JSC.markBinding(@src());
if (this.virtual_machine.uws_event_loop == null) {
diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig
index f1f77aeaa..c9b165def 100644
--- a/src/bun.js/javascript.zig
+++ b/src/bun.js/javascript.zig
@@ -280,6 +280,7 @@ comptime {
_ = Bun__onDidAppendPlugin;
_ = Bun__readOriginTimerStart;
_ = Bun__reportUnhandledError;
+ _ = Bun__queueTaskWithTimeout;
}
}
@@ -289,6 +290,10 @@ pub export fn Bun__queueTask(global: *JSGlobalObject, task: *JSC.CppTask) void {
global.bunVM().eventLoop().enqueueTask(Task.init(task));
}
+pub export fn Bun__queueTaskWithTimeout(global: *JSGlobalObject, task: *JSC.CppTask, milliseconds: i32) void {
+ global.bunVM().eventLoop().enqueueTaskWithTimeout(Task.init(task), milliseconds);
+}
+
pub export fn Bun__reportUnhandledError(globalObject: *JSGlobalObject, value: JSValue) callconv(.C) JSValue {
var jsc_vm = globalObject.bunVM();
jsc_vm.onUnhandledError(globalObject, value);
diff --git a/test/bun.js/abort-signal-timeout.test.js b/test/bun.js/abort-signal-timeout.test.js
new file mode 100644
index 000000000..38705312e
--- /dev/null
+++ b/test/bun.js/abort-signal-timeout.test.js
@@ -0,0 +1,12 @@
+import { expect, test } from "bun:test";
+
+test("AbortSignal.timeout", (done) => {
+ const abort = AbortSignal.timeout(10);
+ abort.addEventListener("abort", (event) => {
+ done();
+ });
+
+ // AbortSignal.timeout doesn't keep the event loop / process alive
+ // so we set a no-op timeout
+ setTimeout(() => {}, 11);
+});