Update Array type to use custom/context allocator.
This commit is contained in:
parent
e0a515017d
commit
680f735b72
30
cpp_lib.todo
30
cpp_lib.todo
@ -1,9 +1,10 @@
|
|||||||
[#TODO]
|
[#TODO]
|
||||||
|
[ ] Thread primitives (Mutex, Semaphore, etc.)
|
||||||
|
[ ] Thread Creation / Deletion
|
||||||
|
[ ] CreateWindow
|
||||||
|
[ ] ... Mouse / Keyboard inputs
|
||||||
[*] This is the order I want to follow, because I need them in thread context.
|
[*] This is the order I want to follow, because I need them in thread context.
|
||||||
- Allocator interface
|
|
||||||
- Thread context (Base_Thread_Context.h)
|
|
||||||
- Arenas (copy from Ex1)
|
|
||||||
- Entry point(s) `Entry_Point_Main.cpp`
|
- Entry point(s) `Entry_Point_Main.cpp`
|
||||||
-> We can have a lib_init() instead of a clear entry point for now.
|
-> We can have a lib_init() instead of a clear entry point for now.
|
||||||
-> Switch from library to application once I add an entry point
|
-> Switch from library to application once I add an entry point
|
||||||
@ -13,3 +14,24 @@
|
|||||||
>> Must be assigned at entry point (arena_alloc())
|
>> Must be assigned at entry point (arena_alloc())
|
||||||
>> TCTX defined in base_thread_context.h
|
>> TCTX defined in base_thread_context.h
|
||||||
> See Base_Thread.h
|
> See Base_Thread.h
|
||||||
|
[Design Stuff]
|
||||||
|
[ ] "Primary Thread" <- Main entry point thread
|
||||||
|
[ ] "Secondary Thread" <- does all the heavy lifting for the first thread and synchronizes with the first.
|
||||||
|
[ ] Tertiary threads (launched by secondary thread and awaiting work as assigned by Primary and Secondary threads)
|
||||||
|
[ ] Multi-threaded by default with sync points
|
||||||
|
[ ] Need bindings for Semaphore and Mutex
|
||||||
|
[ ] Does calling SetProcessWorkingSetSize(.., -1, -1) cause the program to crash? Why tho.
|
||||||
|
[ ] Maybe we just shouldn't do this?
|
||||||
|
[ ] *our* program memory usage can be calculated by Stack Size + allocations from GPAllocator + allocations from arena.
|
||||||
|
[TODO - Low priority]
|
||||||
|
[ ] Implement Secure Arenas (with VirtualLock, wiping memory with RtlSecureZeroMemory)
|
||||||
|
[ ]
|
||||||
|
[Project Ideas]
|
||||||
|
[ ](Graphics): How do I create a basic overlay that shows the time, date, cpu/gpu temps, frequency, memory usage all the time and responds to global hotkey to show more info
|
||||||
|
[Documentation Notes]
|
||||||
|
Main inspirations for this codebase:
|
||||||
|
(1) jonathan blow & jai compiler project
|
||||||
|
(2) casey muratori and "handmade" approach to software
|
||||||
|
(3) ryan fleury and raddebugger codebase
|
||||||
|
|
||||||
|
Always contemplate your impulses
|
||||||
@ -1,15 +1,6 @@
|
|||||||
#include "Allocator.h"
|
#include "Allocator.h"
|
||||||
#include "Base_Thread_Context.h"
|
#include "Base_Thread_Context.h"
|
||||||
|
|
||||||
force_inline Allocator get_temp_allocator() {
|
|
||||||
return get_allocator(get_thread_context()->temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
force_inline Allocator get_context_allocator() {
|
|
||||||
Thread_Context* context = get_thread_context();
|
|
||||||
return context->allocator;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* internal_alloc (s64 size) {
|
void* internal_alloc (s64 size) {
|
||||||
Allocator allocator = get_context_allocator();
|
Allocator allocator = get_context_allocator();
|
||||||
void* result = allocator.proc(Allocator_Mode::ALLOCATE, size, 0, nullptr, allocator.data);
|
void* result = allocator.proc(Allocator_Mode::ALLOCATE, size, 0, nullptr, allocator.data);
|
||||||
@ -18,7 +9,7 @@ void* internal_alloc (s64 size) {
|
|||||||
|
|
||||||
void* internal_realloc (void* memory, s64 size, s64 old_size) {
|
void* internal_realloc (void* memory, s64 size, s64 old_size) {
|
||||||
Allocator allocator = get_context_allocator();
|
Allocator allocator = get_context_allocator();
|
||||||
void* result = allocator.proc(Allocator_Mode::RESIZE, size, 0, nullptr, allocator.data);
|
void* result = allocator.proc(Allocator_Mode::RESIZE, size, old_size, nullptr, allocator.data);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,20 +17,19 @@ typedef void* (*Allocator_Proc)(Allocator_Mode mode, s64 requested_size, s64 old
|
|||||||
struct Allocator {
|
struct Allocator {
|
||||||
Allocator_Proc proc;
|
Allocator_Proc proc;
|
||||||
void* data;
|
void* data;
|
||||||
|
|
||||||
|
bool operator ! () {
|
||||||
|
return (proc == nullptr && data == nullptr);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Public Allocator API:
|
// Public Allocator API:
|
||||||
// Thread-local allocators:
|
|
||||||
PROTOTYPING_API Allocator get_temp_allocator();
|
|
||||||
PROTOTYPING_API Allocator get_context_allocator();
|
|
||||||
|
|
||||||
// Note that alignment is handled on a per-allocator basis.
|
// Note that alignment is handled on a per-allocator basis.
|
||||||
void* internal_alloc (s64 size);
|
void* internal_alloc (s64 size);
|
||||||
void internal_free (void* memory);
|
void internal_free (void* memory);
|
||||||
void* internal_realloc (void* memory, s64 size, s64 old_size);
|
void* internal_realloc (void* memory, s64 size, s64 old_size);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T> force_inline void Initialize (T* memory) { (*memory) = T(); }
|
||||||
void Initialize (T* memory) { (*memory) = T(); }
|
|
||||||
|
|
||||||
template <typename T> T* New (Allocator allocator, bool initialize=true) {
|
template <typename T> T* New (Allocator allocator, bool initialize=true) {
|
||||||
auto memory = (T*)allocator.proc(Allocator_Mode::ALLOCATE, sizeof(T), 0, nullptr, allocator.data);
|
auto memory = (T*)allocator.proc(Allocator_Mode::ALLOCATE, sizeof(T), 0, nullptr, allocator.data);
|
||||||
@ -52,6 +51,35 @@ template <typename T> T* New (bool initialize=true) {
|
|||||||
return memory;
|
return memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Delete (void* object) { internal_free(object); }
|
// For raw-pointer arrays.
|
||||||
|
template <typename T> T* NewArray (Allocator allocator, s64 count, bool initialize=true) {
|
||||||
|
auto memory = (T*)allocator.proc(Allocator_Mode::ALLOCATE, count * sizeof(T), 0, nullptr, allocator.data);
|
||||||
|
|
||||||
// template <typename T> T* NewArray(s64 count, bool initialize) // should be in Array.jai
|
if (initialize) {
|
||||||
|
for (s64 i = 0; i < count; i += 1) {
|
||||||
|
memory[i] = T();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> T* NewArray (s64 count, bool initialize=true) {
|
||||||
|
auto memory = (T*)internal_alloc(count * sizeof(T));
|
||||||
|
|
||||||
|
if (initialize) {
|
||||||
|
for (s64 i = 0; i < count; i += 1) {
|
||||||
|
memory[i] = T();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For Resizes and Deletes, use internal_realloc and internal_free.
|
||||||
|
// template typename<T> void reset_struct(T* src) { (*src) = T(); }
|
||||||
|
// template typename<T> void zero_struct(T* src) { memset(src, 0, sizeof(T)); }
|
||||||
|
// template typename<T> T* copy_struct(T* src) {
|
||||||
|
// T* dst = New<T>(false);
|
||||||
|
// memcpy(dst, src, sizeof(T));
|
||||||
|
// }
|
||||||
|
|||||||
@ -24,7 +24,7 @@ enum class Arena_Flags: u8 {
|
|||||||
Chained = 0x01,
|
Chained = 0x01,
|
||||||
Is_Bootstrapped = 0x02,
|
Is_Bootstrapped = 0x02,
|
||||||
Large_Pages = 0x40,
|
Large_Pages = 0x40,
|
||||||
// Secure_Arena = 0xF0 // #NOTE: Secure Arenas are not implemented here!
|
// Secure_Arena = 0xF0 // #NOTE: Secure Arenas are not implemented yet!
|
||||||
};
|
};
|
||||||
|
|
||||||
force_inline Arena_Flags operator | (Arena_Flags a, Arena_Flags b) {
|
force_inline Arena_Flags operator | (Arena_Flags a, Arena_Flags b) {
|
||||||
@ -99,6 +99,8 @@ void arena_delete (Arena* arena);
|
|||||||
|
|
||||||
// Scoped Macros/Functions for auto_reset and auto_release
|
// Scoped Macros/Functions for auto_reset and auto_release
|
||||||
// usage `Auto_Reset guard(arena);` within a scope.
|
// usage `Auto_Reset guard(arena);` within a scope.
|
||||||
|
#define auto_reset(x) \
|
||||||
|
Auto_Reset Concat(_auto_reset_guard_, __LINE__)(x)
|
||||||
struct Auto_Reset {
|
struct Auto_Reset {
|
||||||
Arena* arena;
|
Arena* arena;
|
||||||
u8* starting_point;
|
u8* starting_point;
|
||||||
@ -114,6 +116,8 @@ struct Auto_Reset {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define auto_release(x) \
|
||||||
|
Auto_Release Concat(_auto_release_guard_, __LINE__)(x)
|
||||||
struct Auto_Release {
|
struct Auto_Release {
|
||||||
Arena* arena;
|
Arena* arena;
|
||||||
u8* starting_point;
|
u8* starting_point;
|
||||||
@ -130,7 +134,9 @@ struct Auto_Release {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Push_Alignment {
|
#define push_alignment(x, y) \
|
||||||
|
Push_Alignment Concat(_push_align_guard_, __LINE__)(x, y)
|
||||||
|
struct Push_Alignment { // #rename to Arena_Push_Alignment?
|
||||||
Arena* arena;
|
Arena* arena;
|
||||||
u16 original_alignment;
|
u16 original_alignment;
|
||||||
|
|
||||||
@ -146,6 +152,8 @@ struct Push_Alignment {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define push_arena(x) \
|
||||||
|
Push_Arena Concat(_push_alloc_guard_, __LINE__)(x)
|
||||||
struct Push_Arena {
|
struct Push_Arena {
|
||||||
Thread_Context* context;
|
Thread_Context* context;
|
||||||
Allocator original_allocator;
|
Allocator original_allocator;
|
||||||
|
|||||||
@ -28,8 +28,8 @@ struct ArenaArray { // downcasts to an ArrayView.
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
ArenaArray<T>* arena_array_new (s64 preallocate_count, Arena_Reserve reserve_size) {
|
ArenaArray<T>* arena_array_new (s64 preallocate_count, Arena_Reserve reserve_size) {
|
||||||
Arena* arena = next_arena(reserve_size);
|
Arena* arena = next_arena(reserve_size);
|
||||||
Push_Arena push_arena(arena);
|
push_arena(arena);
|
||||||
Push_Alignment push_alignment(arena, 1);
|
push_alignment(arena, 1);
|
||||||
ArenaArray<T>* array = New<ArenaArray<T>>(true);
|
ArenaArray<T>* array = New<ArenaArray<T>>(true);
|
||||||
array->arena = arena;
|
array->arena = arena;
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ template <typename T> void array_free (ArenaArray<T>& array) {
|
|||||||
release_arena(array.arena, delete_extra_pages=true);
|
release_arena(array.arena, delete_extra_pages=true);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> ArrayView<T> array_view (Array<T> array) {
|
template <typename T> ArrayView<T> array_view (ArenaArray<T> array) {
|
||||||
ArrayView<T> av;
|
ArrayView<T> av;
|
||||||
av.count = array.count;
|
av.count = array.count;
|
||||||
av.data = array.data;
|
av.data = array.data;
|
||||||
@ -136,14 +136,6 @@ template <typename T> void array_resize (ArenaArray<T>& array, s64 desired_item_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reserve_internal (ArenaArray<void>& array, s64 desired_item_count, s64 element_size) {
|
|
||||||
if (desired_item_count <= array.allocated) return;
|
|
||||||
|
|
||||||
array_arena_realloc(array, desired_item_count * element_size, array.allocated * element_size);
|
|
||||||
|
|
||||||
array.allocated = desired_item_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
s64 max_array_size (ArenaArray<void>& array) {
|
s64 max_array_size (ArenaArray<void>& array) {
|
||||||
return reserve_size(array.arena) - sizeof(Arena) - sizeof(ArenaArray<void>);
|
return reserve_size(array.arena) - sizeof(Arena) - sizeof(ArenaArray<void>);
|
||||||
}
|
}
|
||||||
@ -167,6 +159,14 @@ void array_arena_realloc (ArenaArray<void>& array, s64 new_size, s64 old_size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reserve_internal (ArenaArray<void>& array, s64 desired_item_count, s64 element_size) {
|
||||||
|
if (desired_item_count <= array.allocated) return;
|
||||||
|
|
||||||
|
array_arena_realloc(array, desired_item_count * element_size, array.allocated * element_size);
|
||||||
|
|
||||||
|
array.allocated = desired_item_count;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T> void init_range (T* ptr, s64 start_offset, s64 end_offset) {
|
template <typename T> void init_range (T* ptr, s64 start_offset, s64 end_offset) {
|
||||||
for (s64 i = start_offset; i < end_offset; i += 1) {
|
for (s64 i = start_offset; i < end_offset; i += 1) {
|
||||||
T* current_item = ptr + i;
|
T* current_item = ptr + i;
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
// API in Arena.h
|
// API in Arena.h
|
||||||
#include "Arena.h"
|
#include "Arena.h"
|
||||||
#include "Array.h"
|
#include "Array.h"
|
||||||
|
#include "General_Purpose_Allocator.h"
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
global std::mutex arena_table_mutex;
|
global std::mutex arena_table_mutex;
|
||||||
@ -12,6 +13,8 @@ global Array<Arena*> arenas_in_flight[6];
|
|||||||
|
|
||||||
void initialize_arena_table () {
|
void initialize_arena_table () {
|
||||||
for (s32 i = 0; i < 6; i += 1) {
|
for (s32 i = 0; i < 6; i += 1) {
|
||||||
|
arena_free_table[i].allocator = GPAllocator();
|
||||||
|
arenas_in_flight[i].allocator = GPAllocator();
|
||||||
array_reserve(arena_free_table[i], 64);
|
array_reserve(arena_free_table[i], 64);
|
||||||
array_reserve(arenas_in_flight[i], 64);
|
array_reserve(arenas_in_flight[i], 64);
|
||||||
}
|
}
|
||||||
|
|||||||
105
lib/Base/Array.h
105
lib/Base/Array.h
@ -4,10 +4,14 @@
|
|||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
#include "Allocator.h"
|
#include "Allocator.h"
|
||||||
|
|
||||||
#define DEFAULT_ARRAY_ALIGNMENT 16
|
// #TODO: Array.h
|
||||||
|
// [x] Set allocations to use context.allocator interface
|
||||||
// #NOTE: This uses `General_Purpose_Allocator` for simplicity.
|
// For now, I'm just disabling alignment:
|
||||||
|
// [ ] Add back alignment, and make sure there's a way to pass alignment to NewArray, which gets passed to allocator.proc.
|
||||||
|
// [ ] Make versions of ArrayView initializer that takes allocator as a param
|
||||||
|
// [ ] Make version of array_free (ArrayView&) that takes allocator as a param
|
||||||
// For Arena-Backed arrays use ArenaArray
|
// For Arena-Backed arrays use ArenaArray
|
||||||
|
// #define DEFAULT_ARRAY_ALIGNMENT 16
|
||||||
|
|
||||||
MSVC_RUNTIME_CHECKS_OFF
|
MSVC_RUNTIME_CHECKS_OFF
|
||||||
|
|
||||||
@ -17,39 +21,42 @@ struct Array { // downcasts to an ArrayView.
|
|||||||
s64 count;
|
s64 count;
|
||||||
T* data;
|
T* data;
|
||||||
s64 allocated;
|
s64 allocated;
|
||||||
s64 alignment = DEFAULT_ARRAY_ALIGNMENT;
|
Allocator allocator;
|
||||||
|
// s64 alignment = DEFAULT_ARRAY_ALIGNMENT;
|
||||||
|
|
||||||
Array() {
|
Array() {
|
||||||
memset(this, 0, sizeof(*this));
|
memset(this, 0, sizeof(*this));
|
||||||
alignment = DEFAULT_ARRAY_ALIGNMENT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Array(s64 new_count, s64 _alignment, bool zero_memory=true) {
|
Array(s64 new_count, bool initialize=false) { // old: NewArray ::, array_new :
|
||||||
count = new_count;
|
count = new_count;
|
||||||
data = (T*)GPAllocator_New(new_count * sizeof(T), _alignment);
|
allocator = get_context_allocator();
|
||||||
if (zero_memory) { memset(data, 0, new_count * sizeof(T)); }
|
data = NewArray<T>(new_count, initialize);
|
||||||
alignment = _alignment;
|
|
||||||
allocated = new_count;
|
allocated = new_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use constructor delegation to pass params to above constructor
|
|
||||||
Array(s64 new_count, bool zero_memory=true)
|
|
||||||
: Array(new_count, DEFAULT_ARRAY_ALIGNMENT, zero_memory) {}
|
|
||||||
|
|
||||||
// initializer-list type instantiation: `Array<T> new_array = {count, data}`
|
// initializer-list type instantiation: `Array<T> new_array = {count, data}`
|
||||||
// This is essentially an arrayview.
|
// (Musa) This array cannot then be resized. Why do I even have this? Do I need it?
|
||||||
// (Musa) Ok, but this array cannot then be resized.
|
// Array(s64 new_count, void* new_data) {
|
||||||
Array(s64 new_count, void* new_data) {
|
// count = new_count;
|
||||||
count = new_count;
|
// data = (T*)new_data;
|
||||||
data = (T*)new_data;
|
// allocator = { nullptr, nullptr }; // NOT RESIZABLE.
|
||||||
|
// allocated = new_count;
|
||||||
allocated = new_count;
|
// }
|
||||||
alignment = DEFAULT_ARRAY_ALIGNMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by array_zero, array_copy, etc.
|
// Used by array_zero, array_copy, etc.
|
||||||
Array(s64 new_count, void* new_data, s64 _allocated, s64 _alignment) {
|
Array(s64 new_count, void* new_data, s64 _allocated) {
|
||||||
count = new_count; data = (T*)new_data; allocated = _allocated; alignment = _alignment;
|
count = new_count;
|
||||||
|
data = (T*)new_data;
|
||||||
|
allocated = _allocated;
|
||||||
|
allocator = get_context_allocator();
|
||||||
|
}
|
||||||
|
|
||||||
|
Array(s64 new_count, void* new_data, s64 _allocated, Allocator _allocator) {
|
||||||
|
count = new_count;
|
||||||
|
data = (T*)new_data;
|
||||||
|
allocated = _allocated;
|
||||||
|
allocator = _allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
T& operator[](s64 index) {
|
T& operator[](s64 index) {
|
||||||
@ -60,13 +67,17 @@ struct Array { // downcasts to an ArrayView.
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T> bool is_resizable (Array<T>& src) {
|
||||||
|
// If we have a valid allocator, we assume this is resizeable.
|
||||||
|
return src.allocator.proc != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool is_valid(Array<T> src) {
|
bool is_valid(Array<T> src) {
|
||||||
if (src.count == 0) return true;
|
if (src.count == 0) return true;
|
||||||
if (src.count < 0) return false;
|
if (src.count < 0) return false;
|
||||||
if (src.data == nullptr) return false;
|
if (src.data == nullptr) return false;
|
||||||
if (src.allocated < src.count) return false;
|
if (src.allocated < src.count) return false;
|
||||||
// if ((src.alignment % 8) != 0) return false; Dubious - we could want an alignment of 1
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,10 +87,10 @@ Array<T> array_copy_zero(const Array<T>& src) {
|
|||||||
return Array<T>(); // Return an empty array
|
return Array<T>(); // Return an empty array
|
||||||
}
|
}
|
||||||
|
|
||||||
void* new_data = GPAllocator_New(src.count * sizeof(T), src.alignment);
|
T* new_data = NewArray<T>(src.count, false);
|
||||||
memset(new_data, 0, src.count * sizeof(T));
|
memset(new_data, 0, src.count * sizeof(T));
|
||||||
|
|
||||||
return Array<T>(src.count, new_data, src.allocated, src.alignment);
|
return Array<T>(src.count, new_data, src.allocated);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -88,20 +99,26 @@ Array<T> array_copy(const Array<T>& src) {
|
|||||||
return Array<T>(); // Return an empty array
|
return Array<T>(); // Return an empty array
|
||||||
}
|
}
|
||||||
|
|
||||||
void* new_data = GPAllocator_New(src.count * sizeof(T), src.alignment);
|
T* new_data = NewArray<T>(src.count, false);
|
||||||
memcpy(new_data, src.data, src.count * sizeof(T));
|
memcpy(new_data, src.data, src.count * sizeof(T));
|
||||||
|
|
||||||
return Array<T>(src.count, new_data, src.allocated, src.alignment);
|
return Array<T>(src.count, new_data, src.allocated);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void array_reset_count(Array<T>& src) {
|
void array_reset_keeping_memory(Array<T>& src) {
|
||||||
src.count = 0;
|
src.count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void array_free(Array<T>& src) {
|
void array_free(Array<T>& src) {
|
||||||
GPAllocator_Delete(src.data);
|
if (!src.data) return;
|
||||||
|
if (src.allocated == 0) return;
|
||||||
|
if (src.allocator.proc != nullptr) {
|
||||||
|
src.allocator.proc(Allocator_Mode::DEALLOCATE, 0, 0, src.data, src.allocator.data);
|
||||||
|
} else {
|
||||||
|
internal_free(src.data);
|
||||||
|
}
|
||||||
src.count = 0;
|
src.count = 0;
|
||||||
src.data = nullptr;
|
src.data = nullptr;
|
||||||
src.allocated = 0;
|
src.allocated = 0;
|
||||||
@ -120,7 +137,15 @@ template <typename T>
|
|||||||
void array_reserve(Array<T>& src, s64 desired_items) {
|
void array_reserve(Array<T>& src, s64 desired_items) {
|
||||||
if (desired_items <= src.allocated) return;
|
if (desired_items <= src.allocated) return;
|
||||||
|
|
||||||
src.data = (T*)GPAllocator_Resize(src.allocated * sizeof(T), src.data, desired_items * sizeof(T), src.alignment);
|
src.data = nullptr;
|
||||||
|
if (src.allocator.proc == nullptr) {
|
||||||
|
src.allocator = get_context_allocator();
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert(src.allocator.proc != nullptr);
|
||||||
|
|
||||||
|
src.data = (T*)src.allocator.proc(Allocator_Mode::RESIZE, desired_items * sizeof(T), src.allocated * sizeof(T), nullptr, src.allocator.data);
|
||||||
|
|
||||||
Assert(src.data != nullptr);
|
Assert(src.data != nullptr);
|
||||||
|
|
||||||
src.allocated = desired_items;
|
src.allocated = desired_items;
|
||||||
@ -150,7 +175,7 @@ force_inline void array_maybe_grow(Array<T>& src) {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T pop(Array<T>& src) {
|
T pop(Array<T>& src) {
|
||||||
auto result = src[src.count-1]; // how do I dereference?
|
auto result = src[src.count-1];
|
||||||
src.count -= 1;
|
src.count -= 1;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -239,11 +264,9 @@ struct ArrayView {
|
|||||||
|
|
||||||
ArrayView() { count = 0; data = nullptr; }
|
ArrayView() { count = 0; data = nullptr; }
|
||||||
|
|
||||||
// If we don't need reallocation or alignments
|
ArrayView(s64 new_count, bool initialize=true) {
|
||||||
ArrayView(s64 new_count, s64 alignment=DEFAULT_ARRAY_ALIGNMENT, bool zero_memory=true) {
|
|
||||||
count = new_count;
|
count = new_count;
|
||||||
data = (T*)GPAllocator_New(new_count * sizeof(T), alignment);
|
data = NewArray<T>(new_count, initialize);
|
||||||
if (zero_memory) { memset(data, 0, new_count * sizeof(T)); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// #Note: use array_view to create slices or to downcast to ArrayView!
|
// #Note: use array_view to create slices or to downcast to ArrayView!
|
||||||
@ -315,7 +338,7 @@ ArrayView<T> array_view(Array<T> array, s64 start_index, s64 view_count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void array_reset_count(ArrayView<T>& src) {
|
void array_reset_keeping_memory(ArrayView<T>& src) {
|
||||||
src.count = 0;
|
src.count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +349,7 @@ ArrayView<T> array_copy(const ArrayView<T>& src) {
|
|||||||
return ArrayView<T>(); // Return an empty array
|
return ArrayView<T>(); // Return an empty array
|
||||||
}
|
}
|
||||||
|
|
||||||
void* new_data = GPAllocator_New(src.count * sizeof(T), DEFAULT_ARRAY_ALIGNMENT);
|
T* new_data = NewArray<T>(src.count);
|
||||||
memcpy(new_data, src.data, src.count * sizeof(T));
|
memcpy(new_data, src.data, src.count * sizeof(T));
|
||||||
|
|
||||||
return ArrayView<T>(src.count, (T*)new_data);
|
return ArrayView<T>(src.count, (T*)new_data);
|
||||||
@ -335,7 +358,9 @@ ArrayView<T> array_copy(const ArrayView<T>& src) {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
void array_free(ArrayView<T>& src) {
|
void array_free(ArrayView<T>& src) {
|
||||||
if (!src.data || src.count == 0) { return; }
|
if (!src.data || src.count == 0) { return; }
|
||||||
GPAllocator_Delete(src.data);
|
|
||||||
|
internal_free(src.data); // we just have to trust that the context.allocator is correct for this guy!
|
||||||
|
|
||||||
src.count = 0;
|
src.count = 0;
|
||||||
src.data = nullptr;
|
src.data = nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,28 +1,3 @@
|
|||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
|
|
||||||
// #TODO Split these up into platform_base (e.g. Windows_Base, Unix_Base...)
|
// #TODO Split these up into platform_base (e.g. Windows_Base, Unix_Base...)
|
||||||
#if OS_WINDOWS
|
|
||||||
#include <intrin.h>
|
|
||||||
|
|
||||||
int CPU_Base_Frequency() {
|
|
||||||
int cpuInfo[4] = {0};
|
|
||||||
|
|
||||||
// Call CPUID with EAX = 0x16 (Base CPU Frequency)
|
|
||||||
__cpuid(cpuInfo, 0x16);
|
|
||||||
|
|
||||||
return cpuInfo[0];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if OS_IS_UNIX
|
|
||||||
#include <cpuid.h>
|
|
||||||
|
|
||||||
int CPU_Base_Frequency() {
|
|
||||||
unsigned int eax, ebx, ecx, edx;
|
|
||||||
if (__get_cpuid(0x16, &eax, &ebx, &ecx, &edx)) {
|
|
||||||
return eax;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0; // not found or supported
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#define BUILD_CONSOLE_INTERFACE BUILD_DEBUG
|
#define BUILD_CONSOLE_INTERFACE BUILD_DEBUG
|
||||||
|
|
||||||
#if ARCH_CPU_X64
|
#if ARCH_CPU_X64
|
||||||
|
#include "CPU_X64.cpp"
|
||||||
#define PLATFORM_MEMORY_PAGE_SIZE 4096
|
#define PLATFORM_MEMORY_PAGE_SIZE 4096
|
||||||
#define PLATFORM_MEMORY_LARGE_PAGE_SIZE 2097152
|
#define PLATFORM_MEMORY_LARGE_PAGE_SIZE 2097152
|
||||||
#define CPU_REGISTER_WIDTH_BYTES 8
|
#define CPU_REGISTER_WIDTH_BYTES 8
|
||||||
@ -128,6 +129,9 @@ force_inline s64 Next_Power_Of_Two(s64 v) {
|
|||||||
#define Stringify_(S) #S
|
#define Stringify_(S) #S
|
||||||
#define Stringify(S) Stringify_(S)
|
#define Stringify(S) Stringify_(S)
|
||||||
|
|
||||||
|
#define Concat_(A,B) A##B
|
||||||
|
#define Concat(A,B) Concat_(A,B)
|
||||||
|
|
||||||
#if COMPILER_MSVC
|
#if COMPILER_MSVC
|
||||||
# define debug_break() __debugbreak()
|
# define debug_break() __debugbreak()
|
||||||
#elif COMPILER_CLANG || COMPILER_GCC
|
#elif COMPILER_CLANG || COMPILER_GCC
|
||||||
@ -171,6 +175,3 @@ force_inline s64 Next_Power_Of_Two(s64 v) {
|
|||||||
#define ForArrayStartingAt(_it_, _array_, _start_) for (s64 _it_ = _start_; _it_ < (_array_).count; _it_ += 1)
|
#define ForArrayStartingAt(_it_, _array_, _start_) for (s64 _it_ = _start_; _it_ < (_array_).count; _it_ += 1)
|
||||||
#define ForUpTo(_it_, _end_) for (s64 _it_ = 0; _it_ < _end_; _it_ += 1)
|
#define ForUpTo(_it_, _end_) for (s64 _it_ = 0; _it_ < _end_; _it_ += 1)
|
||||||
|
|
||||||
// #MOVE TO CPU_X64.cpp
|
|
||||||
PROTOTYPING_API int CPU_Base_Frequency();
|
|
||||||
|
|
||||||
|
|||||||
@ -15,17 +15,23 @@ struct string {
|
|||||||
data = nullptr;
|
data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
string(const char* cstr) {
|
string (char* cstr) {
|
||||||
count = strlen(cstr);
|
count = strlen(cstr);
|
||||||
data = (u8*)cstr;
|
data = (u8*)cstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string (s64 _count, char* str) { count = _count; data = (u8*)str; }
|
||||||
|
string (s64 _count, u8* str) { count = _count; data = str; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ~ API ~ #TODO
|
||||||
|
string copy_string (string str);
|
||||||
bool strings_match(string first_string, string second_string);
|
bool strings_match(string first_string, string second_string);
|
||||||
|
|
||||||
// ~ API ~ #TODO
|
// Unicode stuff
|
||||||
|
string wide_to_utf8 (u16* source, s32 length);
|
||||||
|
|
||||||
// string string_view(string n_string, int start_index, int view_count);
|
// string string_view(string n_string, int start_index, int view_count);
|
||||||
// string copy_string(string original_string);
|
|
||||||
// string copy_string(char* c_string);
|
// string copy_string(char* c_string);
|
||||||
// void free(string& n_string);
|
// void free(string& n_string);
|
||||||
|
|
||||||
|
|||||||
@ -21,3 +21,22 @@ void init_thread_context(Thread_Context* tctx) {
|
|||||||
Thread_Context* get_thread_context() {
|
Thread_Context* get_thread_context() {
|
||||||
return (Thread_Context*)thread_local_context;
|
return (Thread_Context*)thread_local_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
force_inline Allocator get_temp_allocator() {
|
||||||
|
return get_allocator(get_thread_context()->temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
force_inline Allocator get_context_allocator() {
|
||||||
|
Thread_Context* context = get_thread_context();
|
||||||
|
return context->allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
void temp_reset_keeping_memory() {
|
||||||
|
Thread_Context* context = get_thread_context();
|
||||||
|
arena_reset_keeping_memory(context->temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void temp_reset() {
|
||||||
|
Thread_Context* context = get_thread_context();
|
||||||
|
arena_reset(context->temp);
|
||||||
|
}
|
||||||
@ -24,7 +24,9 @@ struct Thread_Context {
|
|||||||
|
|
||||||
Thread_Context* get_thread_context();
|
Thread_Context* get_thread_context();
|
||||||
|
|
||||||
#define push_allocator(x) Push_Allocator guard(x) // maybe should append line number to guard?
|
// maybe should append line number to guard?
|
||||||
|
// This is stupid, and maybe should be something generated by a metaprogram?
|
||||||
|
#define push_allocator(x) Push_Allocator Concat(_push_alloc_guard_, __LINE__)(x)
|
||||||
struct Push_Allocator {
|
struct Push_Allocator {
|
||||||
Thread_Context* context;
|
Thread_Context* context;
|
||||||
Allocator old_allocator;
|
Allocator old_allocator;
|
||||||
@ -41,4 +43,9 @@ struct Push_Allocator {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Thread-local allocators:
|
||||||
|
PROTOTYPING_API Allocator get_temp_allocator();
|
||||||
|
PROTOTYPING_API Allocator get_context_allocator();
|
||||||
|
PROTOTYPING_API void reset_temp_allocator();
|
||||||
|
PROTOTYPING_API void free_temp_allocator();
|
||||||
|
|
||||||
|
|||||||
25
lib/Base/CPU_X64.cpp
Normal file
25
lib/Base/CPU_X64.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#if OS_WINDOWS
|
||||||
|
#include <intrin.h>
|
||||||
|
|
||||||
|
int CPU_Base_Frequency() {
|
||||||
|
int cpuInfo[4] = {0};
|
||||||
|
|
||||||
|
// Call CPUID with EAX = 0x16 (Base CPU Frequency)
|
||||||
|
__cpuid(cpuInfo, 0x16);
|
||||||
|
|
||||||
|
return cpuInfo[0];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if OS_IS_UNIX
|
||||||
|
#include <cpuid.h>
|
||||||
|
|
||||||
|
int CPU_Base_Frequency() {
|
||||||
|
unsigned int eax, ebx, ecx, edx;
|
||||||
|
if (__get_cpuid(0x16, &eax, &ebx, &ecx, &edx)) {
|
||||||
|
return eax;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // not found or supported
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -4,7 +4,6 @@
|
|||||||
#include <stdio.h> // vsnprintf, printf
|
#include <stdio.h> // vsnprintf, printf
|
||||||
#include <cstdarg> // va_list...
|
#include <cstdarg> // va_list...
|
||||||
|
|
||||||
// Should always be false when making python bindings.
|
|
||||||
#define BREAK_ON_WARNINGS 0
|
#define BREAK_ON_WARNINGS 0
|
||||||
#define BREAK_ON_ERRORS 0
|
#define BREAK_ON_ERRORS 0
|
||||||
#define BREAK_ON_FATAL_ERROR BUILD_DEBUG
|
#define BREAK_ON_FATAL_ERROR BUILD_DEBUG
|
||||||
@ -13,8 +12,10 @@
|
|||||||
Native_Error* Create_New_Native_Error_Internal(char* format, va_list args) {
|
Native_Error* Create_New_Native_Error_Internal(char* format, va_list args) {
|
||||||
constexpr s64 ERROR_BUFFER_COUNT = 512;
|
constexpr s64 ERROR_BUFFER_COUNT = 512;
|
||||||
|
|
||||||
auto error = ALLOCATE(Native_Error);
|
push_allocator(GPAllocator());
|
||||||
error->data = ALLOCATE_RAW_ARRAY(ERROR_BUFFER_COUNT, u8);
|
|
||||||
|
auto error = New<Native_Error>(false);
|
||||||
|
error->data = (u8*)GPAllocator_New(ERROR_BUFFER_COUNT);
|
||||||
|
|
||||||
// You MUST copy the va_list before using it more than once
|
// You MUST copy the va_list before using it more than once
|
||||||
va_list args_copy;
|
va_list args_copy;
|
||||||
@ -43,12 +44,14 @@ Native_Error* New_Fatal_Error_Internal(char* format, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Native_Error* Native_Error_Callstack(Native_Error* new_error, Native_Error* old_error, ErrorSeverity severity) {
|
Native_Error* Native_Error_Callstack(Native_Error* new_error, Native_Error* old_error, ErrorSeverity severity) {
|
||||||
|
push_allocator(GPAllocator());
|
||||||
|
|
||||||
auto error_message = format_string("%s\n > %s", new_error->data, old_error->data).data;
|
auto error_message = format_string("%s\n > %s", new_error->data, old_error->data).data;
|
||||||
|
|
||||||
Cleanup_Error(new_error);
|
Cleanup_Error(new_error);
|
||||||
Cleanup_Error(old_error);
|
Cleanup_Error(old_error);
|
||||||
|
|
||||||
Native_Error* error_merged = ALLOCATE(Native_Error);
|
Native_Error* error_merged = New<Native_Error>(false);
|
||||||
error_merged->data = (u8*)error_message;
|
error_merged->data = (u8*)error_message;
|
||||||
error_merged->count = strlen((char*)error_merged->data);
|
error_merged->count = strlen((char*)error_merged->data);
|
||||||
error_merged->severity = severity;
|
error_merged->severity = severity;
|
||||||
|
|||||||
@ -1,17 +1,15 @@
|
|||||||
// #TODO: Make this not MSVC-centric with alias for std::aligned_alloc / _aligned_malloc
|
|
||||||
// #TODO: Define GPAllocator_Proc
|
|
||||||
#include "General_Purpose_Allocator.h"
|
#include "General_Purpose_Allocator.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
General_Allocator gAllocator; // @Shared
|
global General_Allocator gAllocator; // @Shared
|
||||||
std::mutex allocator_mutex;
|
global std::mutex allocator_mutex;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !COMPILER_MSVC
|
#if !COMPILER_MSVC
|
||||||
// Note: There is *no* aligned_realloc. Must implement manually if needed.
|
// Note: There is *no* std::aligned_realloc. Must implement manually if needed.
|
||||||
force_inline void* gp_aligned_realloc(u64 old_size, void* ptr, u64 new_size, u64 alignment) {
|
force_inline void* gp_aligned_realloc(u64 old_size, void* ptr, u64 new_size, u64 alignment) {
|
||||||
if (!ptr || old_size == 0) return std::aligned_alloc(alignment, new_size);
|
if (!ptr || old_size == 0) return std::aligned_alloc(alignment, new_size);
|
||||||
if (new_size == 0) { std::free(ptr); return nullptr; }
|
if (new_size == 0) { std::free(ptr); return nullptr; }
|
||||||
@ -49,7 +47,7 @@ void GPAllocator_Initialize_Allocation_Tracker() {
|
|||||||
s64 item_count_max = 64 * 4096;
|
s64 item_count_max = 64 * 4096;
|
||||||
s64 total_allocation_size = item_count_max * sizeof(Allocation);
|
s64 total_allocation_size = item_count_max * sizeof(Allocation);
|
||||||
auto memory = Aligned_Alloc(total_allocation_size, alignment); // @MemoryLeak (intentional)
|
auto memory = Aligned_Alloc(total_allocation_size, alignment); // @MemoryLeak (intentional)
|
||||||
gAllocator.allocations = Array<Allocation>(item_count_max, memory, item_count_max, alignment);
|
gAllocator.allocations = Array<Allocation>(item_count_max, memory, item_count_max, GPAllocator());
|
||||||
gAllocator.allocations.count = 0; // Init to zero.
|
gAllocator.allocations.count = 0; // Init to zero.
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -139,7 +137,11 @@ Allocator GPAllocator() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void* GPAllocator_Proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data) {
|
void* GPAllocator_Proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data) {
|
||||||
u16 alignment = get_thread_context()->GPAllocator_alignment;
|
u16 alignment = 16; // default alignment
|
||||||
|
|
||||||
|
Thread_Context* tctx = get_thread_context();
|
||||||
|
if (tctx) alignment = tctx->GPAllocator_alignment;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case Allocator_Mode::ALLOCATE: {
|
case Allocator_Mode::ALLOCATE: {
|
||||||
return GPAllocator_New(requested_size, alignment);
|
return GPAllocator_New(requested_size, alignment);
|
||||||
|
|||||||
@ -43,13 +43,6 @@ General_Allocator* get_general_allocator_data();
|
|||||||
|
|
||||||
constexpr u16 GPAllocator_Default_Alignment = 16;
|
constexpr u16 GPAllocator_Default_Alignment = 16;
|
||||||
|
|
||||||
// #TODO: #REMOVE these:
|
|
||||||
#define ALLOCATE(type) \
|
|
||||||
(type*)GPAllocator_New(sizeof(type))
|
|
||||||
|
|
||||||
#define ALLOCATE_RAW_ARRAY(length, type) \
|
|
||||||
(type*)GPAllocator_New(sizeof(type) * (length))
|
|
||||||
|
|
||||||
Allocator GPAllocator();
|
Allocator GPAllocator();
|
||||||
|
|
||||||
void* GPAllocator_Proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data);
|
void* GPAllocator_Proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data);
|
||||||
|
|||||||
@ -14,12 +14,23 @@ bool is_valid(string n_string) {
|
|||||||
return (n_string.data != nullptr && n_string.count > 0);
|
return (n_string.data != nullptr && n_string.count > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string copy_string (string str) {
|
||||||
|
string new_str = {};
|
||||||
|
|
||||||
|
new_str.count = str.count;
|
||||||
|
new_str.data = (u8*)internal_alloc(str.count);
|
||||||
|
|
||||||
|
memcpy(new_str.data, str.data, str.count);
|
||||||
|
|
||||||
|
return new_str;
|
||||||
|
}
|
||||||
|
|
||||||
string format_string (char* format, ...) {
|
string format_string (char* format, ...) {
|
||||||
constexpr s64 BUFFER_SIZE = 1024;
|
constexpr s64 BUFFER_SIZE = 4096;
|
||||||
|
|
||||||
string str = {0};
|
string str = {0};
|
||||||
|
|
||||||
str.data = ALLOCATE_RAW_ARRAY(BUFFER_SIZE, u8);
|
str.data = NewArray<u8>(BUFFER_SIZE);
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
@ -30,21 +41,11 @@ string format_string(char* format, ...) {
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
string copy_string(string original_string) {
|
|
||||||
string str = {0};
|
|
||||||
|
|
||||||
str.data = ALLOCATE_RAW_ARRAY(original_string.count + 1, u8);
|
|
||||||
memcpy(str.data, original_string.data, original_string.count);
|
|
||||||
str.count = original_string.count;
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
string copy_string(char* c_string) {
|
string copy_string(char* c_string) {
|
||||||
string str = {0};
|
string str = {0};
|
||||||
s64 string_length = strlen(c_string);
|
s64 string_length = strlen(c_string);
|
||||||
|
|
||||||
str.data = ALLOCATE_RAW_ARRAY(string_length + 1, u8);
|
str.data = NewArray<u8>(string_length + 1);
|
||||||
memcpy(str.data, c_string, string_length);
|
memcpy(str.data, c_string, string_length);
|
||||||
str.count = string_length;
|
str.count = string_length;
|
||||||
|
|
||||||
@ -74,9 +75,36 @@ string string_from_literal(char* literal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void free(string& n_string) {
|
void free(string& n_string) {
|
||||||
// #TODO: Get context allocator?
|
internal_free(n_string.data);
|
||||||
GPAllocator_Delete(n_string.data);
|
|
||||||
|
|
||||||
n_string.data = nullptr;
|
n_string.data = nullptr;
|
||||||
n_string.count = 0;
|
n_string.count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unicode nonsense
|
||||||
|
string wide_to_utf8 (u16* source, s32 length) {
|
||||||
|
if (length == 0) return { };
|
||||||
|
|
||||||
|
s32 query_result = WideCharToMultiByte(CP_UTF8, 0, (LPCWCH)source, length,
|
||||||
|
nullptr, 0, nullptr, nullptr);
|
||||||
|
|
||||||
|
if (query_result <= 0) return { };
|
||||||
|
|
||||||
|
// Make room for a null terminator:
|
||||||
|
query_result += 1;
|
||||||
|
|
||||||
|
u8* memory = NewArray<u8>(query_result);
|
||||||
|
|
||||||
|
string utf8_string;
|
||||||
|
utf8_string.count = query_result;
|
||||||
|
utf8_string.data = memory;
|
||||||
|
|
||||||
|
s32 result = WideCharToMultiByte(CP_UTF8, 0, (LPCWCH)source, length,
|
||||||
|
(LPSTR)memory, query_result, nullptr, nullptr);
|
||||||
|
if (result <= 0) {
|
||||||
|
internal_free(memory);
|
||||||
|
return { };
|
||||||
|
}
|
||||||
|
|
||||||
|
return utf8_string;
|
||||||
|
}
|
||||||
47
src/Base_Entry_Point.cpp
Normal file
47
src/Base_Entry_Point.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
internal void Bootstrap_Main_Thread_Context () {
|
||||||
|
// 0. Setup general purpose allocator
|
||||||
|
GPAllocator_Initialize_Allocation_Tracker();
|
||||||
|
// 1. Setup arena table
|
||||||
|
initialize_arena_table();
|
||||||
|
// 2. Setup thread local context
|
||||||
|
Arena* arena = next_arena(Arena_Reserve::Size_64G);
|
||||||
|
thread_local_context = New<Thread_Context>(get_allocator(arena));
|
||||||
|
thread_local_context->temp = next_arena(Arena_Reserve::Size_64G);
|
||||||
|
thread_local_context->arena = arena;
|
||||||
|
thread_local_context->allocator = get_allocator(arena);
|
||||||
|
thread_local_context->thread_idx = 0;
|
||||||
|
thread_local_context->thread_name = "Main Thread";
|
||||||
|
// thread_local_context->logger = init_logger();
|
||||||
|
|
||||||
|
// debug_break();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// #include "lib/Base/Arena_Array.h"
|
||||||
|
void run_arena_array_tests () {
|
||||||
|
{ push_arena(thread_local_context->temp);
|
||||||
|
push_alignment(thread_local_context->temp, 1);
|
||||||
|
auto_reset(thread_local_context->temp);
|
||||||
|
auto something = New<Thread_Context>();
|
||||||
|
auto something2 = New<Array<s64>>();
|
||||||
|
auto something3 = internal_alloc(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ push_allocator(GPAllocator());
|
||||||
|
auto something = New<Thread_Context>();
|
||||||
|
auto something2 = New<Array<s64>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// { auto na = arena_array_new<s64>(64000, Arena_Reserve::Size_64G);
|
||||||
|
// array_add(...)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Main_Entry_Point (int argc, WCHAR **argv) {
|
||||||
|
run_arena_array_tests();
|
||||||
|
|
||||||
|
// #TODO:
|
||||||
|
// [ ] Launch second thread
|
||||||
|
// [ ] Setup Mouse and Keyboard Inputs
|
||||||
|
// OS_Create_Window();
|
||||||
|
}
|
||||||
166
src/OS_Win32.cpp
166
src/OS_Win32.cpp
@ -1,39 +1,155 @@
|
|||||||
// Move into src/Win32.cpp
|
// Move into src/Win32.cpp
|
||||||
|
|
||||||
// #MOVE TO Base_Entry_Point.cpp
|
struct OS_System_Info {
|
||||||
internal void Bootstrap_Entry_Point () {
|
s32 logical_processor_count;
|
||||||
// 0. Setup general purpose allocator
|
s32 physical_core_count;
|
||||||
GPAllocator_Initialize_Allocation_Tracker();
|
s32 primary_core_count;
|
||||||
// 1. Setup arena table
|
s32 secondary_core_count; // Any weaker or "Efficiency" cores.
|
||||||
initialize_arena_table();
|
u64 page_size;
|
||||||
// 2. Setup thread local context
|
u64 large_page_size;
|
||||||
Arena* arena = next_arena(Arena_Reserve::Size_64G);
|
u64 allocation_granularity;
|
||||||
thread_local_context = New<Thread_Context>(get_allocator(arena));
|
string machine_name;
|
||||||
thread_local_context->temp = next_arena(Arena_Reserve::Size_64G);
|
};
|
||||||
thread_local_context->arena = arena;
|
|
||||||
thread_local_context->allocator = get_allocator(arena);
|
|
||||||
thread_local_context->thread_idx = 0;
|
|
||||||
thread_local_context->thread_name = "Main Thread";
|
|
||||||
// thread_local_context.logger = init_logger();
|
|
||||||
|
|
||||||
// push_allocator(GPAllocator());
|
struct OS_Process_Info {
|
||||||
// auto something = New<Thread_Context>();
|
u32 process_id;
|
||||||
// auto something2 = New<Array<s64>>();
|
b32 large_pages_allowed;
|
||||||
|
string binary_path;
|
||||||
|
string working_path;
|
||||||
|
string user_program_data_path;
|
||||||
|
Array<string> module_load_paths;
|
||||||
|
Array<string> environment_paths;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OS_State_Win32 {
|
||||||
|
Arena* arena;
|
||||||
|
|
||||||
|
OS_System_Info system_info;
|
||||||
|
OS_Process_Info process_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
global OS_State_Win32 os_state_w32;
|
||||||
|
internal b32 win32_g_is_quiet = 0; // No console output
|
||||||
|
|
||||||
|
internal LONG WINAPI Win32_Exception_Filter (EXCEPTION_POINTERS* exception_ptrs) {
|
||||||
|
if (win32_g_is_quiet) { ExitProcess(1); }
|
||||||
|
|
||||||
|
static volatile LONG first = 0;
|
||||||
|
if(InterlockedCompareExchange(&first, 1, 0) != 0)
|
||||||
|
{ // prevent failures in other threads to popup same message box
|
||||||
|
// this handler just shows first thread that crashes
|
||||||
|
// we are terminating afterwards anyway
|
||||||
|
for (;;) Sleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #MOVE TO Base_Entry_Point.cpp
|
// #TODO: Exception handling code.
|
||||||
internal void Main_Entry_Point (int argc, WCHAR **argv) {
|
|
||||||
debug_break();
|
|
||||||
|
|
||||||
// #TODO: Run Tests?
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Win32_Entry_Point (int argc, WCHAR **argv) {
|
internal void Win32_Entry_Point (int argc, WCHAR **argv) {
|
||||||
// See: w32_entry_point_caller(); (raddebugger)
|
// See: w32_entry_point_caller(); (raddebugger)
|
||||||
// [ ] SetUnhandledExceptionFilter
|
SetUnhandledExceptionFilter(&Win32_Exception_Filter);
|
||||||
// [ ] Setup Thread Context:
|
|
||||||
Bootstrap_Entry_Point();
|
SYSTEM_INFO sysinfo = {0};
|
||||||
|
GetSystemInfo(&sysinfo);
|
||||||
|
|
||||||
|
// Try to allow large pages if we can.
|
||||||
|
// b32 large_pages_allowed = 0;
|
||||||
|
// {
|
||||||
|
// HANDLE token;
|
||||||
|
// if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
|
||||||
|
// {
|
||||||
|
// LUID luid;
|
||||||
|
// if(LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &luid))
|
||||||
|
// {
|
||||||
|
// TOKEN_PRIVILEGES priv;
|
||||||
|
// priv.PrivilegeCount = 1;
|
||||||
|
// priv.Privileges[0].Luid = luid;
|
||||||
|
// priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||||
|
// large_pages_allowed = !!AdjustTokenPrivileges(token, 0, &priv, sizeof(priv), 0, 0);
|
||||||
|
// }
|
||||||
|
// CloseHandle(token);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
Bootstrap_Main_Thread_Context();
|
||||||
|
|
||||||
|
push_arena(get_thread_context()->arena);
|
||||||
|
|
||||||
|
// #TODO: Need to write Win32 abstraction layer first.
|
||||||
|
{ OS_System_Info* info = &os_state_w32.system_info;
|
||||||
|
info->logical_processor_count = (s32)sysinfo.dwNumberOfProcessors;
|
||||||
|
info->page_size = sysinfo.dwPageSize;
|
||||||
|
info->large_page_size = GetLargePageMinimum();
|
||||||
|
info->allocation_granularity = sysinfo.dwAllocationGranularity;
|
||||||
|
}
|
||||||
|
{ OS_Process_Info* info = &os_state_w32.process_info;
|
||||||
|
info->large_pages_allowed = false;
|
||||||
|
info->process_id = GetCurrentProcessId();
|
||||||
|
}
|
||||||
|
/*{ OS_System_Info* info = &os_state_w32.system_info;
|
||||||
|
// [ ] Extract input args
|
||||||
|
u32 length;
|
||||||
|
GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, (PDWORD)&length);
|
||||||
|
u8* cpu_information_buffer = NewArray<u8>(length);
|
||||||
|
GetLogicalProcessorInformationEx(RelationProcessorCore, // *sigh*
|
||||||
|
(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)cpu_information_buffer, (PDWORD)&length);
|
||||||
|
|
||||||
|
u32 offset = 0;
|
||||||
|
|
||||||
|
u32 all_cpus_count = 0;
|
||||||
|
u32 max_performance = 0;
|
||||||
|
u32 performance_core_count = 0;
|
||||||
|
// u32 efficient_core_count;
|
||||||
|
|
||||||
|
while (offset < length) {
|
||||||
|
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* cpu_information
|
||||||
|
= (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(cpu_information_buffer + offset);
|
||||||
|
|
||||||
|
offset += cpu_information->Size;
|
||||||
|
|
||||||
|
u32 count_per_group_physical = 1;
|
||||||
|
u32 value = (u32)cpu_information->Processor.GroupMask->Mask;
|
||||||
|
u32 count_per_group = __popcnt(value); // logical
|
||||||
|
if (cpu_information->Relationship != RelationProcessorCore) continue;
|
||||||
|
|
||||||
|
if (cpu_information->Processor.EfficiencyClass > max_performance) {
|
||||||
|
max_performance = cpu_information->Processor.EfficiencyClass;
|
||||||
|
performance_core_count = count_per_group_physical;
|
||||||
|
} else if (cpu_information->Processor.EfficiencyClass == max_performance) {
|
||||||
|
performance_core_count += count_per_group_physical;
|
||||||
|
}
|
||||||
|
|
||||||
|
all_cpus_count += count_per_group;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->physical_core_count = (s32)all_cpus_count;
|
||||||
|
info->primary_core_count = (s32)performance_core_count;
|
||||||
|
}
|
||||||
|
// info->secondary_core_count = #TODO;
|
||||||
|
*/
|
||||||
|
{ OS_System_Info* info = &os_state_w32.system_info;
|
||||||
|
u8 buffer[MAX_COMPUTERNAME_LENGTH + 1] = {0};
|
||||||
|
DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
|
||||||
|
if(GetComputerNameA((char*)buffer, &size)) {
|
||||||
|
string machine_name_temp = string(size, buffer);
|
||||||
|
info->machine_name = copy_string(machine_name_temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_break();
|
||||||
|
|
||||||
|
{ OS_Process_Info* info = &os_state_w32.process_info;
|
||||||
|
DWORD length = GetCurrentDirectoryW(0, 0);
|
||||||
|
// This can be freed later when we call temp_reset();
|
||||||
|
u16* memory = NewArray<u16>(get_temp_allocator(), length + 1);
|
||||||
|
length = GetCurrentDirectoryW(length + 1, (WCHAR*)memory);
|
||||||
|
info->working_path = wide_to_utf8(memory, length);
|
||||||
|
Assert(is_valid(info->working_path));
|
||||||
|
}
|
||||||
|
// [ ] Get Working directory (info->working_path)
|
||||||
|
// [ ] GetEnvironmentStringsW
|
||||||
|
|
||||||
printf("Hello there!\n\n");
|
printf("Hello there!\n\n");
|
||||||
// See: main_thread_base_entry_point
|
// See: main_thread_base_entry_point
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
#include "unity_build_lib.cpp"
|
#include "unity_build_lib.cpp"
|
||||||
|
#include "Base_Entry_Point.cpp"
|
||||||
|
// #include "imgui-docking.cpp"
|
||||||
#include "src/OS_Win32.cpp"
|
#include "src/OS_Win32.cpp"
|
||||||
// #include "src/OS_Linux.cpp"
|
// #include "src/OS_Linux.cpp"
|
||||||
// #include "src/OS_MacOS.cpp"
|
// #include "src/OS_MacOS.cpp"
|
||||||
|
|
||||||
// #include "imgui-docking.cpp"
|
|
||||||
|
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
#if BUILD_CONSOLE_INTERFACE
|
#if BUILD_CONSOLE_INTERFACE
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user