mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-02-04 14:33:47 +00:00
Add finalizer mode
When a type is finalized by V8, it's because it's fallen out of scope. When a type is finalized by Zig, it's because the Context is being shutdown. Those are two different environments and might require distinct cleanup logic. Specifically, a zig-initiated finalization needs to consider that the page and context are being shutdown. It isn't necessarily safe to execute JavaScript at this point, and thus, not safe to execute a callback (on_error, on_abort, ready_state_change, ...).
This commit is contained in:
@@ -92,11 +92,11 @@ pub fn Builder(comptime T: type) type {
|
|||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finalizer(comptime func: *const fn (self: *T) void) Finalizer {
|
pub fn finalizer(comptime func: *const fn (self: *T, comptime shutdown: bool) void) Finalizer {
|
||||||
return .{
|
return .{
|
||||||
.from_zig = struct {
|
.from_zig = struct {
|
||||||
fn wrap(ptr: *anyopaque) void {
|
fn wrap(ptr: *anyopaque) void {
|
||||||
func(@ptrCast(@alignCast(ptr)));
|
func(@ptrCast(@alignCast(ptr)), true);
|
||||||
}
|
}
|
||||||
}.wrap,
|
}.wrap,
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ pub fn Builder(comptime T: type) type {
|
|||||||
if (!ctx.identity_map.contains(@intFromPtr(ptr))) {
|
if (!ctx.identity_map.contains(@intFromPtr(ptr))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
func(self);
|
func(self, false);
|
||||||
ctx.release(ptr);
|
ctx.release(ptr);
|
||||||
}
|
}
|
||||||
}.wrap,
|
}.wrap,
|
||||||
|
|||||||
@@ -90,9 +90,13 @@ pub fn init(page: *Page) !*XMLHttpRequest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *XMLHttpRequest) void {
|
pub fn deinit(self: *XMLHttpRequest, comptime shutdown: bool) void {
|
||||||
if (self._transfer) |transfer| {
|
if (self._transfer) |transfer| {
|
||||||
transfer.terminate();
|
if (shutdown) {
|
||||||
|
transfer.terminate();
|
||||||
|
} else {
|
||||||
|
transfer.abort(error.Abort);
|
||||||
|
}
|
||||||
self._transfer = null;
|
self._transfer = null;
|
||||||
}
|
}
|
||||||
self._page.releaseArena(self._arena);
|
self._page.releaseArena(self._arena);
|
||||||
|
|||||||
@@ -371,7 +371,7 @@ fn makeTransfer(self: *Client, req: Request) !*Transfer {
|
|||||||
return transfer;
|
return transfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn requestFailed(self: *Client, transfer: *Transfer, err: anyerror) void {
|
fn requestFailed(self: *Client, transfer: *Transfer, err: anyerror, comptime execute_callback: bool) void {
|
||||||
// this shouldn't happen, we'll crash in debug mode. But in release, we'll
|
// this shouldn't happen, we'll crash in debug mode. But in release, we'll
|
||||||
// just noop this state.
|
// just noop this state.
|
||||||
if (comptime IS_DEBUG) {
|
if (comptime IS_DEBUG) {
|
||||||
@@ -390,7 +390,9 @@ fn requestFailed(self: *Client, transfer: *Transfer, err: anyerror) void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer.req.error_callback(transfer.ctx, err);
|
if (execute_callback) {
|
||||||
|
transfer.req.error_callback(transfer.ctx, err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restrictive since it'll only work if there are no inflight requests. In some
|
// Restrictive since it'll only work if there are no inflight requests. In some
|
||||||
@@ -600,7 +602,7 @@ fn processMessages(self: *Client) !bool {
|
|||||||
if (!transfer._header_done_called) {
|
if (!transfer._header_done_called) {
|
||||||
const proceed = transfer.headerDoneCallback(easy) catch |err| {
|
const proceed = transfer.headerDoneCallback(easy) catch |err| {
|
||||||
log.err(.http, "header_done_callback", .{ .err = err });
|
log.err(.http, "header_done_callback", .{ .err = err });
|
||||||
self.requestFailed(transfer, err);
|
self.requestFailed(transfer, err, true);
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if (!proceed) {
|
if (!proceed) {
|
||||||
@@ -611,7 +613,7 @@ fn processMessages(self: *Client) !bool {
|
|||||||
transfer.req.done_callback(transfer.ctx) catch |err| {
|
transfer.req.done_callback(transfer.ctx) catch |err| {
|
||||||
// transfer isn't valid at this point, don't use it.
|
// transfer isn't valid at this point, don't use it.
|
||||||
log.err(.http, "done_callback", .{ .err = err });
|
log.err(.http, "done_callback", .{ .err = err });
|
||||||
self.requestFailed(transfer, err);
|
self.requestFailed(transfer, err, true);
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -622,7 +624,7 @@ fn processMessages(self: *Client) !bool {
|
|||||||
}
|
}
|
||||||
processed = true;
|
processed = true;
|
||||||
} else |err| {
|
} else |err| {
|
||||||
self.requestFailed(transfer, err);
|
self.requestFailed(transfer, err, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return processed;
|
return processed;
|
||||||
@@ -972,7 +974,7 @@ pub const Transfer = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn abort(self: *Transfer, err: anyerror) void {
|
pub fn abort(self: *Transfer, err: anyerror) void {
|
||||||
self.client.requestFailed(self, err);
|
self.client.requestFailed(self, err, true);
|
||||||
if (self._handle != null) {
|
if (self._handle != null) {
|
||||||
self.client.endTransfer(self);
|
self.client.endTransfer(self);
|
||||||
}
|
}
|
||||||
@@ -980,6 +982,7 @@ pub const Transfer = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn terminate(self: *Transfer) void {
|
pub fn terminate(self: *Transfer) void {
|
||||||
|
self.client.requestFailed(self, error.Shutdown, false);
|
||||||
if (self._handle != null) {
|
if (self._handle != null) {
|
||||||
self.client.endTransfer(self);
|
self.client.endTransfer(self);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user