Ensure page background tasks are re-registered on reset

This commit is contained in:
Karl Seguin
2025-10-09 16:29:09 +08:00
parent 852c30b2e5
commit 75e0637d2d
3 changed files with 32 additions and 23 deletions

View File

@@ -37,8 +37,10 @@ pub fn init(allocator: Allocator) Scheduler {
} }
pub fn reset(self: *Scheduler) void { pub fn reset(self: *Scheduler) void {
self.high_priority.clearRetainingCapacity(); // Our allocator is the page arena, it's been reset. We cannot use
self.low_priority.clearRetainingCapacity(); // clearAndRetainCapacity, since that space is no longer ours
self.high_priority.clearAndFree();
self.low_priority.clearAndFree();
} }
const AddOpts = struct { const AddOpts = struct {

View File

@@ -138,10 +138,7 @@ fn getThis(self: *const Function) v8.Object {
return self.this orelse self.context.v8_context.getGlobal(); return self.this orelse self.context.v8_context.getGlobal();
} }
// debug/helper to print the source of the JS callback pub fn src(self: *const Function) ![]const u8 {
pub fn printFunc(self: Function) !void {
const context = self.context;
const value = self.func.castToFunction().toValue(); const value = self.func.castToFunction().toValue();
const src = try js.valueToString(context.call_arena, value, context.isolate, context.v8_context); return self.context.valueToString(value, .{});
std.debug.print("{s}\n", .{src});
} }

View File

@@ -24,6 +24,7 @@ const Allocator = std.mem.Allocator;
const Dump = @import("dump.zig"); const Dump = @import("dump.zig");
const State = @import("State.zig"); const State = @import("State.zig");
const Mime = @import("mime.zig").Mime; const Mime = @import("mime.zig").Mime;
const Browser = @import("browser.zig").Browser;
const Session = @import("session.zig").Session; const Session = @import("session.zig").Session;
const Renderer = @import("renderer.zig").Renderer; const Renderer = @import("renderer.zig").Renderer;
const Window = @import("html/window.zig").Window; const Window = @import("html/window.zig").Window;
@@ -146,11 +147,7 @@ pub const Page = struct {
self.js = try session.executor.createContext(self, true, js.GlobalMissingCallback.init(&self.polyfill_loader)); self.js = try session.executor.createContext(self, true, js.GlobalMissingCallback.init(&self.polyfill_loader));
try polyfill.preload(self.arena, self.js); try polyfill.preload(self.arena, self.js);
try self.scheduler.add(self, runMicrotasks, 5, .{ .name = "page.microtasks" }); try self.registerBackgroundTasks();
// message loop must run only non-test env
if (comptime !builtin.is_test) {
try self.scheduler.add(self, runMessageLoop, 5, .{ .name = "page.messageLoop" });
}
} }
pub fn deinit(self: *Page) void { pub fn deinit(self: *Page) void {
@@ -160,7 +157,7 @@ pub const Page = struct {
self.script_manager.deinit(); self.script_manager.deinit();
} }
fn reset(self: *Page) void { fn reset(self: *Page) !void {
// Force running the micro task to drain the queue. // Force running the micro task to drain the queue.
self.session.browser.env.runMicrotasks(); self.session.browser.env.runMicrotasks();
@@ -171,18 +168,31 @@ pub const Page = struct {
self.load_state = .parsing; self.load_state = .parsing;
self.mode = .{ .pre = {} }; self.mode = .{ .pre = {} };
_ = self.session.browser.page_arena.reset(.{ .retain_with_limit = 1 * 1024 * 1024 }); _ = self.session.browser.page_arena.reset(.{ .retain_with_limit = 1 * 1024 * 1024 });
try self.registerBackgroundTasks();
} }
fn runMicrotasks(ctx: *anyopaque) ?u32 { fn registerBackgroundTasks(self: *Page) !void {
const self: *Page = @ptrCast(@alignCast(ctx)); if (comptime builtin.is_test) {
self.session.browser.runMicrotasks(); // HTML test runner manually calls these as necessary
return 5; return;
} }
fn runMessageLoop(ctx: *anyopaque) ?u32 { try self.scheduler.add(self.session.browser, struct {
const self: *Page = @ptrCast(@alignCast(ctx)); fn runMicrotasks(ctx: *anyopaque) ?u32 {
self.session.browser.runMessageLoop(); const b: *Browser = @ptrCast(@alignCast(ctx));
return 100; b.runMicrotasks();
return 5;
}
}.runMicrotasks, 5, .{ .name = "page.microtasks" });
try self.scheduler.add(self.session.browser, struct {
fn runMessageLoop(ctx: *anyopaque) ?u32 {
const b: *Browser = @ptrCast(@alignCast(ctx));
b.runMessageLoop();
return 100;
}
}.runMessageLoop, 5, .{ .name = "page.messageLoop" });
} }
pub const DumpOpts = struct { pub const DumpOpts = struct {
@@ -529,7 +539,7 @@ pub const Page = struct {
if (self.mode != .pre) { if (self.mode != .pre) {
// it's possible for navigate to be called multiple times on the // it's possible for navigate to be called multiple times on the
// same page (via CDP). We want to reset the page between each call. // same page (via CDP). We want to reset the page between each call.
self.reset(); try self.reset();
} }
log.info(.http, "navigate", .{ log.info(.http, "navigate", .{