- Start work on string library
- Dyamically load minimum crt symbols in os backend so we don't need to #include c headers - Some more os calls: - write to stdout (with our string type) - macros for variadic argument lists - Dynamic library loading
This commit is contained in:
parent
98feda0cbb
commit
68d1efb759
8 changed files with 238 additions and 18 deletions
2
build.c
2
build.c
|
@ -2,7 +2,7 @@
|
||||||
///
|
///
|
||||||
// Build config stuff
|
// Build config stuff
|
||||||
#define VERY_DEBUG 0
|
#define VERY_DEBUG 0
|
||||||
#define RUN_TESTS 0
|
#define RUN_TESTS 1
|
||||||
|
|
||||||
typedef struct Context_Extra {
|
typedef struct Context_Extra {
|
||||||
int monkee;
|
int monkee;
|
||||||
|
|
|
@ -29,13 +29,43 @@ typedef u8 bool;
|
||||||
|
|
||||||
#define assert(cond, ...) if (!(cond)) { printf("Assertion failed for condition: " #cond ". Message: " __VA_ARGS__); os_debug_break(); }
|
#define assert(cond, ...) if (!(cond)) { printf("Assertion failed for condition: " #cond ". Message: " __VA_ARGS__); os_debug_break(); }
|
||||||
|
|
||||||
#ifndef max
|
|
||||||
#define max(a, b) ((a) > (b) ? (a) : (b))
|
|
||||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define cast(t) (t)
|
#define cast(t) (t)
|
||||||
|
|
||||||
|
///
|
||||||
|
// inline
|
||||||
|
// (Credit to chatgpt, so it might not be 100% correct)
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
// Microsoft Visual C++
|
||||||
|
#define inline __forceinline
|
||||||
|
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||||
|
// GNU GCC/G++
|
||||||
|
#define inline __attribute__((always_inline)) inline
|
||||||
|
#elif defined(__clang__)
|
||||||
|
// Clang/LLVM
|
||||||
|
#define inline __attribute__((always_inline)) inline
|
||||||
|
#elif defined(__INTEL_COMPILER) || defined(__ICC)
|
||||||
|
// Intel C++ Compiler
|
||||||
|
#define inline __forceinline
|
||||||
|
#elif defined(__BORLANDC__)
|
||||||
|
// Borland C++
|
||||||
|
#define inline __inline
|
||||||
|
#elif defined(__MINGW32__) || defined(__MINGW64__)
|
||||||
|
// MinGW (Minimalist GNU for Windows)
|
||||||
|
#define inline __attribute__((always_inline)) inline
|
||||||
|
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
||||||
|
// Oracle Solaris Studio
|
||||||
|
#define inline inline __attribute__((always_inline))
|
||||||
|
#elif defined(__IBMC__) || defined(__IBMCPP__)
|
||||||
|
// IBM XL C/C++ Compiler
|
||||||
|
#define inline __attribute__((always_inline)) inline
|
||||||
|
#elif defined(__PGI)
|
||||||
|
// Portland Group Compiler
|
||||||
|
#define inline inline __attribute__((always_inline))
|
||||||
|
#else
|
||||||
|
// Fallback for unknown compilers
|
||||||
|
#define inline inline
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct Nothing {int nothing;} Nothing;
|
typedef struct Nothing {int nothing;} Nothing;
|
||||||
|
|
||||||
#ifndef CONTEXT_EXTRA
|
#ifndef CONTEXT_EXTRA
|
||||||
|
|
|
@ -164,10 +164,11 @@ void heap_init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void *heap_alloc(u64 size) {
|
void *heap_alloc(u64 size) {
|
||||||
// #Sync #Speed oof
|
|
||||||
os_lock_mutex(heap_mutex);
|
|
||||||
|
|
||||||
if (!heap_initted) heap_init();
|
if (!heap_initted) heap_init();
|
||||||
|
|
||||||
|
// #Sync #Speed oof
|
||||||
|
os_lock_mutex(heap_mutex);
|
||||||
|
|
||||||
size += sizeof(Heap_Allocation_Metadata);
|
size += sizeof(Heap_Allocation_Metadata);
|
||||||
|
|
||||||
|
@ -262,9 +263,10 @@ void *heap_alloc(u64 size) {
|
||||||
}
|
}
|
||||||
void heap_dealloc(void *p) {
|
void heap_dealloc(void *p) {
|
||||||
// #Sync #Speed oof
|
// #Sync #Speed oof
|
||||||
os_lock_mutex(heap_mutex);
|
|
||||||
|
|
||||||
if (!heap_initted) heap_init();
|
if (!heap_initted) heap_init();
|
||||||
|
|
||||||
|
os_lock_mutex(heap_mutex);
|
||||||
|
|
||||||
assert(is_pointer_in_program_memory(p), "Garbage pointer; out of program memory bounds!");
|
assert(is_pointer_in_program_memory(p), "Garbage pointer; out of program memory bounds!");
|
||||||
p = (u8*)p-sizeof(Heap_Allocation_Metadata);
|
p = (u8*)p-sizeof(Heap_Allocation_Metadata);
|
||||||
|
@ -431,3 +433,8 @@ void reset_temporary_storage() {
|
||||||
has_warned_temporary_storage_overflow = true;
|
has_warned_temporary_storage_overflow = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// So we can do this in code included before this.
|
||||||
|
void push_temp_allocator() {
|
||||||
|
if (!temporary_storage_initted) temporary_storage_init();
|
||||||
|
push_allocator(temp);
|
||||||
|
}
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
|
|
||||||
#include <stdio.h> // #Cleanup just using this for printf
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "base.c"
|
#include "base.c"
|
||||||
|
|
||||||
|
#include "string.c"
|
||||||
|
|
||||||
#include "os_interface.c"
|
#include "os_interface.c"
|
||||||
|
|
||||||
#include "memory.c"
|
#include "memory.c"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef OS_WINDOWS
|
#ifdef OS_WINDOWS
|
||||||
#include "os_impl_windows.c"
|
#include "os_impl_windows.c"
|
||||||
#elif defined (OS_LINUX)
|
#elif defined (OS_LINUX)
|
||||||
|
@ -24,6 +22,6 @@
|
||||||
|
|
||||||
void oogabooga_init(u64 program_memory_size) {
|
void oogabooga_init(u64 program_memory_size) {
|
||||||
os_init(program_memory_size);
|
os_init(program_memory_size);
|
||||||
heap_init();
|
heap_init();
|
||||||
temporary_storage_init();
|
temporary_storage_init();
|
||||||
}
|
}
|
|
@ -37,6 +37,20 @@ void os_init(u64 program_memory_size) {
|
||||||
|
|
||||||
context.allocator = heap_allocator;
|
context.allocator = heap_allocator;
|
||||||
|
|
||||||
|
os.crt = os_load_dynamic_library(const_string("msvcrt.dll"));
|
||||||
|
assert(os.crt != 0, "Could not load win32 crt library. Might be compiled with non-msvc? #Incomplete #Portability");
|
||||||
|
os.crt_vprintf = (Crt_Vprintf_Proc)os_dynamic_library_load_symbol(os.crt, const_string("vprintf"));
|
||||||
|
assert(os.crt_vprintf, "Missing vprintf in crt");
|
||||||
|
os.crt_printf = (Crt_Printf_Proc)os_dynamic_library_load_symbol(os.crt, const_string("printf"));
|
||||||
|
assert(os.crt_printf, "Missing printf in crt");
|
||||||
|
os.crt_vsnprintf = (Crt_Vsnprintf_Proc)os_dynamic_library_load_symbol(os.crt, const_string("vsnprintf"));
|
||||||
|
assert(os.crt_vsnprintf, "Missing vsnprintf in crt");
|
||||||
|
os.crt_memcpy = (Crt_Memcpy_Proc)os_dynamic_library_load_symbol(os.crt, const_string("memcpy"));
|
||||||
|
assert(os.crt_memcpy, "Missing memcpy in crt");
|
||||||
|
os.crt_memcmp = (Crt_Memcmp_Proc)os_dynamic_library_load_symbol(os.crt, const_string("memcmp"));
|
||||||
|
assert(os.crt_memcmp, "Missing crt_memcmp in crt");
|
||||||
|
os.crt_memset = (Crt_Memset_Proc)os_dynamic_library_load_symbol(os.crt, const_string("memset"));
|
||||||
|
assert(os.crt_memset, "Missing memset in crt");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool os_grow_program_memory(u64 new_size) {
|
bool os_grow_program_memory(u64 new_size) {
|
||||||
|
@ -171,4 +185,23 @@ float64 os_get_current_time_in_seconds() {
|
||||||
return -1.0;
|
return -1.0;
|
||||||
}
|
}
|
||||||
return (double)counter.QuadPart / (double)frequency.QuadPart;
|
return (double)counter.QuadPart / (double)frequency.QuadPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Dynamic_Library_Handle os_load_dynamic_library(string path) {
|
||||||
|
return LoadLibraryA(temp_convert_to_null_terminated_string(path));
|
||||||
|
}
|
||||||
|
void *os_dynamic_library_load_symbol(Dynamic_Library_Handle l, string identifier) {
|
||||||
|
return GetProcAddress(l, temp_convert_to_null_terminated_string(identifier));
|
||||||
|
}
|
||||||
|
void os_unload_dynamic_library(Dynamic_Library_Handle l) {
|
||||||
|
FreeLibrary(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void os_write_string_to_stdout(string s) {
|
||||||
|
HANDLE win32_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
if (win32_stdout == INVALID_HANDLE_VALUE) return;
|
||||||
|
|
||||||
|
WriteFile(win32_stdout, s.data, s.count, 0, NULL);
|
||||||
}
|
}
|
|
@ -6,32 +6,111 @@
|
||||||
|
|
||||||
typedef HANDLE Mutex_Handle;
|
typedef HANDLE Mutex_Handle;
|
||||||
typedef HANDLE Thread_Handle;
|
typedef HANDLE Thread_Handle;
|
||||||
|
typedef HMODULE Dynamic_Library_Handle;
|
||||||
|
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
// Include whatever #Incomplete #Portability
|
// Include whatever #Incomplete #Portability
|
||||||
#define OS_LINUX
|
#define OS_LINUX
|
||||||
|
|
||||||
typedef SOMETHING Mutex_Handle;
|
typedef SOMETHING Mutex_Handle;
|
||||||
typedef SOMETHING Thread_Handle;
|
typedef SOMETHING Thread_Handle;
|
||||||
|
typedef SOMETHING Dynamic_Library_Handle;
|
||||||
|
|
||||||
|
#error "Linux is not supported yet";
|
||||||
#elif defined(__APPLE__) && defined(__MACH__)
|
#elif defined(__APPLE__) && defined(__MACH__)
|
||||||
// Include whatever #Incomplete #Portability
|
// Include whatever #Incomplete #Portability
|
||||||
#define OS_MAC
|
#define OS_MAC
|
||||||
|
|
||||||
typedef SOMETHING Mutex_Handle;
|
typedef SOMETHING Mutex_Handle;
|
||||||
typedef SOMETHING Thread_Handle;
|
typedef SOMETHING Thread_Handle;
|
||||||
|
typedef SOMETHING Dynamic_Library_Handle;
|
||||||
|
#error "Mac is not supported yet";
|
||||||
#else
|
#else
|
||||||
#error "Current OS not supported!";
|
#error "Current OS not supported!";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef max
|
||||||
|
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1))
|
||||||
|
|
||||||
|
#define oogabooga_va_start(ap, v) (ap = (va_list)&v + _INTSIZEOF(v))
|
||||||
|
#define oogabooga_va_arg(ap, t) (*(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))
|
||||||
|
#define oogabooga_va_end(ap) (ap = (va_list)0)
|
||||||
|
|
||||||
|
typedef void* (__cdecl *Crt_Memcpy_Proc) (void*, const void*, size_t);
|
||||||
|
typedef int (__cdecl *Crt_Memcmp_Proc) (const void*, const void*, size_t);
|
||||||
|
typedef void* (__cdecl *Crt_Memset_Proc) (void*, int, size_t);
|
||||||
|
typedef int (__cdecl *Crt_Printf_Proc) (const char*, ...);
|
||||||
|
typedef int (__cdecl *Crt_Vprintf_Proc) (const char*, va_list);
|
||||||
|
typedef int (__cdecl *Crt_Vsnprintf_Proc) (char*, size_t, const char*, va_list);
|
||||||
|
|
||||||
typedef struct Os_Info {
|
typedef struct Os_Info {
|
||||||
u64 page_size;
|
u64 page_size;
|
||||||
u64 granularity;
|
u64 granularity;
|
||||||
|
|
||||||
|
Dynamic_Library_Handle crt;
|
||||||
|
|
||||||
|
Crt_Memcpy_Proc crt_memcpy;
|
||||||
|
Crt_Memcmp_Proc crt_memcmp;
|
||||||
|
Crt_Memset_Proc crt_memset;
|
||||||
|
Crt_Printf_Proc crt_printf; // #Cleanup remove after we have our own print
|
||||||
|
Crt_Vprintf_Proc crt_vprintf; // #Cleanup remove after we have our own print
|
||||||
|
Crt_Vsnprintf_Proc crt_vsnprintf;
|
||||||
|
|
||||||
} Os_Info;
|
} Os_Info;
|
||||||
Os_Info os;
|
Os_Info os;
|
||||||
|
|
||||||
|
inline void* naive_memcpy(void* dest, const void* source, size_t size) {
|
||||||
|
for (u64 i = 0; i < (u64)size; i++) ((u8*)dest)[i] = ((u8*)source)[i];
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
inline void* memcpy(void* dest, const void* source, size_t size) {
|
||||||
|
if (!os.crt_memcpy) return naive_memcpy(dest, source, size);
|
||||||
|
return os.crt_memcpy(dest, source, size);
|
||||||
|
}
|
||||||
|
inline int naive_memcmp(const void* a, const void* b, size_t amount) {
|
||||||
|
// I don't understand the return value of memcmp but I also dont care
|
||||||
|
for (u64 i = 0; i < (u64)amount; i++) {
|
||||||
|
if (((u8*)a)[i] != ((u8*)b)[i]) return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
inline int memcmp(const void* a, const void* b, size_t amount) {
|
||||||
|
if (!os.crt_memcmp) return naive_memcmp(a, b, amount);
|
||||||
|
return os.crt_memcmp(a, b, amount);
|
||||||
|
}
|
||||||
|
inline void* naive_memset(void* dest, int value, size_t amount) {
|
||||||
|
for (u64 i = 0; i < (u64)amount; i++) ((u8*)dest)[i] = (u8)value;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
inline void* memset(void* dest, int value, size_t amount) {
|
||||||
|
if (!os.crt_memset) return naive_memset(dest, value, amount);
|
||||||
|
return os.crt_memset(dest, value, amount);
|
||||||
|
}
|
||||||
|
inline int printf(const char* fmt, ...) {
|
||||||
|
char fast_buffer[8196];
|
||||||
|
char *large_buffer = 0;
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
oogabooga_va_start(args, fmt);
|
||||||
|
int r = vprintf(fmt, args);
|
||||||
|
oogabooga_va_end(args);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
void os_write_string_to_stdout(string s);
|
||||||
|
inline int vprintf(const char* fmt, va_list args) {
|
||||||
|
if (os.crt_vprintf) return os.crt_vprintf(fmt, args);
|
||||||
|
else {
|
||||||
|
os_write_string_to_stdout(cstr(fmt));
|
||||||
|
os_write_string_to_stdout(cstr(" <crt_vprintf is not loaded so we cannot vprintf.>"));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline int vsnprintf(char* buffer, size_t n, const char* fmt, va_list args) {
|
||||||
|
os.crt_vsnprintf(buffer, n, fmt, args);
|
||||||
|
}
|
||||||
|
|
||||||
void* program_memory = 0;
|
void* program_memory = 0;
|
||||||
u64 program_memory_size = 0;
|
u64 program_memory_size = 0;
|
||||||
|
@ -80,4 +159,23 @@ void os_unlock_mutex(Mutex_Handle m);
|
||||||
///
|
///
|
||||||
|
|
||||||
u64 os_get_current_cycle_count();
|
u64 os_get_current_cycle_count();
|
||||||
float64 os_get_current_time_in_seconds();
|
float64 os_get_current_time_in_seconds();
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
// Dynamic Libraries
|
||||||
|
///
|
||||||
|
|
||||||
|
Dynamic_Library_Handle os_load_dynamic_library(string path);
|
||||||
|
void *os_dynamic_library_load_symbol(Dynamic_Library_Handle l, string identifier);
|
||||||
|
void os_unload_dynamic_library(Dynamic_Library_Handle l);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
// IO
|
||||||
|
///
|
||||||
|
|
||||||
|
void os_write_string_to_stdout(string s);
|
45
oogabooga/string.c
Normal file
45
oogabooga/string.c
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
|
||||||
|
void * memcpy (void *,const void *,size_t);
|
||||||
|
|
||||||
|
typedef struct string {
|
||||||
|
u8 *data;
|
||||||
|
u64 count;
|
||||||
|
} string;
|
||||||
|
|
||||||
|
void push_temp_allocator();
|
||||||
|
|
||||||
|
#define cstr const_string
|
||||||
|
#define const_string(s) (string){ (u8*)s, length_of_null_terminated_string(s) }
|
||||||
|
|
||||||
|
inline u64 length_of_null_terminated_string(const char* cstring) {
|
||||||
|
u64 len = 0;
|
||||||
|
while (*cstring != 0) {
|
||||||
|
len += 1;
|
||||||
|
cstring += 1;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// context.allocator !
|
||||||
|
string string_concat(string left, string right) {
|
||||||
|
string result;
|
||||||
|
result.count = left.count + right.count;
|
||||||
|
result.data = cast(u8*)alloc(result.count);
|
||||||
|
memcpy(result.data, left.data, left.count);
|
||||||
|
memcpy(result.data+left.count, right.data, right.count);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// context.allocator !
|
||||||
|
char *convert_to_null_terminated_string(string s) {
|
||||||
|
char *cstring = cast(char*)alloc(s.count+1);
|
||||||
|
memcpy(cstring, s.data, s.count);
|
||||||
|
cstring[s.count] = 0;
|
||||||
|
return cstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *temp_convert_to_null_terminated_string(string s) {
|
||||||
|
push_temp_allocator();
|
||||||
|
char *c = convert_to_null_terminated_string(s);
|
||||||
|
pop_allocator();
|
||||||
|
return c;
|
||||||
|
}
|
|
@ -221,6 +221,11 @@ void test_allocator_threaded(Thread *t) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_strings() {
|
||||||
|
string s = (string){ (u8*)"Ooga booga", length_of_null_terminated_string("Ooga booga") };
|
||||||
|
string a = const_string("Ooga booga");
|
||||||
|
}
|
||||||
|
|
||||||
void oogabooga_run_tests() {
|
void oogabooga_run_tests() {
|
||||||
printf("Testing allocator...\n");
|
printf("Testing allocator...\n");
|
||||||
test_allocator(true);
|
test_allocator(true);
|
||||||
|
@ -229,6 +234,10 @@ void oogabooga_run_tests() {
|
||||||
printf("Testing threads...\n");
|
printf("Testing threads...\n");
|
||||||
test_threads();
|
test_threads();
|
||||||
printf("OK!\n");
|
printf("OK!\n");
|
||||||
|
|
||||||
|
printf("Testing strings...\n");
|
||||||
|
test_strings();
|
||||||
|
printf("OK!\n");
|
||||||
|
|
||||||
printf("Thread bombing allocator...\n");
|
printf("Thread bombing allocator...\n");
|
||||||
Thread* threads[100];
|
Thread* threads[100];
|
||||||
|
|
Reference in a new issue