2023-06-04 13:37:26 +00:00
|
|
|
const builtin = @import("builtin");
|
|
|
|
|
2023-05-24 00:33:02 +00:00
|
|
|
const coral = @import("coral");
|
|
|
|
|
|
|
|
const ext = @import("./ext.zig");
|
|
|
|
|
2023-06-04 01:16:52 +00:00
|
|
|
const std = @import("std");
|
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
const AllocationNode = struct {
|
|
|
|
trace: std.debug.ConfigurableTrace(2, 4, switch (builtin.mode) {
|
|
|
|
.Debug, .ReleaseSafe => true,
|
|
|
|
.ReleaseFast, .ReleaseSmall => false,
|
|
|
|
}),
|
|
|
|
|
|
|
|
next: ?*AllocationNode,
|
2023-06-04 02:00:31 +00:00
|
|
|
size: usize,
|
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
fn alloc(size: usize, return_address: usize) *AllocationNode {
|
|
|
|
const node = @as(*AllocationNode, @ptrCast(@alignCast(ext.SDL_malloc(@sizeOf(AllocationNode) + size))));
|
2023-06-04 13:37:26 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
node.* = .{
|
|
|
|
.size = size,
|
|
|
|
.next = null,
|
|
|
|
.trace = .{},
|
|
|
|
};
|
2023-06-04 13:37:26 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
node.trace.addAddr(return_address, "");
|
2023-06-04 01:16:52 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
return node;
|
|
|
|
}
|
2023-06-04 01:16:52 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
fn dealloc(self: *AllocationNode) void {
|
|
|
|
ext.SDL_free(self);
|
|
|
|
}
|
2023-06-04 01:16:52 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
fn realloc(self: *AllocationNode, size: usize, return_address: usize) *AllocationNode {
|
|
|
|
const node = @as(*AllocationNode, @ptrCast(@alignCast(ext.SDL_realloc(self, @sizeOf(AllocationNode) + size))));
|
2023-06-04 13:37:26 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
node.* = .{
|
|
|
|
.size = size,
|
|
|
|
.next = null,
|
|
|
|
.trace = .{},
|
|
|
|
};
|
|
|
|
|
|
|
|
node.trace.addAddr(return_address, "");
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn owns_userdata(self: *AllocationNode, other_userdata: []const coral.io.Byte) bool {
|
|
|
|
const self_userdata = self.userdata();
|
|
|
|
|
|
|
|
return self_userdata.ptr == other_userdata.ptr and self_userdata.len == other_userdata.len;
|
2023-06-04 13:37:26 +00:00
|
|
|
}
|
2023-06-04 01:16:52 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
fn userdata(self: *AllocationNode) []coral.io.Byte {
|
|
|
|
return @as([*]coral.io.Byte, @ptrFromInt(@intFromPtr(self) + @sizeOf(AllocationNode)))[0 .. self.size];
|
2023-06-04 01:16:52 +00:00
|
|
|
}
|
2023-07-10 01:10:56 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
const Context = struct {
|
|
|
|
head: ?*AllocationNode = null,
|
2023-05-24 00:33:02 +00:00
|
|
|
|
2023-06-04 01:16:52 +00:00
|
|
|
fn deallocate(self: *Context, allocation: []u8) void {
|
2023-06-04 13:37:26 +00:00
|
|
|
switch (builtin.mode) {
|
|
|
|
.Debug, .ReleaseSafe => {
|
2023-07-10 01:10:56 +01:00
|
|
|
const panic_message = "incorrect allocation address for deallocating";
|
|
|
|
var current_node = self.head orelse @panic(panic_message);
|
|
|
|
|
|
|
|
if (current_node.owns_userdata(allocation)) {
|
|
|
|
self.head = current_node.next;
|
2023-05-24 00:33:02 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
return current_node.dealloc();
|
2023-06-04 13:37:26 +00:00
|
|
|
}
|
2023-05-29 01:22:30 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
while (true) {
|
|
|
|
const next_node = current_node.next orelse @panic(panic_message);
|
2023-05-24 00:33:02 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
if (next_node.owns_userdata(allocation)) {
|
|
|
|
current_node.next = next_node.next;
|
2023-05-29 01:22:30 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
return next_node.dealloc();
|
2023-06-04 13:37:26 +00:00
|
|
|
}
|
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
current_node = next_node;
|
2023-06-04 01:16:52 +00:00
|
|
|
}
|
2023-06-04 13:37:26 +00:00
|
|
|
},
|
2023-05-24 00:33:02 +00:00
|
|
|
|
2023-06-04 13:37:26 +00:00
|
|
|
.ReleaseFast, .ReleaseSmall => {
|
|
|
|
ext.SDL_free(allocation.ptr);
|
|
|
|
},
|
|
|
|
}
|
2023-06-04 01:16:52 +00:00
|
|
|
}
|
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
fn reallocate(self: *Context, return_address: usize, existing_allocation: ?[]u8, size: usize) coral.io.AllocationError![]u8 {
|
2023-06-04 13:37:26 +00:00
|
|
|
switch (builtin.mode) {
|
|
|
|
.Debug, .ReleaseSafe => {
|
2023-07-10 01:10:56 +01:00
|
|
|
if (existing_allocation) |allocation| {
|
|
|
|
const panic_message = "incorrect allocation address for reallocating";
|
|
|
|
var current_node = self.head orelse @panic(panic_message);
|
2023-06-04 01:16:52 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
if (current_node.owns_userdata(allocation)) {
|
|
|
|
const node = current_node.realloc(size, return_address);
|
2023-06-04 01:16:52 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
self.head = node;
|
2023-06-04 13:37:26 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
return node.userdata();
|
2023-06-04 13:37:26 +00:00
|
|
|
}
|
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
while (true) {
|
|
|
|
const next_node = current_node.next orelse @panic(panic_message);
|
2023-05-24 00:33:02 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
if (next_node.owns_userdata(allocation)) {
|
|
|
|
const node = next_node.realloc(size, return_address);
|
2023-06-04 13:44:27 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
current_node.next = node;
|
2023-06-04 13:44:27 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
return node.userdata();
|
2023-06-04 13:37:26 +00:00
|
|
|
}
|
2023-06-04 01:16:52 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
current_node = next_node;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const node = AllocationNode.alloc(size, return_address);
|
|
|
|
|
|
|
|
if (self.head) |head| {
|
|
|
|
node.next = head;
|
2023-06-04 13:37:26 +00:00
|
|
|
}
|
2023-06-04 01:16:52 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
self.head = node;
|
|
|
|
|
|
|
|
return node.userdata();
|
|
|
|
}
|
2023-06-04 13:37:26 +00:00
|
|
|
},
|
2023-05-24 00:33:02 +00:00
|
|
|
|
2023-06-04 13:37:26 +00:00
|
|
|
.ReleaseFast, .ReleaseSmall => {
|
2023-07-10 01:10:56 +01:00
|
|
|
if (existing_allocation) |allocation | {
|
|
|
|
return @as([*]u8, ext.SDL_realloc(allocation.ptr, size) orelse {
|
|
|
|
return error.OutOfMemory;
|
|
|
|
})[0 .. size];
|
|
|
|
}
|
|
|
|
|
|
|
|
return @as([*]u8, ext.SDL_malloc(size) orelse return error.OutOfMemory)[0 .. size];
|
2023-06-04 13:37:26 +00:00
|
|
|
},
|
|
|
|
}
|
2023-05-24 00:33:02 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-06-04 01:16:52 +00:00
|
|
|
var context = Context{};
|
2023-05-24 00:33:02 +00:00
|
|
|
|
2023-07-10 01:10:56 +01:00
|
|
|
pub const allocator = coral.io.Allocator.bind(Context, &context, .{
|
|
|
|
.reallocate = Context.reallocate,
|
|
|
|
.deallocate = Context.deallocate,
|
|
|
|
});
|
2023-06-04 01:16:52 +00:00
|
|
|
|
2023-06-04 02:23:07 +00:00
|
|
|
pub fn trace_leaks() void {
|
2023-06-04 13:37:26 +00:00
|
|
|
switch (builtin.mode) {
|
|
|
|
.Debug, .ReleaseSafe => {
|
2023-07-22 11:03:23 +01:00
|
|
|
var current_node = context.head;
|
2023-06-04 13:37:26 +00:00
|
|
|
|
2023-07-22 11:03:23 +01:00
|
|
|
while (current_node) |node| : (current_node = node.next) {
|
2023-07-22 15:20:31 +01:00
|
|
|
std.debug.print("{d} byte leak at 0x{x} detected", .{
|
2023-07-22 11:03:23 +01:00
|
|
|
node.size,
|
|
|
|
@intFromPtr(node) + @sizeOf(AllocationNode),
|
2023-06-04 13:37:26 +00:00
|
|
|
});
|
|
|
|
|
2023-07-22 11:03:23 +01:00
|
|
|
node.trace.dump();
|
2023-06-04 13:37:26 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
.ReleaseFast, .ReleaseSmall => {},
|
2023-06-04 01:16:52 +00:00
|
|
|
}
|
|
|
|
}
|