terminal/new: pages must use mmap directly

This commit is contained in:
Mitchell Hashimoto
2024-02-22 10:27:18 -08:00
parent f7c597fa95
commit 424f121104
2 changed files with 31 additions and 18 deletions

View File

@ -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,

View File

@ -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);