mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
terminal: PageList.clone must use createPageExt for non-std pages
This commit is contained in:
@ -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
|
||||||
|
Reference in New Issue
Block a user