mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-08-01 02:06:17 -04:00
The main addition in this commit is that we hook into the Isolate's AddNearHeapLimitCallback callback and try to force the isolate to shutdown rather than letting v8 hit an OOM which would take down the entire process. In support of this, we now support a `--v8-max-heap-mb` command line option to set an explicit heap limit. As a simple way to test this feature, load a relatively heavy JS page with `--v8-max-heap-mb 1`. There's also a `--v8-flags-unsafe` which is a mechanism to pass arbitrary flags to v8 via its `SetFlagsFromString`. The parameter is called `unsafe` because some [of the many] configurable flags could conflict with how the snapshot is built and result in crashes. The snapshot creator also gains a `--v8-flags-unsafe` flag, so advance users COULD create their snapshot and run lightpanda with the same set of flags.
123 lines
3.7 KiB
Zig
123 lines
3.7 KiB
Zig
// Copyright (C) 2023-2026 Lightpanda (Selecy SAS)
|
|
//
|
|
// Francis Bouvier <francis@lightpanda.io>
|
|
// Pierre Tachoire <pierre@lightpanda.io>
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
const std = @import("std");
|
|
const lp = @import("lightpanda");
|
|
|
|
const Config = @import("Config.zig");
|
|
const Snapshot = @import("browser/js/Snapshot.zig");
|
|
const Platform = @import("browser/js/Platform.zig");
|
|
const Telemetry = @import("telemetry/telemetry.zig").Telemetry;
|
|
|
|
const Storage = @import("storage/Storage.zig");
|
|
const Network = @import("network/Network.zig");
|
|
pub const ArenaPool = @import("ArenaPool.zig");
|
|
|
|
const log = lp.log;
|
|
const Allocator = std.mem.Allocator;
|
|
|
|
const App = @This();
|
|
|
|
network: Network,
|
|
config: *const Config,
|
|
storage: Storage,
|
|
platform: Platform,
|
|
snapshot: Snapshot,
|
|
telemetry: Telemetry,
|
|
allocator: Allocator,
|
|
arena_pool: ArenaPool,
|
|
app_dir_path: ?[]const u8,
|
|
|
|
pub fn init(allocator: Allocator, config: *const Config) !*App {
|
|
const platform = try Platform.init(config.v8Flags());
|
|
errdefer platform.deinit();
|
|
|
|
const snapshot = try Snapshot.load();
|
|
errdefer snapshot.deinit();
|
|
|
|
var storage = try Storage.init(allocator, config);
|
|
errdefer storage.deinit(allocator);
|
|
|
|
const app = try allocator.create(App);
|
|
errdefer allocator.destroy(app);
|
|
|
|
app.* = .{
|
|
.config = config,
|
|
.allocator = allocator,
|
|
.platform = platform,
|
|
.snapshot = snapshot,
|
|
.storage = storage,
|
|
.network = undefined,
|
|
.app_dir_path = undefined,
|
|
.telemetry = undefined,
|
|
.arena_pool = undefined,
|
|
};
|
|
app.network = try Network.init(allocator, app, config);
|
|
errdefer app.network.deinit();
|
|
|
|
app.app_dir_path = getAndMakeAppDir(allocator);
|
|
|
|
app.telemetry = try Telemetry.init(app, config.mode, config.interactive());
|
|
errdefer app.telemetry.deinit(allocator);
|
|
|
|
app.arena_pool = ArenaPool.init(allocator, .{});
|
|
errdefer app.arena_pool.deinit();
|
|
|
|
return app;
|
|
}
|
|
|
|
pub fn shutdown(self: *const App) bool {
|
|
return self.network.shutdown.load(.acquire);
|
|
}
|
|
|
|
pub fn deinit(self: *App) void {
|
|
const allocator = self.allocator;
|
|
if (self.app_dir_path) |app_dir_path| {
|
|
allocator.free(app_dir_path);
|
|
self.app_dir_path = null;
|
|
}
|
|
self.telemetry.deinit(allocator);
|
|
self.network.deinit();
|
|
self.snapshot.deinit();
|
|
self.platform.deinit();
|
|
self.arena_pool.deinit();
|
|
self.storage.deinit(allocator);
|
|
|
|
allocator.destroy(self);
|
|
}
|
|
|
|
fn getAndMakeAppDir(allocator: Allocator) ?[]const u8 {
|
|
if (@import("builtin").is_test) {
|
|
return allocator.dupe(u8, "/tmp") catch unreachable;
|
|
}
|
|
const app_dir_path = std.fs.getAppDataDir(allocator, "lightpanda") catch |err| {
|
|
log.warn(.app, "get data dir", .{ .err = err });
|
|
return null;
|
|
};
|
|
|
|
std.fs.cwd().makePath(app_dir_path) catch |err| switch (err) {
|
|
error.PathAlreadyExists => return app_dir_path,
|
|
else => {
|
|
allocator.free(app_dir_path);
|
|
log.warn(.app, "create data dir", .{ .err = err, .path = app_dir_path });
|
|
return null;
|
|
},
|
|
};
|
|
return app_dir_path;
|
|
}
|