Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: single-tick non-tracking event loop runner #56

Closed
wants to merge 1 commit into from
Closed
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
4 changes: 0 additions & 4 deletions builtins/web/fetch/request-response.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -990,10 +990,6 @@ bool reader_for_outgoing_body_catch_handler(JSContext *cx, JS::HandleObject body
// `responseDone`. (Note that even though we encountered an error,
// `responseDone` is the right state: `respondedWithError` is for when sending
// a response at all failed.)
// TODO(TS): investigate why this is disabled.
// if (Response::is_instance(body_owner)) {
// FetchEvent::set_state(FetchEvent::instance(), FetchEvent::State::responseDone);
// }
return finish_outgoing_body_streaming(cx, body_owner);
}

Expand Down
12 changes: 12 additions & 0 deletions host-apis/wasi-0.2.0/host_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,18 @@ size_t api::AsyncTask::select(std::vector<AsyncTask *> &tasks) {
return ready_index;
}

std::optional<size_t> api::AsyncTask::ready(std::vector<api::AsyncTask *> &tasks) {
auto count = tasks.size();
for (size_t idx = 0; idx < count; ++idx) {
auto task = tasks.at(idx);
WASIHandle<host_api::Pollable>::Borrowed poll = { task->id() };
if (wasi_io_0_2_0_poll_method_pollable_ready(poll)) {
return idx;
}
}
return std::nullopt;
}

namespace host_api {

HostString::HostString(const char *c_str) {
Expand Down
5 changes: 5 additions & 0 deletions include/extension-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ class AsyncTask {
* Select for the next available ready task, providing the oldest ready first.
*/
static size_t select(std::vector<AsyncTask *> &handles);

/**
* Non-blocking check for a ready task, providing the oldest ready first, if any.
*/
static std::optional<size_t> ready(std::vector<AsyncTask *> &handles);
};

} // namespace api
Expand Down
31 changes: 22 additions & 9 deletions runtime/event_loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,32 +61,42 @@ bool EventLoop::run_event_loop(api::Engine *engine, double total_compute) {
queue.get().event_loop_running = true;
JSContext *cx = engine->cx();

while (true) {
do {
// Run a microtask checkpoint
js::RunJobs(cx);

if (JS_IsExceptionPending(cx)) {
exit_event_loop();
return false;
}
// if there is no interest in the event loop at all, just run one tick
if (interest_complete()) {
exit_event_loop();
return true;
}

const auto tasks = &queue.get().tasks;
size_t tasks_size = tasks->size();

if (tasks_size == 0) {
if (interest_complete()) {
break;
}
exit_event_loop();
tschneidereit marked this conversation as resolved.
Show resolved Hide resolved
MOZ_ASSERT(!interest_complete());
fprintf(stderr, "event loop error - both task and job queues are empty, but expected "
"operations did not resolve");
return false;
}

size_t task_idx;

// Select the next task to run according to event-loop semantics of oldest-first.
size_t task_idx = api::AsyncTask::select(*tasks);
if (interest_complete()) {
// Perform a non-blocking select in the case of there being no event loop interest
// (we are thus only performing a "single tick", but must still progress work that is ready)
std::optional<size_t> maybe_task_idx = api::AsyncTask::ready(*tasks);
if (!maybe_task_idx.has_value()) {
break;
tschneidereit marked this conversation as resolved.
Show resolved Hide resolved
}
task_idx = maybe_task_idx.value();
} else {
task_idx = api::AsyncTask::select(*tasks);
}

auto task = tasks->at(task_idx);
tasks->erase(tasks->begin() + task_idx);
Expand All @@ -95,7 +105,10 @@ bool EventLoop::run_event_loop(api::Engine *engine, double total_compute) {
exit_event_loop();
return false;
}
}
} while (!interest_complete());

exit_event_loop();
return true;
}

void EventLoop::init(JSContext *cx) { queue.init(cx); }
Expand Down
Loading