terminal: PageList.clone must use createPageExt for non-std pages

This commit is contained in:
Mitchell Hashimoto
2024-03-11 19:37:12 -07:00
parent dc04cc1317
commit ab1a302daa

View File

@ -328,17 +328,38 @@ pub fn clone(
errdefer tracked_pins.deinit(pool.alloc); errdefer tracked_pins.deinit(pool.alloc);
try tracked_pins.putNoClobber(pool.alloc, viewport_pin, {}); try tracked_pins.putNoClobber(pool.alloc, viewport_pin, {});
// Copy our pages // Our list of pages
var page_list: List = .{}; var page_list: List = .{};
errdefer {
const page_alloc = pool.pages.arena.child_allocator;
var page_it = page_list.first;
while (page_it) |node| : (page_it = node.next) {
if (node.data.memory.len > std_size) {
page_alloc.free(node.data.memory);
}
}
}
// Copy our pages
var total_rows: usize = 0; var total_rows: usize = 0;
var page_count: usize = 0; var page_size: usize = 0;
while (it.next()) |chunk| { while (it.next()) |chunk| {
// Clone the page // Clone the page. We have to use createPageExt here because
const page = try pool.nodes.create(); // we don't know if the source page has a standard size.
const page_buf = try pool.pages.create(); const page = try createPageExt(
page.* = .{ .data = chunk.page.data.cloneBuf(page_buf) }; pool,
chunk.page.data.capacity,
&page_size,
);
assert(page.data.capacity.rows >= chunk.page.data.capacity.rows);
page.data.size.rows = chunk.page.data.size.rows;
try page.data.cloneFrom(
&chunk.page.data,
0,
chunk.page.data.size.rows,
);
page_list.append(page); page_list.append(page);
page_count += 1;
// If this is a full page then we're done. // If this is a full page then we're done.
if (chunk.fullPage()) { if (chunk.fullPage()) {
@ -427,7 +448,7 @@ pub fn clone(
.alloc => true, .alloc => true,
}, },
.pages = page_list, .pages = page_list,
.page_size = PagePool.item_size * page_count, .page_size = page_size,
.max_size = self.max_size, .max_size = self.max_size,
.cols = self.cols, .cols = self.cols,
.rows = self.rows, .rows = self.rows,
@ -1587,19 +1608,30 @@ pub fn compact(self: *PageList, page: *List.Node) !*List.Node {
/// Create a new page node. This does not add it to the list and this /// Create a new page node. This does not add it to the list and this
/// does not do any memory size accounting with max_size/page_size. /// does not do any memory size accounting with max_size/page_size.
fn createPage(self: *PageList, cap: Capacity) !*List.Node { fn createPage(
var page = try self.pool.nodes.create(); self: *PageList,
errdefer self.pool.nodes.destroy(page); cap: Capacity,
) !*List.Node {
return try createPageExt(&self.pool, cap, &self.page_size);
}
fn createPageExt(
pool: *MemoryPool,
cap: Capacity,
total_size: ?*usize,
) !*List.Node {
var page = try pool.nodes.create();
errdefer pool.nodes.destroy(page);
const layout = Page.layout(cap); const layout = Page.layout(cap);
const pooled = layout.total_size <= std_size; const pooled = layout.total_size <= std_size;
const page_alloc = self.pool.pages.arena.child_allocator; const page_alloc = pool.pages.arena.child_allocator;
// Our page buffer comes from our standard memory pool if it // Our page buffer comes from our standard memory pool if it
// is within our standard size since this is what the pool // is within our standard size since this is what the pool
// dispenses. Otherwise, we use the heap allocator to allocate. // dispenses. Otherwise, we use the heap allocator to allocate.
const page_buf = if (pooled) const page_buf = if (pooled)
try self.pool.pages.create() try pool.pages.create()
else else
try page_alloc.alignedAlloc( try page_alloc.alignedAlloc(
u8, u8,
@ -1607,7 +1639,7 @@ fn createPage(self: *PageList, cap: Capacity) !*List.Node {
layout.total_size, layout.total_size,
); );
errdefer if (pooled) errdefer if (pooled)
self.pool.pages.destroy(page_buf) pool.pages.destroy(page_buf)
else else
page_alloc.free(page_buf); page_alloc.free(page_buf);
@ -1618,10 +1650,12 @@ fn createPage(self: *PageList, cap: Capacity) !*List.Node {
page.* = .{ .data = Page.initBuf(OffsetBuf.init(page_buf), layout) }; page.* = .{ .data = Page.initBuf(OffsetBuf.init(page_buf), layout) };
page.data.size.rows = 0; page.data.size.rows = 0;
// Accumulate page size now. We don't assert or check max size because if (total_size) |v| {
// we may exceed it here temporarily as we are allocating pages before // Accumulate page size now. We don't assert or check max size
// destroy. // because we may exceed it here temporarily as we are allocating
self.page_size += page_buf.len; // pages before destroy.
v.* += page_buf.len;
}
return page; return page;
} }
@ -1629,19 +1663,27 @@ fn createPage(self: *PageList, cap: Capacity) !*List.Node {
/// Destroy the memory of the given page and return it to the pool. The /// Destroy the memory of the given page and return it to the pool. The
/// page is assumed to already be removed from the linked list. /// page is assumed to already be removed from the linked list.
fn destroyPage(self: *PageList, page: *List.Node) void { fn destroyPage(self: *PageList, page: *List.Node) void {
destroyPageExt(&self.pool, page, &self.page_size);
}
fn destroyPageExt(
pool: *MemoryPool,
page: *List.Node,
total_size: ?*usize,
) void {
// Update our accounting for page size // Update our accounting for page size
self.page_size -= page.data.memory.len; if (total_size) |v| v.* -= page.data.memory.len;
if (page.data.memory.len <= std_size) { if (page.data.memory.len <= std_size) {
// Reset the memory to zero so it can be reused // Reset the memory to zero so it can be reused
@memset(page.data.memory, 0); @memset(page.data.memory, 0);
self.pool.pages.destroy(@ptrCast(page.data.memory.ptr)); pool.pages.destroy(@ptrCast(page.data.memory.ptr));
} else { } else {
const page_alloc = self.pool.pages.arena.child_allocator; const page_alloc = pool.pages.arena.child_allocator;
page_alloc.free(page.data.memory); page_alloc.free(page.data.memory);
} }
self.pool.nodes.destroy(page); pool.nodes.destroy(page);
} }
/// Erase the rows from the given top to bottom (inclusive). Erasing /// Erase the rows from the given top to bottom (inclusive). Erasing