mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
terminal/new: pages must use mmap directly
This commit is contained in:
@ -92,7 +92,7 @@ pub fn init(
|
|||||||
// no errdefer because the pool deinit will clean up the page
|
// no errdefer because the pool deinit will clean up the page
|
||||||
|
|
||||||
page.* = .{
|
page.* = .{
|
||||||
.data = try Page.init(alloc, .{
|
.data = try Page.init(.{
|
||||||
.cols = cols,
|
.cols = cols,
|
||||||
.rows = @max(rows, page_min_rows),
|
.rows = @max(rows, page_min_rows),
|
||||||
.styles = page_default_styles,
|
.styles = page_default_styles,
|
||||||
@ -131,7 +131,7 @@ pub fn init(
|
|||||||
pub fn deinit(self: *PageList) void {
|
pub fn deinit(self: *PageList) void {
|
||||||
// Deallocate all the pages. We don't need to deallocate the list or
|
// Deallocate all the pages. We don't need to deallocate the list or
|
||||||
// nodes because they all reside in the pool.
|
// nodes because they all reside in the pool.
|
||||||
while (self.pages.popFirst()) |node| node.data.deinit(self.alloc);
|
while (self.pages.popFirst()) |node| node.data.deinit();
|
||||||
self.pool.deinit();
|
self.pool.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,10 +237,10 @@ pub fn grow(self: *PageList) !*List.Node {
|
|||||||
/// Create a new page node. This does not add it to the list.
|
/// Create a new page node. This does not add it to the list.
|
||||||
fn createPage(self: *PageList) !*List.Node {
|
fn createPage(self: *PageList) !*List.Node {
|
||||||
var page = try self.pool.create();
|
var page = try self.pool.create();
|
||||||
errdefer page.data.deinit(self.alloc);
|
errdefer page.data.deinit();
|
||||||
|
|
||||||
page.* = .{
|
page.* = .{
|
||||||
.data = try Page.init(self.alloc, .{
|
.data = try Page.init(.{
|
||||||
.cols = self.cols,
|
.cols = self.cols,
|
||||||
.rows = @max(self.rows, page_min_rows),
|
.rows = @max(self.rows, page_min_rows),
|
||||||
.styles = page_default_styles,
|
.styles = page_default_styles,
|
||||||
|
@ -112,11 +112,27 @@ pub const Page = struct {
|
|||||||
|
|
||||||
/// Initialize a new page, allocating the required backing memory.
|
/// Initialize a new page, allocating the required backing memory.
|
||||||
/// The size of the initialized page defaults to the full capacity.
|
/// The size of the initialized page defaults to the full capacity.
|
||||||
pub fn init(alloc: Allocator, cap: Capacity) !Page {
|
///
|
||||||
|
/// The backing memory is always allocated using mmap directly.
|
||||||
|
/// You cannot use custom allocators with this structure because
|
||||||
|
/// it is critical to performance that we use mmap.
|
||||||
|
pub fn init(cap: Capacity) !Page {
|
||||||
const l = layout(cap);
|
const l = layout(cap);
|
||||||
const backing = try alloc.alignedAlloc(u8, std.mem.page_size, l.total_size);
|
|
||||||
errdefer alloc.free(backing);
|
// We use mmap directly to avoid Zig allocator overhead
|
||||||
@memset(backing, 0);
|
// (small but meaningful for this path) and because a private
|
||||||
|
// anonymous mmap is guaranteed on Linux and macOS to be zeroed,
|
||||||
|
// which is a critical property for us.
|
||||||
|
assert(l.total_size % std.mem.page_size == 0);
|
||||||
|
const backing = try std.os.mmap(
|
||||||
|
null,
|
||||||
|
l.total_size,
|
||||||
|
std.os.PROT.READ | std.os.PROT.WRITE,
|
||||||
|
.{ .TYPE = .PRIVATE, .ANONYMOUS = true },
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
errdefer std.os.munmap(backing);
|
||||||
|
|
||||||
const buf = OffsetBuf.init(backing);
|
const buf = OffsetBuf.init(backing);
|
||||||
const rows = buf.member(Row, l.rows_start);
|
const rows = buf.member(Row, l.rows_start);
|
||||||
@ -154,8 +170,8 @@ pub const Page = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Page, alloc: Allocator) void {
|
pub fn deinit(self: *Page) void {
|
||||||
alloc.free(self.memory);
|
std.os.munmap(self.memory);
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +244,7 @@ pub const Page = struct {
|
|||||||
const grapheme_map_start = alignForward(usize, grapheme_alloc_end, GraphemeMap.base_align);
|
const grapheme_map_start = alignForward(usize, grapheme_alloc_end, GraphemeMap.base_align);
|
||||||
const grapheme_map_end = grapheme_map_start + grapheme_map_layout.total_size;
|
const grapheme_map_end = grapheme_map_start + grapheme_map_layout.total_size;
|
||||||
|
|
||||||
const total_size = grapheme_map_end;
|
const total_size = alignForward(usize, grapheme_map_end, std.mem.page_size);
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.total_size = total_size,
|
.total_size = total_size,
|
||||||
@ -317,25 +333,22 @@ pub const Cell = packed struct(u64) {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
test "Page init" {
|
test "Page init" {
|
||||||
const testing = std.testing;
|
var page = try Page.init(.{
|
||||||
const alloc = testing.allocator;
|
|
||||||
var page = try Page.init(alloc, .{
|
|
||||||
.cols = 120,
|
.cols = 120,
|
||||||
.rows = 80,
|
.rows = 80,
|
||||||
.styles = 32,
|
.styles = 32,
|
||||||
});
|
});
|
||||||
defer page.deinit(alloc);
|
defer page.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Page read and write cells" {
|
test "Page read and write cells" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
var page = try Page.init(.{
|
||||||
var page = try Page.init(alloc, .{
|
|
||||||
.cols = 10,
|
.cols = 10,
|
||||||
.rows = 10,
|
.rows = 10,
|
||||||
.styles = 8,
|
.styles = 8,
|
||||||
});
|
});
|
||||||
defer page.deinit(alloc);
|
defer page.deinit();
|
||||||
|
|
||||||
for (0..page.capacity.rows) |y| {
|
for (0..page.capacity.rows) |y| {
|
||||||
const rac = page.getRowAndCell(1, y);
|
const rac = page.getRowAndCell(1, y);
|
||||||
|
Reference in New Issue
Block a user