Allow .allocator for dynamic arrays; Add mem.Pool

This commit is contained in:
gingerBill
2018-06-12 19:10:14 +01:00
parent 915dcb0c28
commit e9e7ce2606
8 changed files with 253 additions and 142 deletions
+159 -1
View File
@@ -75,7 +75,6 @@ free :: proc[
default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, loc := #caller_location) -> rawptr {
if old_memory == nil do return alloc(new_size, alignment, loc);
@@ -108,3 +107,162 @@ nil_allocator :: proc() -> Allocator {
};
}
Pool :: struct {
block_size: int,
out_band_size: int,
alignment: int,
unused_blocks: [dynamic]rawptr,
used_blocks: [dynamic]rawptr,
out_band_allocations: [dynamic]rawptr,
current_block: rawptr,
current_pos: rawptr,
bytes_left: int,
block_allocator: Allocator,
}
POOL_BLOCK_SIZE_DEFAULT :: 65536;
POOL_OUT_OF_BAND_SIZE_DEFAULT :: 6554;
pool_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
pool := (^Pool)(allocator_data);
switch mode {
case Allocator_Mode.Alloc:
return pool_alloc(pool, size);
case Allocator_Mode.Free:
panic("Allocator_Mode.Free is not supported for a pool");
case Allocator_Mode.Free_All:
pool_free_all(pool);
case Allocator_Mode.Resize:
panic("Allocator_Mode.Resize is not supported for a pool");
}
return nil;
}
pool_allocator :: proc(pool: ^Pool) -> Allocator {
return Allocator{
procedure = pool_allocator_proc,
data = pool,
};
}
pool_init :: proc(pool: ^Pool,
block_allocator := Allocator{} , array_allocator := Allocator{},
block_size := POOL_BLOCK_SIZE_DEFAULT, out_band_size := POOL_OUT_OF_BAND_SIZE_DEFAULT,
alignment := 8) {
pool.block_size = block_size;
pool.out_band_size = out_band_size;
pool.alignment = alignment;
if block_allocator.procedure == nil {
block_allocator = context.allocator;
}
if array_allocator.procedure == nil {
array_allocator = context.allocator;
}
pool.block_allocator = block_allocator;
pool.out_band_allocations.allocator = array_allocator;
pool. unused_blocks.allocator = array_allocator;
pool. used_blocks.allocator = array_allocator;
}
pool_destroy :: proc(using pool: ^Pool) {
pool_free_all(pool);
free(unused_blocks);
free(used_blocks);
zero(pool, size_of(pool^));
}
pool_alloc :: proc(using pool: ^Pool, bytes: int) -> rawptr {
cycle_new_block :: proc(using pool: ^Pool) {
if block_allocator.procedure == nil {
panic("You must call pool_init on a Pool before using it");
}
if current_block != nil {
append(&used_blocks, current_block);
}
new_block: rawptr;
if len(unused_blocks) > 0 {
new_block = pop(&unused_blocks);
} else {
new_block = block_allocator.procedure(block_allocator.data, Allocator_Mode.Alloc,
block_size, alignment,
nil, 0);
}
bytes_left = block_size;
current_pos = new_block;
current_block = new_block;
}
extra := alignment - (bytes % alignment);
bytes += extra;
if bytes >= out_band_size {
assert(block_allocator.procedure != nil);
memory := block_allocator.procedure(block_allocator.data, Allocator_Mode.Alloc,
block_size, alignment,
nil, 0);
if memory != nil {
append(&out_band_allocations, (^byte)(memory));
}
return memory;
}
if bytes_left < bytes {
cycle_new_block(pool);
if current_block == nil {
return nil;
}
}
memory := current_pos;
current_pos = ptr_offset((^byte)(current_pos), uintptr(bytes));
bytes_left -= bytes;
return memory;
}
pool_reset :: proc(using pool: ^Pool) {
if current_block != nil {
append(&unused_blocks, current_block);
current_block = nil;
}
for block in used_blocks {
append(&unused_blocks, block);
}
clear(&used_blocks);
for a in out_band_allocations {
free_ptr_with_allocator(block_allocator, a);
}
clear(&out_band_allocations);
}
pool_free_all :: proc(using pool: ^Pool) {
pool_reset(pool);
for block in unused_blocks {
free_ptr_with_allocator(block_allocator, block);
}
clear(&unused_blocks);
}
+20 -60
View File
@@ -7,19 +7,14 @@ Semaphore :: struct {
_handle: win32.Handle,
}
/*
Mutex :: struct {
_semaphore: Semaphore,
_counter: i32,
_owner: i32,
_recursion: i32,
}
*/
Mutex :: struct {
_critical_section: win32.Critical_Section,
}
Condition :: struct {
event: win32.Handle,
}
current_thread_id :: proc() -> i32 {
return i32(win32.get_current_thread_id());
}
@@ -41,7 +36,8 @@ semaphore_release :: inline proc(s: ^Semaphore) {
}
semaphore_wait :: proc(s: ^Semaphore) {
win32.wait_for_single_object(s._handle, win32.INFINITE);
result := win32.wait_for_single_object(s._handle, win32.INFINITE);
assert(result != win32.WAIT_FAILED);
}
@@ -66,59 +62,23 @@ mutex_unlock :: proc(m: ^Mutex) {
}
condition_init :: proc(using c: ^Condition) {
event = win32.create_event_a(nil, false, false, nil);
assert(event != nil);
}
/*
mutex_init :: proc(m: ^Mutex) {
atomics.store(&m._counter, 0);
atomics.store(&m._owner, current_thread_id());
semaphore_init(&m._semaphore);
m._recursion = 0;
condition_signal :: proc(using c: ^Condition) {
ok := win32.set_event(event);
assert(bool(ok));
}
mutex_destroy :: proc(m: ^Mutex) {
semaphore_destroy(&m._semaphore);
}
mutex_lock :: proc(m: ^Mutex) {
thread_id := current_thread_id();
if atomics.fetch_add(&m._counter, 1) > 0 {
if thread_id != atomics.load(&m._owner) {
semaphore_wait(&m._semaphore);
}
}
atomics.store(&m._owner, thread_id);
m._recursion++;
}
mutex_try_lock :: proc(m: ^Mutex) -> bool {
thread_id := current_thread_id();
if atomics.load(&m._owner) == thread_id {
atomics.fetch_add(&m._counter, 1);
} else {
expected: i32 = 0;
if atomics.load(&m._counter) != 0 {
return false;
}
if atomics.compare_exchange(&m._counter, expected, 1) == 0 {
return false;
}
atomics.store(&m._owner, thread_id);
}
m._recursion++;
return true;
}
mutex_unlock :: proc(m: ^Mutex) {
recursion: i32;
thread_id := current_thread_id();
assert(thread_id == atomics.load(&m._owner));
m._recursion--;
recursion = m._recursion;
if recursion == 0 {
atomics.store(&m._owner, thread_id);
}
condition_wait_for :: proc(using c: ^Condition) {
result := win32.wait_for_single_object(event, win32.INFINITE);
assert(result != win32.WAIT_FAILED);
}
if atomics.fetch_add(&m._counter, -1) > 1 {
if recursion == 0 {
semaphore_release(&m._semaphore);
}
condition_destroy :: proc(using c: ^Condition) {
if event != nil {
win32.close_handle(event);
}
}
*/
+3
View File
@@ -701,6 +701,9 @@ foreign kernel32 {
@(link_name="LeaveCriticalSection") leave_critical_section :: proc(critical_section: ^Critical_Section) ---;
@(link_name="CreateEventA") create_event_a :: proc(event_attributes: ^Security_Attributes, manual_reset, initial_state: Bool, name: cstring) -> Handle ---;
@(link_name="PulseEvent") pulse_event :: proc(event: Handle) -> Bool ---;
@(link_name="SetEvent") set_event :: proc(event: Handle) -> Bool ---;
@(link_name="ResetEvent") reset_event :: proc(event: Handle) -> Bool ---;
@(link_name="LoadLibraryA") load_library_a :: proc(c_str: cstring) -> Hmodule ---;
@(link_name="LoadLibraryW") load_library_w :: proc(c_str: Wstring) -> Hmodule ---;