aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-06-22 06:43:57 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-06-22 06:56:47 -0700
commit92aeb0af5594516d6444c9fcc69d56682e34771b (patch)
tree4ff007b8f345e1ccdf25839858bf104ada1cb5f0 /src
parent759bfadb933266de99c4bd7cf7c4c92b8dd97576 (diff)
downloadbun-92aeb0af5594516d6444c9fcc69d56682e34771b.tar.gz
bun-92aeb0af5594516d6444c9fcc69d56682e34771b.tar.zst
bun-92aeb0af5594516d6444c9fcc69d56682e34771b.zip
Add a way to schedule microtasks from C++
Diffstat (limited to 'src')
-rw-r--r--src/javascript/jsc/bindings/ScriptExecutionContext.h75
-rw-r--r--src/javascript/jsc/bindings/ZigGlobalObject.cpp11
-rw-r--r--src/javascript/jsc/bindings/ZigGlobalObject.h5
-rw-r--r--src/javascript/jsc/bindings/webcore/JSCallbackData.h4
-rw-r--r--src/javascript/jsc/event_loop.zig17
5 files changed, 77 insertions, 35 deletions
diff --git a/src/javascript/jsc/bindings/ScriptExecutionContext.h b/src/javascript/jsc/bindings/ScriptExecutionContext.h
index e5644c2fc..72837368e 100644
--- a/src/javascript/jsc/bindings/ScriptExecutionContext.h
+++ b/src/javascript/jsc/bindings/ScriptExecutionContext.h
@@ -14,8 +14,12 @@
namespace uWS {
template<bool isServer, bool isClient, typename UserData>
struct WebSocketContext;
-
}
+
+#ifndef ZIG_GLOBAL_OBJECT_DEFINED
+#include "ZigGlobalObject.h"
+#endif
+
struct us_socket_t;
struct us_socket_context_t;
struct us_loop_t;
@@ -24,42 +28,48 @@ namespace WebCore {
class WebSocket;
-class ScriptExecutionContext : public CanMakeWeakPtr<ScriptExecutionContext> {
-public:
- class Task {
- WTF_MAKE_FAST_ALLOCATED;
+class ScriptExecutionContext;
- public:
- enum CleanupTaskTag { CleanupTask };
+class EventLoopTask {
+ WTF_MAKE_FAST_ALLOCATED;
- template<typename T, typename = typename std::enable_if<!std::is_base_of<Task, T>::value && std::is_convertible<T, Function<void(ScriptExecutionContext&)>>::value>::type>
- Task(T task)
- : m_task(WTFMove(task))
- , m_isCleanupTask(false)
- {
- }
+public:
+ enum CleanupTaskTag { CleanupTask };
- Task(Function<void()>&& task)
- : m_task([task = WTFMove(task)](ScriptExecutionContext&) { task(); })
- , m_isCleanupTask(false)
- {
- }
+ template<typename T, typename = typename std::enable_if<!std::is_base_of<EventLoopTask, T>::value && std::is_convertible<T, Function<void(ScriptExecutionContext&)>>::value>::type>
+ EventLoopTask(T task)
+ : m_task(WTFMove(task))
+ , m_isCleanupTask(false)
+ {
+ }
- template<typename T, typename = typename std::enable_if<std::is_convertible<T, Function<void(ScriptExecutionContext&)>>::value>::type>
- Task(CleanupTaskTag, T task)
- : m_task(WTFMove(task))
- , m_isCleanupTask(true)
- {
- }
+ EventLoopTask(Function<void()>&& task)
+ : m_task([task = WTFMove(task)](ScriptExecutionContext&) { task(); })
+ , m_isCleanupTask(false)
+ {
+ }
- void performTask(ScriptExecutionContext& context) { m_task(context); }
- bool isCleanupTask() const { return m_isCleanupTask; }
+ template<typename T, typename = typename std::enable_if<std::is_convertible<T, Function<void(ScriptExecutionContext&)>>::value>::type>
+ EventLoopTask(CleanupTaskTag, T task)
+ : m_task(WTFMove(task))
+ , m_isCleanupTask(true)
+ {
+ }
- protected:
- Function<void(ScriptExecutionContext&)> m_task;
- bool m_isCleanupTask;
- };
+ void performTask(ScriptExecutionContext& context)
+ {
+ m_task(context);
+ delete this;
+ }
+ bool isCleanupTask() const { return m_isCleanupTask; }
+protected:
+ Function<void(ScriptExecutionContext&)> m_task;
+ bool m_isCleanupTask;
+};
+
+class ScriptExecutionContext : public CanMakeWeakPtr<ScriptExecutionContext> {
+public:
public:
ScriptExecutionContext(JSC::VM* vm, JSC::JSGlobalObject* globalObject)
: m_vm(vm)
@@ -96,9 +106,10 @@ public:
// {
// }
- void postTask(Task&& task)
+ void postTask(Function<void(ScriptExecutionContext&)>&& lambda)
{
-
+ auto* task = new EventLoopTask(WTFMove(lambda));
+ reinterpret_cast<Zig::GlobalObject*>(m_globalObject)->queueTask(task);
} // Executes the task on context's thread asynchronously.
template<typename... Arguments>
diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.cpp b/src/javascript/jsc/bindings/ZigGlobalObject.cpp
index 53872f325..e99f9a1cc 100644
--- a/src/javascript/jsc/bindings/ZigGlobalObject.cpp
+++ b/src/javascript/jsc/bindings/ZigGlobalObject.cpp
@@ -2107,6 +2107,17 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
visitor.addOpaqueRoot(context);
}
+extern "C" void Bun__queueMicrotask(JSC__JSGlobalObject*, WebCore::EventLoopTask* task);
+extern "C" void Bun__performTask(Zig::GlobalObject* globalObject, WebCore::EventLoopTask* task)
+{
+ task->performTask(*globalObject->scriptExecutionContext());
+}
+
+void GlobalObject::queueTask(WebCore::EventLoopTask* task)
+{
+ Bun__queueMicrotask(this, task);
+}
+
DEFINE_VISIT_CHILDREN(GlobalObject);
// void GlobalObject::destroy(JSCell* cell)
diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.h b/src/javascript/jsc/bindings/ZigGlobalObject.h
index 4f8a7871e..41556e639 100644
--- a/src/javascript/jsc/bindings/ZigGlobalObject.h
+++ b/src/javascript/jsc/bindings/ZigGlobalObject.h
@@ -13,6 +13,7 @@ class LazyClassStructure;
namespace WebCore {
class ScriptExecutionContext;
class DOMGuardedObject;
+class EventLoopTask;
}
#include "root.h"
@@ -37,6 +38,8 @@ namespace Zig {
using JSDOMStructureMap = HashMap<const JSC::ClassInfo*, JSC::WriteBarrier<JSC::Structure>>;
using DOMGuardedObjectSet = HashSet<WebCore::DOMGuardedObject*>;
+#define ZIG_GLOBAL_OBJECT_DEFINED
+
class GlobalObject : public JSC::JSGlobalObject {
using Base = JSC::JSGlobalObject;
@@ -111,6 +114,8 @@ public:
WebCore::ScriptExecutionContext* scriptExecutionContext();
WebCore::ScriptExecutionContext* scriptExecutionContext() const;
+ void queueTask(WebCore::EventLoopTask* task);
+
JSDOMStructureMap& structures() WTF_REQUIRES_LOCK(m_gcLock) { return m_structures; }
JSDOMStructureMap& structures(NoLockingNecessaryTag) WTF_IGNORES_THREAD_SAFETY_ANALYSIS
{
diff --git a/src/javascript/jsc/bindings/webcore/JSCallbackData.h b/src/javascript/jsc/bindings/webcore/JSCallbackData.h
index 07114ce41..7ddd70ba7 100644
--- a/src/javascript/jsc/bindings/webcore/JSCallbackData.h
+++ b/src/javascript/jsc/bindings/webcore/JSCallbackData.h
@@ -109,11 +109,11 @@ private:
JSC::Weak<JSC::JSObject> m_callback;
};
-class DeleteCallbackDataTask : public ScriptExecutionContext::Task {
+class DeleteCallbackDataTask : public EventLoopTask {
public:
template<typename CallbackDataType>
explicit DeleteCallbackDataTask(CallbackDataType* data)
- : ScriptExecutionContext::Task(ScriptExecutionContext::Task::CleanupTask, [data = std::unique_ptr<CallbackDataType>(data)](ScriptExecutionContext&) {
+ : EventLoopTask(EventLoopTask::CleanupTask, [data = std::unique_ptr<CallbackDataType>(data)](ScriptExecutionContext&) {
})
{
}
diff --git a/src/javascript/jsc/event_loop.zig b/src/javascript/jsc/event_loop.zig
index f7ba4c49e..2623551f6 100644
--- a/src/javascript/jsc/event_loop.zig
+++ b/src/javascript/jsc/event_loop.zig
@@ -259,6 +259,14 @@ pub const AnyTask = struct {
};
}
};
+
+pub const CppTask = opaque {
+ extern fn Bun__performTask(globalObject: *JSGlobalObject, task: *CppTask) void;
+ pub fn run(this: *CppTask, global: *JSGlobalObject) void {
+ JSC.markBinding();
+ Bun__performTask(global, this);
+ }
+};
const ThreadSafeFunction = JSC.napi.ThreadSafeFunction;
const MicrotaskForDefaultGlobalObject = JSC.MicrotaskForDefaultGlobalObject;
// const PromiseTask = JSInternalPromise.Completion.PromiseTask;
@@ -274,6 +282,7 @@ pub const Task = TaggedPointerUnion(.{
AnyTask,
napi_async_work,
ThreadSafeFunction,
+ CppTask,
// PromiseTask,
// TimeoutTasklet,
});
@@ -287,7 +296,7 @@ pub const EventLoop = struct {
concurrent_lock: Lock = Lock.init(),
global: *JSGlobalObject = undefined,
virtual_machine: *VirtualMachine = undefined,
- pub const Queue = bun.LinearFifo(Task, .Dynamic);
+ pub const Queue = std.fifo.LinearFifo(Task, .Dynamic);
pub fn tickWithCount(this: *EventLoop) u32 {
var finished: u32 = 0;
@@ -357,6 +366,12 @@ pub const EventLoop = struct {
finished += 1;
vm_.active_tasks -|= 1;
},
+ @field(Task.Tag, @typeName(CppTask)) => {
+ var any: *CppTask = task.get(CppTask).?;
+ any.run(global);
+ finished += 1;
+ vm_.active_tasks -|= 1;
+ },
else => if (Environment.allow_assert) {
bun.Output.prettyln("\nUnexpected tag: {s}\n", .{@tagName(task.tag())});
} else unreachable,