base layer, mostly stolen
This commit is contained in:
@@ -0,0 +1,691 @@
|
|||||||
|
// good base layer overview https://www.youtube.com/watch?v=bUOOaXf9qIM
|
||||||
|
#ifndef BASE_ALL_H
|
||||||
|
#define BASE_ALL_H
|
||||||
|
|
||||||
|
///// Context Cracking
|
||||||
|
// Development Settings
|
||||||
|
#if !defined(ENABLE_ASSERT)
|
||||||
|
# define ENABLE_ASSERT 1
|
||||||
|
#endif
|
||||||
|
#if !defined(ENABLE_SANITIZER)
|
||||||
|
# define ENABLE_SANITIZER 0
|
||||||
|
#endif
|
||||||
|
#if !defined(ENABLE_MANUAL_PROFILE)
|
||||||
|
# define ENABLE_MANUAL_PROFILE 0
|
||||||
|
#endif
|
||||||
|
#if !defined(ENABLE_AUTO_PROFILE)
|
||||||
|
# define ENABLE_AUTO_PROFILE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_ANY_PROFILE)
|
||||||
|
# error user should not configure ENABLE_ANY_PROFILE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ENABLE_MANUAL_PROFILE || ENABLE_AUTO_PROFILE
|
||||||
|
# define ENABLE_ANY_PROFILE 1
|
||||||
|
#else
|
||||||
|
# define ENABLE_ANY_PROFILE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Untangle Compiler, OS & Architecture
|
||||||
|
#if defined(__clang__)
|
||||||
|
# define COMPILER_CLANG 1
|
||||||
|
|
||||||
|
# if defined(_WIN32)
|
||||||
|
# define OS_WINDOWS 1
|
||||||
|
# elif defined(__gnu_linux__)
|
||||||
|
# define OS_LINUX 1
|
||||||
|
# elif defined(__APPLE__) && defined(__MACH__)
|
||||||
|
# define OS_MAC 1
|
||||||
|
# else
|
||||||
|
# error missing OS detection
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(__amd64__)
|
||||||
|
# define ARCH_X64 1
|
||||||
|
// TODO verify this works on clang
|
||||||
|
# elif defined(__i386__)
|
||||||
|
# define ARCH_X86 1
|
||||||
|
// TODO verify this works on clang
|
||||||
|
# elif defined(__arm__)
|
||||||
|
# define ARCH_ARM 1
|
||||||
|
// TODO verify this works on clang
|
||||||
|
# elif defined(__aarch64__)
|
||||||
|
# define ARCH_ARM64 1
|
||||||
|
# else
|
||||||
|
# error missing ARCH detection
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
# define COMPILER_CL 1
|
||||||
|
|
||||||
|
# if defined(_WIN32)
|
||||||
|
# define OS_WINDOWS 1
|
||||||
|
# else
|
||||||
|
# error missing OS detection
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(_M_AMD64)
|
||||||
|
# define ARCH_X64 1
|
||||||
|
# elif defined(_M_I86)
|
||||||
|
# define ARCH_X86 1
|
||||||
|
# elif defined(_M_ARM)
|
||||||
|
# define ARCH_ARM 1
|
||||||
|
// TODO ARM64?
|
||||||
|
# else
|
||||||
|
# error missing ARCH detection
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# define COMPILER_GCC 1
|
||||||
|
|
||||||
|
# if defined(_WIN32)
|
||||||
|
# define OS_WINDOWS 1
|
||||||
|
# elif defined(__gnu_linux__)
|
||||||
|
# define OS_LINUX 1
|
||||||
|
# elif defined(__APPLE__) && defined(__MACH__)
|
||||||
|
# define OS_MAC 1
|
||||||
|
# else
|
||||||
|
# error missing OS detection
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(__amd64__)
|
||||||
|
# define ARCH_X64 1
|
||||||
|
# elif defined(__i386__)
|
||||||
|
# define ARCH_X86 1
|
||||||
|
# elif defined(__arm__)
|
||||||
|
# define ARCH_ARM 1
|
||||||
|
# elif defined(__aarch64__)
|
||||||
|
# define ARCH_ARM64 1
|
||||||
|
# else
|
||||||
|
# error missing ARCH detection
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error no context cracking for this compiler
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(COMPILER_CL)
|
||||||
|
# define COMPILER_CL 0
|
||||||
|
#endif
|
||||||
|
#if !defined(COMPILER_CLANG)
|
||||||
|
# define COMPILER_CLANG 0
|
||||||
|
#endif
|
||||||
|
#if !defined(COMPILER_GCC)
|
||||||
|
# define COMPILER_GCC 0
|
||||||
|
#endif
|
||||||
|
#if !defined(OS_WINDOWS)
|
||||||
|
# define OS_WINDOWS 0
|
||||||
|
#endif
|
||||||
|
#if !defined(OS_LINUX)
|
||||||
|
# define OS_LINUX 0
|
||||||
|
#endif
|
||||||
|
#if !defined(OS_MAC)
|
||||||
|
# define OS_MAC 0
|
||||||
|
#endif
|
||||||
|
#if !defined(ARCH_X64)
|
||||||
|
# define ARCH_X64 0
|
||||||
|
#endif
|
||||||
|
#if !defined(ARCH_X86)
|
||||||
|
# define ARCH_X86 0
|
||||||
|
#endif
|
||||||
|
#if !defined(ARCH_ARM)
|
||||||
|
# define ARCH_ARM 0
|
||||||
|
#endif
|
||||||
|
#if !defined(ARCH_ARM64)
|
||||||
|
# define ARCH_ARM64 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Language
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
# define LANG_CXX 1
|
||||||
|
#else
|
||||||
|
# define LANG_C 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(LANG_CXX)
|
||||||
|
# define LANG_CXX 0
|
||||||
|
#endif
|
||||||
|
#if !defined(LANG_C)
|
||||||
|
# define LANG_C 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Profiler
|
||||||
|
#if !defined(PROFILER_SPALL)
|
||||||
|
# define PROFILER_SPALL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Determine Intrinsics Mode
|
||||||
|
#if OS_WINDOWS
|
||||||
|
# if COMPILER_CL || COMPILER_CLANG
|
||||||
|
# define INTRINSICS_MICROSOFT 1
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(INTRINSICS_MICROSOFT)
|
||||||
|
# define INTRINSICS_MICROSOFT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Setup Pointer Size Macro
|
||||||
|
#if ARCH_X64 || ARCH_ARM64
|
||||||
|
# define ARCH_ADDRSIZE 64
|
||||||
|
#else
|
||||||
|
# define ARCH_ADDRSIZE 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///// MACROS
|
||||||
|
#define global static
|
||||||
|
#define internal static
|
||||||
|
#define fn static
|
||||||
|
|
||||||
|
#define arrayLen(a) (sizeof(a)/sizeof(*(a)))
|
||||||
|
|
||||||
|
#define intFromPtr(p) (U64)((U8*)p - (U8*)0)
|
||||||
|
#define ptrFromInt(n) (void*)((U8*)0 + (n))
|
||||||
|
|
||||||
|
#define stmnt(S) do{ S }while(0)
|
||||||
|
|
||||||
|
#if !defined(assertBreak)
|
||||||
|
# define assertBreak() (*(volatile int*)0 = 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef offsetof
|
||||||
|
# define offsetof(st, m) ((size_t)&(((st*)0)->m))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ENABLE_ASSERT
|
||||||
|
# define assert(c) stmnt( if (!(c)){ assertBreak(); } )
|
||||||
|
#else
|
||||||
|
# define assert(c)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ToBool(x) ((x) != 0)
|
||||||
|
|
||||||
|
#define KB(x) ((x) << 10)
|
||||||
|
#define MB(x) ((x) << 20)
|
||||||
|
#define GB(x) ((x) << 30)
|
||||||
|
#define TB(x) ((u64)(x) << 40llu)
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#define MemoryCopy(d,s,z) memmove((d), (s), (z))
|
||||||
|
#define MemoryCopyStruct(d,s) MemoryCopy((d),(s), Min(sizeof(*(d)) , sizeof(*(s))))
|
||||||
|
#define MemoryZero(d,z) memset((d), 0, (z))
|
||||||
|
#define MemoryZeroStruct(d,s) MemoryZero((d),sizeof(s))
|
||||||
|
#define Min(a,b) (((a)<(b))?(a):(b))
|
||||||
|
#define Max(a,b) (((a)>(b))?(a):(b))
|
||||||
|
#define Abs(x) (((x)<0)?((x)*-1):(x))
|
||||||
|
|
||||||
|
#define SetFlag(flags, bit) ((flags) |= (1ULL << (bit)))
|
||||||
|
#define ClearFlag(flags, bit) ((flags) &= ~(1ULL << (bit)))
|
||||||
|
#define ToggleFlag(flags, bit) ((flags) ^= (1ULL << (bit)))
|
||||||
|
#define CheckFlag(flags, bit) (((flags) >> (bit)) & 1ULL)
|
||||||
|
|
||||||
|
#define QueuePush(f,l,n) (((f)==NULL) ? ((f)=(l)=(n)) : ((l)->next=(n),(l)=(n),(n)->next = NULL))
|
||||||
|
|
||||||
|
#define DEFAULT_ALIGNMENT sizeof(void*)
|
||||||
|
#define isPowerOfTwo(x) ((x & (x-1)) == 0)
|
||||||
|
|
||||||
|
#define XYToPos(x, y, w) ((u32)(((u32)(x)) + (((u32)(y)) * (w))))
|
||||||
|
|
||||||
|
#if COMPILER_MSVC
|
||||||
|
# define thread_static __declspec(thread)
|
||||||
|
#elif COMPILER_CLANG || COMPILER_GCC
|
||||||
|
# define thread_static __thread
|
||||||
|
#else
|
||||||
|
# error thread_static not defined for this compiler.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// only valid if there's an in-scope variable bool `debug_mode`
|
||||||
|
#define dbg(fmt, ...) osDebugPrint(debug_mode, fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
///// SYSTEM INCLUDES I always want
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
///// TYPES
|
||||||
|
// integer types
|
||||||
|
typedef unsigned char u8;
|
||||||
|
typedef signed char i8;
|
||||||
|
typedef unsigned short u16;
|
||||||
|
typedef short i16;
|
||||||
|
typedef unsigned int u32;
|
||||||
|
typedef int i32;
|
||||||
|
typedef unsigned long long u64;
|
||||||
|
typedef signed long long i64;
|
||||||
|
typedef char * usize;
|
||||||
|
typedef char * ptr;
|
||||||
|
typedef const char* str;
|
||||||
|
|
||||||
|
// Floating point types
|
||||||
|
typedef float f32;
|
||||||
|
typedef double f64;
|
||||||
|
|
||||||
|
//typedef long double f80; only returning 8 bytes on my mac for some reason
|
||||||
|
/*
|
||||||
|
printf("u8 %d\n", (int)sizeof(u8) * 8);
|
||||||
|
printf("i8 %d\n", (int)sizeof(i8) * 8);
|
||||||
|
printf("u16 %d\n", (int)sizeof(u16) * 8);
|
||||||
|
printf("i16 %d\n", (int)sizeof(i16) * 8);
|
||||||
|
printf("u32 %d\n", (int)sizeof(u32) * 8);
|
||||||
|
printf("i32 %d\n", (int)sizeof(i32) * 8);
|
||||||
|
printf("u64 %d\n", (int)sizeof(u64) * 8);
|
||||||
|
printf("i64 %d\n", (int)sizeof(i64) * 8);
|
||||||
|
printf("usize %d\n", (int)sizeof(usize) * 8);
|
||||||
|
|
||||||
|
printf("f32 %d\n", (int)sizeof(f32) * 8);
|
||||||
|
printf("f64 %d\n", (int)sizeof(f64) * 8);
|
||||||
|
printf("f80 %d\n", (int)sizeof(f80) * 8);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Boolean types
|
||||||
|
typedef u8 b8;
|
||||||
|
typedef u32 b32;
|
||||||
|
#ifndef bool
|
||||||
|
# define bool b8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define true 1
|
||||||
|
#define false 0
|
||||||
|
|
||||||
|
// Structs
|
||||||
|
typedef struct Arena {
|
||||||
|
u8* memory;
|
||||||
|
u64 max;
|
||||||
|
u64 alloc_position;
|
||||||
|
u64 commit_position;
|
||||||
|
b8 static_size;
|
||||||
|
} Arena;
|
||||||
|
|
||||||
|
typedef struct PtrArray {
|
||||||
|
u32 length;
|
||||||
|
u32 capacity;
|
||||||
|
ptr* items;
|
||||||
|
} PtrArray;
|
||||||
|
|
||||||
|
typedef struct u8List {
|
||||||
|
u32 length;
|
||||||
|
u32 capacity;
|
||||||
|
u8* items;
|
||||||
|
} u8List;
|
||||||
|
|
||||||
|
typedef struct String {
|
||||||
|
u32 length;
|
||||||
|
u32 capacity;
|
||||||
|
ptr bytes;
|
||||||
|
} String;
|
||||||
|
|
||||||
|
typedef struct StringUTF16Const {
|
||||||
|
u16* string;
|
||||||
|
u64 size;
|
||||||
|
} StringUTF16Const;
|
||||||
|
|
||||||
|
typedef enum Utf8Character {
|
||||||
|
Utf8CharacterAscii,
|
||||||
|
Utf8CharacterTwoByte,
|
||||||
|
Utf8CharacterThreeByte,
|
||||||
|
Utf8CharacterFourByte,
|
||||||
|
Utf8Character_Count,
|
||||||
|
} Utf8Character;
|
||||||
|
|
||||||
|
typedef enum FieldType {
|
||||||
|
FieldTypeU8,
|
||||||
|
FieldTypeU16,
|
||||||
|
FieldTypeU32,
|
||||||
|
FieldTypeFloat,
|
||||||
|
FieldTypeString,
|
||||||
|
FieldTypeEnum,
|
||||||
|
FieldType_Count,
|
||||||
|
} FieldType;
|
||||||
|
|
||||||
|
typedef struct FieldDescriptor {
|
||||||
|
str name;
|
||||||
|
FieldType type;
|
||||||
|
size_t offset;
|
||||||
|
int width; // column width for display
|
||||||
|
str* enum_vals;
|
||||||
|
} FieldDescriptor;
|
||||||
|
|
||||||
|
typedef struct TableDrawInfo {
|
||||||
|
u32 x_offset;
|
||||||
|
u32 y_offset;
|
||||||
|
u32 rows;
|
||||||
|
u32 cols;
|
||||||
|
} TableDrawInfo;
|
||||||
|
|
||||||
|
typedef struct Box {
|
||||||
|
u32 x;
|
||||||
|
u32 y;
|
||||||
|
u32 height;
|
||||||
|
u32 width;
|
||||||
|
} Box;
|
||||||
|
|
||||||
|
typedef struct Dim2 {
|
||||||
|
u16 height;
|
||||||
|
u16 width;
|
||||||
|
} Dim2;
|
||||||
|
|
||||||
|
typedef struct Pos2 {
|
||||||
|
u16 x;
|
||||||
|
u16 y;
|
||||||
|
} Pos2;
|
||||||
|
|
||||||
|
typedef struct Pos2u8 {
|
||||||
|
u8 x;
|
||||||
|
u8 y;
|
||||||
|
} Pos2u8;
|
||||||
|
|
||||||
|
typedef union Range1u32 Range1u32;
|
||||||
|
union Range1u32
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u32 min;
|
||||||
|
u32 max;
|
||||||
|
};
|
||||||
|
u32 v[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef union Range1i32 Range1i32;
|
||||||
|
union Range1i32
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
i32 min;
|
||||||
|
i32 max;
|
||||||
|
};
|
||||||
|
i32 v[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef union Range1u64 Range1u64;
|
||||||
|
union Range1u64
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u64 min;
|
||||||
|
u64 max;
|
||||||
|
};
|
||||||
|
u64 v[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef union Range1i64 Range1i64;
|
||||||
|
union Range1i64
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
i64 min;
|
||||||
|
i64 max;
|
||||||
|
};
|
||||||
|
i64 v[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef union Range1f32 Range1f32;
|
||||||
|
union Range1f32
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
f32 min;
|
||||||
|
f32 max;
|
||||||
|
};
|
||||||
|
f32 v[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# include <Windows.h>
|
||||||
|
# include <winsock2.h>
|
||||||
|
# include <iphlpapi.h>
|
||||||
|
# include <ws2tcpip.h>
|
||||||
|
# include <timeapi.h>
|
||||||
|
# include <conio.h>
|
||||||
|
# include <pthread.h>
|
||||||
|
typedef struct {
|
||||||
|
DWORD input_mode;
|
||||||
|
DWORD output_mode;
|
||||||
|
} TermIOs;
|
||||||
|
// <poll.h> networking shim for windows
|
||||||
|
#ifndef POLLIN
|
||||||
|
# define POLLIN 0x0001
|
||||||
|
# define POLLPRI 0x0002
|
||||||
|
# define POLLOUT 0x0004
|
||||||
|
# define POLLERR 0x0008
|
||||||
|
# define POLLHUP 0x0010
|
||||||
|
# define POLLNVAL 0x0020
|
||||||
|
|
||||||
|
typedef struct pollfd {
|
||||||
|
SOCKET fd;
|
||||||
|
short events;
|
||||||
|
short revents;
|
||||||
|
} pollfd_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef int nfds_t;
|
||||||
|
|
||||||
|
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
|
||||||
|
#else
|
||||||
|
# include <poll.h>
|
||||||
|
# include <sys/socket.h>
|
||||||
|
# include <netinet/in.h>
|
||||||
|
# include <netdb.h>
|
||||||
|
# include <arpa/inet.h>
|
||||||
|
# include <net/if.h>
|
||||||
|
# include <ifaddrs.h>
|
||||||
|
# include <termios.h>
|
||||||
|
# include <sys/ioctl.h>
|
||||||
|
# include <pthread.h>
|
||||||
|
typedef struct termios TermIOs;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct Barrier {
|
||||||
|
u64 a[1];
|
||||||
|
} Barrier;
|
||||||
|
|
||||||
|
typedef struct CondVar {
|
||||||
|
u64 a[1];
|
||||||
|
} CondVar;
|
||||||
|
|
||||||
|
typedef struct Thread {
|
||||||
|
pthread_t thread;
|
||||||
|
} Thread;
|
||||||
|
|
||||||
|
typedef struct Mutex {
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
} Mutex;
|
||||||
|
|
||||||
|
typedef struct Cond {
|
||||||
|
pthread_cond_t cond;
|
||||||
|
} Cond;
|
||||||
|
|
||||||
|
#define M_SCRATCH_SIZE KB(16)
|
||||||
|
typedef struct ScratchFreeListNode ScratchFreeListNode;
|
||||||
|
struct ScratchFreeListNode {
|
||||||
|
ScratchFreeListNode* next;
|
||||||
|
u32 index;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ScratchMem {
|
||||||
|
Arena arena;
|
||||||
|
u32 index;
|
||||||
|
u64 pos;
|
||||||
|
} ScratchMem;
|
||||||
|
|
||||||
|
typedef struct LaneCtx {
|
||||||
|
u64 lane_idx;
|
||||||
|
u64 lane_count;
|
||||||
|
Barrier barrier;
|
||||||
|
u64 *broadcast_memory;
|
||||||
|
} LaneCtx;
|
||||||
|
|
||||||
|
typedef struct ThreadContext {
|
||||||
|
Arena arena; // scratch
|
||||||
|
u32 max_created;
|
||||||
|
ScratchFreeListNode* free_list;
|
||||||
|
LaneCtx lane_ctx;
|
||||||
|
} ThreadContext;
|
||||||
|
|
||||||
|
///// HARDCODED GLOBALS
|
||||||
|
global const u64 MAX_u64 = 0xffffffffffffffffull;
|
||||||
|
global const u32 MAX_u32 = 0xffffffff;
|
||||||
|
global const u16 MAX_u16 = 0xffff;
|
||||||
|
global const u8 MAX_u8 = 0xff;
|
||||||
|
#define EULERS_E (2.71828)
|
||||||
|
#define PI (3.14159265358979323846)
|
||||||
|
|
||||||
|
///// CUSTOM ENTRY POINT
|
||||||
|
/* TODO?
|
||||||
|
fn void mainThreadBaseEntryPoint(i32 argc, char **argv);
|
||||||
|
fn void asyncThreadEntryPoint(void *params);
|
||||||
|
fn void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params);
|
||||||
|
fn u64 update_tick_idx(void);
|
||||||
|
fn b32 update(void);
|
||||||
|
*/
|
||||||
|
|
||||||
|
///// MATH
|
||||||
|
fn Range1u64 range1u64Create(u64 min, u64 max);
|
||||||
|
fn Range1u64 mRangeFromNIdxMCount(u64 n_idx, u64 n_count, u64 m_count);
|
||||||
|
fn void u32Quicksort(u32 arr[], u32 low, u32 high);
|
||||||
|
fn void u32ReverseArray(u32 arr[], u32 size);
|
||||||
|
|
||||||
|
///// MEMORY (Arenas)
|
||||||
|
#define ARENA_MAX GB(1)
|
||||||
|
// this was an evil bug to figure out
|
||||||
|
#if defined(OS_MAC)
|
||||||
|
# define ARENA_COMMIT_SIZE KB(16)
|
||||||
|
#else
|
||||||
|
# define ARENA_COMMIT_SIZE KB(8)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fn void* arenaAlloc(Arena* arena, u64 size);
|
||||||
|
fn void* arenaAllocZero(Arena* arena, u64 size);
|
||||||
|
fn void arenaDealloc(Arena* arena, u64 size);
|
||||||
|
fn void arenaDeallocTo(Arena* arena, u64 pos);
|
||||||
|
fn void* arenaRaise(Arena* arena, void* ptr, u64 size);
|
||||||
|
fn void* arenaAllocArraySized(Arena* arena, u64 elem_size, u64 count);
|
||||||
|
#define arenaAllocArray(arena, elem_type, count) arenaAllocArraySized(arena, sizeof(elem_type), count)
|
||||||
|
|
||||||
|
fn void arenaInit(Arena* arena);
|
||||||
|
fn void arenaInitSized(Arena* arena, u64 max);
|
||||||
|
fn void arenaClear(Arena* arena);
|
||||||
|
fn void arenaFree(Arena* arena);
|
||||||
|
|
||||||
|
ScratchMem scratchGet(void);
|
||||||
|
void scratchReset(ScratchMem* scratch);
|
||||||
|
void scratchReturn(ScratchMem* scratch);
|
||||||
|
|
||||||
|
///// STRINGS
|
||||||
|
#define ASCII_TAB (9)
|
||||||
|
#define ASCII_LINE_FEED (10)
|
||||||
|
#define ASCII_RETURN (13)
|
||||||
|
#define ASCII_ESCAPE (27)
|
||||||
|
#define ASCII_DEL (127)
|
||||||
|
#define ASCII_BACKSPACE (8)
|
||||||
|
|
||||||
|
fn bool stringsEq(String* a, String* b);
|
||||||
|
fn bool cStringEqString(str a, String* b);
|
||||||
|
fn Utf8Character classifyUtf8Character(u8 c);
|
||||||
|
fn bool isUtf8Ascii(u8 c);
|
||||||
|
fn bool isUtf8TwoByte(u8 c);
|
||||||
|
fn bool isUtf8ThreeByte(u8 c);
|
||||||
|
fn bool isUtf8FourByte(u8 c);
|
||||||
|
fn u8 lowerAscii(u8 c);
|
||||||
|
fn u8 upperAscii(u8 c);
|
||||||
|
fn StringUTF16Const str16FromStr8(Arena* a, String string);
|
||||||
|
fn bool isAlphaUnderscoreSpace(u8 c);
|
||||||
|
fn bool isSimplePrintable(u8 c);
|
||||||
|
|
||||||
|
///// OS-wrapped apis
|
||||||
|
void osInit();
|
||||||
|
void* osThreadContextGet();
|
||||||
|
void osThreadContextSet(void* ctx);
|
||||||
|
bool osThreadJoin(Thread handle, u64 endt_us);
|
||||||
|
|
||||||
|
fn Barrier osBarrierAlloc(u64 count);
|
||||||
|
fn void osBarrierRelease(Barrier barrier);
|
||||||
|
fn void osBarrierWait(Barrier barrier);
|
||||||
|
|
||||||
|
// Memory
|
||||||
|
fn void* osMemoryReserve(u64 size);
|
||||||
|
fn void osMemoryCommit(void* memory, u64 size);
|
||||||
|
fn void osMemoryDecommit(void* memory, u64 size);
|
||||||
|
fn void osMemoryRelease(void* memory, u64 size);
|
||||||
|
fn u64 osTimeMicrosecondsNow();
|
||||||
|
fn void osSleepMicroseconds(u32 t);
|
||||||
|
|
||||||
|
// Files
|
||||||
|
fn bool osFileExists(String filename);
|
||||||
|
fn String osFileRead(Arena* arena, ptr filepath);
|
||||||
|
fn bool osFileCreate(String filename);
|
||||||
|
fn bool osFileCreateWrite(String filename, String data);
|
||||||
|
fn bool osFileWrite(String filename, String data);
|
||||||
|
|
||||||
|
fn void osDebugPrint(bool debug_mode, const char* format, ...);
|
||||||
|
|
||||||
|
// Tui stuff
|
||||||
|
TermIOs osStartTUI(bool blocking);
|
||||||
|
fn void osEndTUI(TermIOs old_terminal_attributes);
|
||||||
|
fn Dim2 osGetTerminalDimensions();
|
||||||
|
void osBlitToTerminal(ptr writeable_output_ansi_string, i64 count);
|
||||||
|
void osReadConsoleInput(u8* buffer, u32 len);
|
||||||
|
|
||||||
|
// network stuff
|
||||||
|
bool osInitNetwork();
|
||||||
|
i32 osLanIPAddress();
|
||||||
|
|
||||||
|
///// Basic THREAD synchronization apis
|
||||||
|
Thread spawnThread(void * (*threadFn)(void *), void* thread_arg);
|
||||||
|
Mutex newMutex();
|
||||||
|
Cond newCond();
|
||||||
|
void lockMutex(Mutex* m);
|
||||||
|
void unlockMutex(Mutex* m);
|
||||||
|
void signalCond(Cond* cond);
|
||||||
|
void waitForCondSignal(Cond* cond, Mutex* mutex);
|
||||||
|
|
||||||
|
///// Multi-Core by Default ThreadContext stuff
|
||||||
|
void tctxInit(ThreadContext* ctx);
|
||||||
|
void tctxFree(ThreadContext* ctx);
|
||||||
|
fn ThreadContext *tctxSelected(void);
|
||||||
|
|
||||||
|
ScratchMem tctxScratchGet(ThreadContext* ctx);
|
||||||
|
void tctxScratchReset(ThreadContext* ctx, ScratchMem* scratch);
|
||||||
|
void tctxScratchReturn(ThreadContext* ctx, ScratchMem* scratch);
|
||||||
|
|
||||||
|
fn LaneCtx tctxSetLaneCtx(LaneCtx lane_ctx);
|
||||||
|
fn void tctxLaneBarrierWait(void *broadcast_ptr, u64 broadcast_size, u64 broadcast_src_lane_idx);
|
||||||
|
#define LaneIdx() (tctxSelected()->lane_ctx.lane_idx)
|
||||||
|
#define LaneCount() (tctxSelected()->lane_ctx.lane_count)
|
||||||
|
#define LaneFromTaskIdx(idx) ((idx)%LaneCount())
|
||||||
|
#define LaneCtx(ctx) tctxSetLaneCtx((ctx))
|
||||||
|
#define LaneSync() tctxLaneBarrierWait(0, 0, 0)
|
||||||
|
#define LaneSyncu64(pointer, src_lane_idx) tctxLaneBarrierWait((pointer), sizeof(*(pointer)), (src_lane_idx))
|
||||||
|
#define LaneRange(count) mRangeFromNIdxMCount(LaneIdx(), LaneCount(), (count))
|
||||||
|
|
||||||
|
///// StringChunk stuff
|
||||||
|
#ifndef STRING_CHUNK_PAYLOAD_SIZE
|
||||||
|
#define STRING_CHUNK_PAYLOAD_SIZE (64 - sizeof(StringChunk*))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct StringChunk {
|
||||||
|
struct StringChunk *next; // essentially a header, followed by a fixed maximum str bytes
|
||||||
|
} StringChunk;
|
||||||
|
|
||||||
|
typedef struct StringChunkList {
|
||||||
|
StringChunk* first;
|
||||||
|
StringChunk* last;
|
||||||
|
u64 count;
|
||||||
|
u64 total_size;
|
||||||
|
} StringChunkList;
|
||||||
|
|
||||||
|
typedef struct StringArena {
|
||||||
|
Arena a;
|
||||||
|
StringChunk* first_free_str_chunk;
|
||||||
|
Mutex mutex;
|
||||||
|
} StringArena;
|
||||||
|
|
||||||
|
fn StringChunkList allocStringChunkList(StringArena* a, String string);
|
||||||
|
fn void releaseStringChunkList(StringArena* a, StringChunkList* list);
|
||||||
|
fn String stringChunkToString(Arena* a, StringChunkList list);
|
||||||
|
fn void stringChunkListAppend(StringArena* a, StringChunkList* list, String string);
|
||||||
|
fn void stringChunkListDeleteLast(StringArena* a, StringChunkList* list);
|
||||||
|
fn StringChunkList stringChunkListInit(StringArena* a);
|
||||||
|
fn void stringChunkCopyToBuffer(StringChunkList* list, u8* buffer, u32 len);
|
||||||
|
|
||||||
|
#endif// BASE_ALL_H
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#include "all.h"
|
||||||
|
|
||||||
|
fn void mainThreadBaseEntryPoint(i32 argc, char **argv) {
|
||||||
|
Thread* async_threads = 0;
|
||||||
|
u64 lane_broadcast_val = 0;
|
||||||
|
{
|
||||||
|
u32 num_main_threads = 1;
|
||||||
|
u32 num_async_threads = 12;//TODO: os_get_system_info()->logical_processor_count;
|
||||||
|
u32 num_main_threads_clamped = Min(num_async_threads, num_main_threads);
|
||||||
|
num_async_threads -= num_main_threads_clamped;
|
||||||
|
String num_async_threads_string = cmd_line_string(&cmdline, str8_lit("async_thread_count"));
|
||||||
|
if(num_async_threads_string.size != 0)
|
||||||
|
{
|
||||||
|
try_u64_from_str8_c_rules(num_async_threads_string, &num_async_threads);
|
||||||
|
}
|
||||||
|
num_async_threads = Max(1, num_async_threads);
|
||||||
|
Barrier barrier = barrier_alloc(num_async_threads);
|
||||||
|
LaneCtx *lane_ctxs = push_array(scratch.arena, LaneCtx, num_async_threads);
|
||||||
|
async_threads_count = num_async_threads;
|
||||||
|
async_threads = push_array(scratch.arena, Thread, async_threads_count);
|
||||||
|
for EachIndex(idx, num_async_threads)
|
||||||
|
{
|
||||||
|
lane_ctxs[idx].lane_idx = idx;
|
||||||
|
lane_ctxs[idx].lane_count = async_threads_count;
|
||||||
|
lane_ctxs[idx].barrier = barrier;
|
||||||
|
lane_ctxs[idx].broadcast_memory = &lane_broadcast_val;
|
||||||
|
async_threads[idx] = thread_launch(async_thread_entry_point, &lane_ctxs[idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: call into entry point
|
||||||
|
entry_point(&cmdline);
|
||||||
|
|
||||||
|
//- rjf: join async threads
|
||||||
|
ins_atomic_u32_inc_eval(&global_async_exit);
|
||||||
|
cond_var_broadcast(async_tick_start_cond_var);
|
||||||
|
for EachIndex(idx, async_threads_count)
|
||||||
|
{
|
||||||
|
thread_join(async_threads[idx], max_U64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void asyncThreadEntryPoint(void *params) {
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef BASE_IMPL_C
|
||||||
|
#define BASE_IMPL_C
|
||||||
|
|
||||||
|
#include "math.c"
|
||||||
|
#include "os.c"
|
||||||
|
#include "memory.c"
|
||||||
|
#include "serialize.c"
|
||||||
|
#include "string.c"
|
||||||
|
#include "tctx.c"
|
||||||
|
#include "thread.c"
|
||||||
|
#include "string_chunk.c"
|
||||||
|
|
||||||
|
#endif // BASE_IMPL_C
|
||||||
+139
@@ -0,0 +1,139 @@
|
|||||||
|
#include <sys/mman.h>
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "all.h"
|
||||||
|
|
||||||
|
global pthread_barrier_t linux_thread_barrier;
|
||||||
|
|
||||||
|
fn Barrier osBarrierAlloc(u64 count) {
|
||||||
|
pthread_barrier_init(&linux_thread_barrier, NULL, count);
|
||||||
|
Barrier result = {(u64)&linux_thread_barrier};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void osBarrierRelease(Barrier barrier) {
|
||||||
|
pthread_barrier_t* addr = (pthread_barrier_t*)barrier.a[0];
|
||||||
|
pthread_barrier_destroy(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void osBarrierWait(Barrier barrier) {
|
||||||
|
pthread_barrier_t* addr = (pthread_barrier_t*)barrier.a[0];
|
||||||
|
pthread_barrier_wait(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time
|
||||||
|
fn u64 osTimeMicrosecondsNow() {
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
return ((u64)ts.tv_sec * 1000000) + ((u64)ts.tv_nsec / 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MICROSECONDS_PER_SECOND 1000000
|
||||||
|
#define NANOSECONDS_PER_MICROSECOND 1000
|
||||||
|
fn void osSleepMicroseconds(u32 t) {
|
||||||
|
struct timespec ts = { t / MICROSECONDS_PER_SECOND, (t % MICROSECONDS_PER_SECOND)*NANOSECONDS_PER_MICROSECOND };
|
||||||
|
nanosleep(&ts, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Files
|
||||||
|
fn bool osFileExists(String filename) {
|
||||||
|
bool result = access((str)filename.bytes, F_OK) == 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn String osFileRead(Arena* arena, ptr filepath) {
|
||||||
|
struct stat st;
|
||||||
|
stat(filepath, &st);
|
||||||
|
String result = { st.st_size, st.st_size, 0 };
|
||||||
|
result.bytes = arenaAlloc(arena, st.st_size);
|
||||||
|
|
||||||
|
size_t handle = open(filepath, O_RDWR, S_IRUSR | S_IRGRP | S_IROTH);
|
||||||
|
read(handle, result.bytes, st.st_size);
|
||||||
|
close(handle);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool osFileCreate(String filename) {
|
||||||
|
/*
|
||||||
|
M_Scratch scratch = scratch_get();
|
||||||
|
string nt = str_copy(&scratch.arena, filename);
|
||||||
|
bool result = true;
|
||||||
|
size_t handle = open((const char*) nt.str, O_RDWR | O_CREAT, S_IRUSR | S_IRGRP | S_IROTH);
|
||||||
|
if (handle == -1) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
scratch_return(&scratch);
|
||||||
|
close(handle);
|
||||||
|
return true;
|
||||||
|
*/
|
||||||
|
bool result = true;
|
||||||
|
size_t handle = open((str)filename.bytes, O_RDWR | O_CREAT, S_IRUSR | S_IRGRP | S_IROTH);
|
||||||
|
if (handle == -1) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
if (close(handle) == -1) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool osFileCreateWrite(String filename, String data) {
|
||||||
|
/*
|
||||||
|
M_Scratch scratch = scratch_get();
|
||||||
|
string nt = str_copy(&scratch.arena, filename);
|
||||||
|
b32 result = true;
|
||||||
|
size_t handle =
|
||||||
|
open((const char*) nt.str, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IRGRP | S_IROTH);
|
||||||
|
if (handle == -1) result = false;
|
||||||
|
write(handle, data.str, data.size);
|
||||||
|
close(handle);
|
||||||
|
scratch_return(&scratch);
|
||||||
|
return result;
|
||||||
|
*/
|
||||||
|
bool result = true;
|
||||||
|
size_t handle = open(
|
||||||
|
(str)filename.bytes,
|
||||||
|
O_RDWR | O_CREAT | O_TRUNC,
|
||||||
|
S_IRUSR | S_IRGRP | S_IROTH
|
||||||
|
);
|
||||||
|
if (handle == -1) result = false;
|
||||||
|
write(handle, data.bytes, data.length);
|
||||||
|
close(handle);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool osFileWrite(String filename, String data) {
|
||||||
|
/*
|
||||||
|
M_Scratch scratch = scratch_get();
|
||||||
|
string nt = str_copy(&scratch.arena, filename);
|
||||||
|
b32 result = true;
|
||||||
|
size_t handle =
|
||||||
|
open((const char*) nt.str, O_RDWR | O_TRUNC, S_IRUSR | S_IRGRP | S_IROTH);
|
||||||
|
if (handle == -1) result = false;
|
||||||
|
write(handle, data.str, data.size);
|
||||||
|
close(handle);
|
||||||
|
*/
|
||||||
|
bool result = true;
|
||||||
|
size_t handle = open((str) filename.bytes, O_RDWR | O_TRUNC, S_IRUSR | S_IRGRP | S_IROTH);
|
||||||
|
if (handle == -1) result = false;
|
||||||
|
write(handle, data.bytes, data.length);
|
||||||
|
close(handle);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
fn void osDebugPrint(bool debug_mode, const char * format, ... ) {
|
||||||
|
if (debug_mode) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
vprintf(format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "all.h"
|
||||||
|
#include "pthread_barrier.h"
|
||||||
|
|
||||||
|
global pthread_barrier_t macos_thread_barrier;
|
||||||
|
|
||||||
|
fn Barrier osBarrierAlloc(u64 count) {
|
||||||
|
pthread_barrier_init(&macos_thread_barrier, NULL, count);
|
||||||
|
Barrier result = {(u64)&macos_thread_barrier};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void osBarrierRelease(Barrier barrier) {
|
||||||
|
pthread_barrier_t* addr = (pthread_barrier_t*)barrier.a[0];
|
||||||
|
pthread_barrier_destroy(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void osBarrierWait(Barrier barrier) {
|
||||||
|
pthread_barrier_t* addr = (pthread_barrier_t*)barrier.a[0];
|
||||||
|
pthread_barrier_wait(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time
|
||||||
|
fn u64 osTimeMicrosecondsNow() {
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||||
|
return ((u64)ts.tv_sec * 1000000) + ((u64)ts.tv_nsec / 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void osSleepMicroseconds(u32 t) {
|
||||||
|
usleep(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Files
|
||||||
|
fn bool osFileExists(String filename) {
|
||||||
|
bool result = access((str)filename.bytes, F_OK) == 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn String osFileRead(Arena* arena, ptr filepath) {
|
||||||
|
struct stat st;
|
||||||
|
stat(filepath, &st);
|
||||||
|
String result = { st.st_size, st.st_size, 0 };
|
||||||
|
result.bytes = arenaAlloc(arena, st.st_size);
|
||||||
|
|
||||||
|
size_t handle = open(filepath, O_RDWR, S_IRUSR | S_IRGRP | S_IROTH);
|
||||||
|
read(handle, result.bytes, st.st_size);
|
||||||
|
close(handle);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool osFileCreate(String filename) {
|
||||||
|
/*
|
||||||
|
M_Scratch scratch = scratch_get();
|
||||||
|
string nt = str_copy(&scratch.arena, filename);
|
||||||
|
bool result = true;
|
||||||
|
size_t handle = open((const char*) nt.str, O_RDWR | O_CREAT, S_IRUSR | S_IRGRP | S_IROTH);
|
||||||
|
if (handle == -1) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
scratch_return(&scratch);
|
||||||
|
close(handle);
|
||||||
|
return true;
|
||||||
|
*/
|
||||||
|
bool result = true;
|
||||||
|
size_t handle = open((str)filename.bytes, O_RDWR | O_CREAT, S_IRUSR | S_IRGRP | S_IROTH);
|
||||||
|
if (handle == -1) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
if (close(handle) == -1) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool osFileCreateWrite(String filename, String data) {
|
||||||
|
/*
|
||||||
|
M_Scratch scratch = scratch_get();
|
||||||
|
string nt = str_copy(&scratch.arena, filename);
|
||||||
|
b32 result = true;
|
||||||
|
size_t handle =
|
||||||
|
open((const char*) nt.str, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IRGRP | S_IROTH);
|
||||||
|
if (handle == -1) result = false;
|
||||||
|
write(handle, data.str, data.size);
|
||||||
|
close(handle);
|
||||||
|
scratch_return(&scratch);
|
||||||
|
return result;
|
||||||
|
*/
|
||||||
|
bool result = true;
|
||||||
|
size_t handle = open(
|
||||||
|
(str)filename.bytes,
|
||||||
|
O_RDWR | O_CREAT | O_TRUNC,
|
||||||
|
S_IRUSR | S_IRGRP | S_IROTH
|
||||||
|
);
|
||||||
|
if (handle == -1) result = false;
|
||||||
|
write(handle, data.bytes, data.length);
|
||||||
|
close(handle);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool osFileWrite(String filename, String data) {
|
||||||
|
/*
|
||||||
|
M_Scratch scratch = scratch_get();
|
||||||
|
string nt = str_copy(&scratch.arena, filename);
|
||||||
|
b32 result = true;
|
||||||
|
size_t handle =
|
||||||
|
open((const char*) nt.str, O_RDWR | O_TRUNC, S_IRUSR | S_IRGRP | S_IROTH);
|
||||||
|
if (handle == -1) result = false;
|
||||||
|
write(handle, data.str, data.size);
|
||||||
|
close(handle);
|
||||||
|
*/
|
||||||
|
bool result = true;
|
||||||
|
size_t handle = open((str) filename.bytes, O_RDWR | O_TRUNC, S_IRUSR | S_IRGRP | S_IROTH);
|
||||||
|
if (handle == -1) result = false;
|
||||||
|
write(handle, data.bytes, data.length);
|
||||||
|
close(handle);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
fn void osDebugPrint(bool debug_mode, const char * format, ... ) {
|
||||||
|
if (debug_mode) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
vprintf(format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#include "all.h"
|
||||||
|
|
||||||
|
fn Range1u64 range1u64Create(u64 min, u64 max) {
|
||||||
|
Range1u64 result = {
|
||||||
|
.min = min,
|
||||||
|
.max = max
|
||||||
|
};
|
||||||
|
if (result.min > result.max) {
|
||||||
|
result.max = min;
|
||||||
|
result.min = max;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Range1u64 mRangeFromNIdxMCount(u64 n_idx, u64 n_count, u64 m_count) {
|
||||||
|
u64 main_idxes_per_lane = m_count / n_count;
|
||||||
|
u64 leftover_idxes_count = m_count - main_idxes_per_lane * n_count;
|
||||||
|
u64 leftover_idxes_before_this_lane_count = Min(n_idx, leftover_idxes_count);
|
||||||
|
u64 lane_base_idx = n_idx*main_idxes_per_lane + leftover_idxes_before_this_lane_count;
|
||||||
|
u64 lane_base_idx__clamped = Min(lane_base_idx, m_count);
|
||||||
|
u64 lane_opl_idx = lane_base_idx__clamped + main_idxes_per_lane + ((n_idx < leftover_idxes_count) ? 1 : 0);
|
||||||
|
u64 lane_opl_idx__clamped = Min(lane_opl_idx, m_count);
|
||||||
|
Range1u64 result = range1u64Create(lane_base_idx__clamped, lane_opl_idx__clamped);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void u32Swap(u32* a, u32* b) {
|
||||||
|
int t = *a;
|
||||||
|
*a = *b;
|
||||||
|
*b = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 u32ArrPartition(u32 arr[], u32 low, u32 high) {
|
||||||
|
u32 pivot = arr[high];
|
||||||
|
u32 i = low - 1;
|
||||||
|
|
||||||
|
for (u32 j = low; j < high; j++) {
|
||||||
|
if (arr[j] < pivot) {
|
||||||
|
i++;
|
||||||
|
u32Swap(&arr[i], &arr[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u32Swap(&arr[i + 1], &arr[high]);
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void u32Quicksort(u32 arr[], u32 low, u32 high) {
|
||||||
|
if (low < high) {
|
||||||
|
u32 pi = u32ArrPartition(arr, low, high);
|
||||||
|
if (pi != 0) {
|
||||||
|
u32Quicksort(arr, low, pi - 1);
|
||||||
|
}
|
||||||
|
u32Quicksort(arr, pi + 1, high);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void u32ReverseArray(u32 arr[], u32 size) {
|
||||||
|
u32 start = 0;
|
||||||
|
u32 end = size - 1;
|
||||||
|
while (start < end) {
|
||||||
|
u32 temp = arr[start];
|
||||||
|
arr[start] = arr[end];
|
||||||
|
arr[end] = temp;
|
||||||
|
start++;
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
#include "all.h"
|
||||||
|
|
||||||
|
fn u64 alignForward(u64 pointer, u64 align) {
|
||||||
|
u64 p, modulo;
|
||||||
|
assert(isPowerOfTwo(align));
|
||||||
|
p = pointer;
|
||||||
|
// Same as (p % a) but faster as 'a' is a power of two
|
||||||
|
modulo = p & (align-1);
|
||||||
|
if (modulo != 0) {
|
||||||
|
// If 'p' address is not aligned, push the address to the
|
||||||
|
// next value which is aligned
|
||||||
|
p += align - modulo;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void* arenaAlloc(Arena* arena, u64 size) {
|
||||||
|
void* memory = 0;
|
||||||
|
size = alignForward(size, DEFAULT_ALIGNMENT);
|
||||||
|
if (arena->alloc_position + size > arena->commit_position) {
|
||||||
|
if (!arena->static_size) {
|
||||||
|
u64 commit_size = size;
|
||||||
|
|
||||||
|
commit_size += ARENA_COMMIT_SIZE - 1;
|
||||||
|
commit_size -= commit_size % ARENA_COMMIT_SIZE;
|
||||||
|
|
||||||
|
if (arena->commit_position < arena->max) {
|
||||||
|
osMemoryCommit(arena->memory + arena->commit_position, commit_size);
|
||||||
|
arena->commit_position += commit_size;
|
||||||
|
} else {
|
||||||
|
assert(0 && "Arena is out of memory");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(0 && "Static-Size Arena is out of memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memory = arena->memory + arena->alloc_position;
|
||||||
|
arena->alloc_position += size;
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void* arenaAllocZero(Arena* a, u64 size) {
|
||||||
|
void* result = arenaAlloc(a, size);
|
||||||
|
MemoryZero(result, size);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void* arenaAllocArraySized(Arena* arena, u64 elem_size, u64 count) {
|
||||||
|
return arenaAlloc(arena, elem_size * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void arenaDealloc(Arena* arena, u64 size) {
|
||||||
|
if (size > arena->alloc_position) size = arena->alloc_position;
|
||||||
|
arena->alloc_position -= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void arenaInit(Arena* arena) {
|
||||||
|
MemoryZeroStruct(arena, Arena);
|
||||||
|
arena->max = ARENA_MAX;
|
||||||
|
arena->memory = osMemoryReserve(arena->max);
|
||||||
|
arena->alloc_position = 0;
|
||||||
|
arena->commit_position = 0;
|
||||||
|
arena->static_size = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// WARNING: segfault problems with this approach
|
||||||
|
fn void arenaInitStatic(Arena* arena, u64 max) {
|
||||||
|
MemoryZeroStruct(arena, Arena);
|
||||||
|
arena->max = max;
|
||||||
|
arena->memory = osMemoryReserve(arena->max);
|
||||||
|
osMemoryCommit(arena->memory, max + (max % ARENA_COMMIT_SIZE));
|
||||||
|
arena->alloc_position = 0;
|
||||||
|
arena->commit_position = 0;
|
||||||
|
arena->static_size = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn void arenaClear(Arena* a) {
|
||||||
|
a->alloc_position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void arenaFree(Arena* a) {
|
||||||
|
osMemoryRelease(a->memory, a->max);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScratchMem scratchGet(void) {
|
||||||
|
ThreadContext* ctx = (ThreadContext*)osThreadContextGet();
|
||||||
|
return tctxScratchGet(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void scratchReset(ScratchMem* scratch) {
|
||||||
|
ThreadContext* ctx = (ThreadContext*)osThreadContextGet();
|
||||||
|
tctxScratchReset(ctx, scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void scratchReturn(ScratchMem* scratch) {
|
||||||
|
ThreadContext* ctx = (ThreadContext*)osThreadContextGet();
|
||||||
|
tctxScratchReturn(ctx, scratch);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#include "all.h"
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
# include "win32_os.c"
|
||||||
|
#elif OS_LINUX
|
||||||
|
# include "linux_os.c"
|
||||||
|
# include "unix_os.c"
|
||||||
|
#elif OS_MAC
|
||||||
|
# include "pthread_barrier.c"
|
||||||
|
# include "mac_os.c"
|
||||||
|
# include "unix_os.c"
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
/* (C) Copyright 2019 Robert Sauter
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Pthread-barrier implementation for macOS using a pthread mutex and condition variable */
|
||||||
|
|
||||||
|
|
||||||
|
#include "pthread_barrier.h"
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
|
||||||
|
int pthread_barrier_init(pthread_barrier_t *__restrict barrier,
|
||||||
|
const pthread_barrierattr_t * __restrict attr,
|
||||||
|
unsigned count) {
|
||||||
|
if (count == 0) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
pthread_condattr_t condattr;
|
||||||
|
pthread_condattr_init(&condattr);
|
||||||
|
if (attr) {
|
||||||
|
int pshared;
|
||||||
|
ret = pthread_barrierattr_getpshared(attr, &pshared);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = pthread_condattr_setpshared(&condattr, pshared);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = pthread_mutex_init(&barrier->mutex, attr);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = pthread_cond_init(&barrier->cond, &condattr);
|
||||||
|
if (ret) {
|
||||||
|
pthread_mutex_destroy(&barrier->mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
barrier->count = count;
|
||||||
|
barrier->left = count;
|
||||||
|
barrier->round = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_barrier_destroy(pthread_barrier_t *barrier) {
|
||||||
|
if (barrier->count == 0) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
barrier->count = 0;
|
||||||
|
int rm = pthread_mutex_destroy(&barrier->mutex);
|
||||||
|
int rc = pthread_cond_destroy(&barrier->cond);
|
||||||
|
return rm ? rm : rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int pthread_barrier_wait(pthread_barrier_t *barrier) {
|
||||||
|
pthread_mutex_lock(&barrier->mutex);
|
||||||
|
if (--barrier->left) {
|
||||||
|
unsigned round = barrier->round;
|
||||||
|
do {
|
||||||
|
pthread_cond_wait(&barrier->cond, &barrier->mutex);
|
||||||
|
} while (round == barrier->round);
|
||||||
|
pthread_mutex_unlock(&barrier->mutex);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
barrier->round += 1;
|
||||||
|
barrier->left = barrier->count;
|
||||||
|
pthread_cond_broadcast(&barrier->cond);
|
||||||
|
pthread_mutex_unlock(&barrier->mutex);
|
||||||
|
return PTHREAD_BARRIER_SERIAL_THREAD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int pthread_barrierattr_init(pthread_barrierattr_t *attr) {
|
||||||
|
return pthread_mutexattr_init(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_barrierattr_destroy(pthread_barrierattr_t *attr) {
|
||||||
|
return pthread_mutexattr_destroy(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_barrierattr_getpshared(const pthread_barrierattr_t *__restrict attr,
|
||||||
|
int *__restrict pshared) {
|
||||||
|
return pthread_mutexattr_getpshared(attr, pshared);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) {
|
||||||
|
return pthread_mutexattr_setpshared(attr, pshared);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __APPLE */
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/** Pthread-barrier implementation for macOS */
|
||||||
|
#ifndef PTHREAD_BARRIER_H
|
||||||
|
#define PTHREAD_BARRIER_H
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PTHREAD_BARRIER_SERIAL_THREAD
|
||||||
|
# define PTHREAD_BARRIER_SERIAL_THREAD -1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef pthread_mutexattr_t pthread_barrierattr_t;
|
||||||
|
|
||||||
|
/* structure for internal use that should be considered opaque */
|
||||||
|
typedef struct {
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
pthread_cond_t cond;
|
||||||
|
unsigned count;
|
||||||
|
unsigned left;
|
||||||
|
unsigned round;
|
||||||
|
} pthread_barrier_t;
|
||||||
|
|
||||||
|
int pthread_barrier_init(pthread_barrier_t *__restrict barrier,
|
||||||
|
const pthread_barrierattr_t * __restrict attr,
|
||||||
|
unsigned count);
|
||||||
|
int pthread_barrier_destroy(pthread_barrier_t *barrier);
|
||||||
|
|
||||||
|
int pthread_barrier_wait(pthread_barrier_t *barrier);
|
||||||
|
|
||||||
|
int pthread_barrierattr_init(pthread_barrierattr_t *attr);
|
||||||
|
int pthread_barrierattr_destroy(pthread_barrierattr_t *attr);
|
||||||
|
int pthread_barrierattr_getpshared(const pthread_barrierattr_t *__restrict attr,
|
||||||
|
int *__restrict pshared);
|
||||||
|
int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr,
|
||||||
|
int pshared);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __APPLE__ */
|
||||||
|
|
||||||
|
#endif /* PTHREAD_BARRIER_H */
|
||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
#include "all.h"
|
||||||
|
|
||||||
|
fn u64 writeU64ToBufferLE(u8* buffer, u64 value) {
|
||||||
|
buffer[0] = (u8)(value & 0xFF);
|
||||||
|
buffer[1] = (u8)((value >> 8) & 0xFF);
|
||||||
|
buffer[2] = (u8)((value >> 16) & 0xFF);
|
||||||
|
buffer[3] = (u8)((value >> 24) & 0xFF);
|
||||||
|
buffer[4] = (u8)((value >> 32) & 0xFF);
|
||||||
|
buffer[5] = (u8)((value >> 40) & 0xFF);
|
||||||
|
buffer[6] = (u8)((value >> 48) & 0xFF);
|
||||||
|
buffer[7] = (u8)((value >> 56) & 0xFF);
|
||||||
|
return 8;// number of bytes written
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u64 writeU32ToBufferLE(u8* buffer, u32 value) {
|
||||||
|
buffer[0] = (u8)(value & 0xFF);
|
||||||
|
buffer[1] = (u8)((value >> 8) & 0xFF);
|
||||||
|
buffer[2] = (u8)((value >> 16) & 0xFF);
|
||||||
|
buffer[3] = (u8)((value >> 24) & 0xFF);
|
||||||
|
return 4;// number of bytes written
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u64 writeI32ToBufferLE(u8* buffer, i32 value) {
|
||||||
|
buffer[0] = (u8)(value & 0xFF);
|
||||||
|
buffer[1] = (u8)((value >> 8) & 0xFF);
|
||||||
|
buffer[2] = (u8)((value >> 16) & 0xFF);
|
||||||
|
buffer[3] = (u8)((value >> 24) & 0xFF);
|
||||||
|
return 4;// number of bytes written
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u64 writeU16ToBufferLE(u8* buffer, u16 value) {
|
||||||
|
buffer[0] = (u8)(value & 0xFF);
|
||||||
|
buffer[1] = (u8)((value >> 8) & 0xFF);
|
||||||
|
return 2;// number of bytes written
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u64 writeF32ToBufferLE(u8* buffer, f32 value) {
|
||||||
|
u32 bits;
|
||||||
|
memcpy(&bits, &value, sizeof(u32)); // reinterpret float bits as integer
|
||||||
|
|
||||||
|
buffer[0] = (u8)(bits & 0xFF);
|
||||||
|
buffer[1] = (u8)((bits >> 8) & 0xFF);
|
||||||
|
buffer[2] = (u8)((bits >> 16) & 0xFF);
|
||||||
|
buffer[3] = (u8)((bits >> 24) & 0xFF);
|
||||||
|
return 4;// number of bytes written
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u64 readU64FromBufferLE(u8 *buffer) {
|
||||||
|
return (u64)buffer[0] |
|
||||||
|
((u64)buffer[1] << 8) |
|
||||||
|
((u64)buffer[2] << 16) |
|
||||||
|
((u64)buffer[3] << 24) |
|
||||||
|
((u64)buffer[4] << 32) |
|
||||||
|
((u64)buffer[5] << 40) |
|
||||||
|
((u64)buffer[6] << 48) |
|
||||||
|
((u64)buffer[7] << 56);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u32 readU32FromBufferLE(u8 *buffer) {
|
||||||
|
return (u32)buffer[0] |
|
||||||
|
((u32)buffer[1] << 8) |
|
||||||
|
((u32)buffer[2] << 16) |
|
||||||
|
((u32)buffer[3] << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn i32 readI32FromBufferLE(u8 *buffer) {
|
||||||
|
return (i32)buffer[0] |
|
||||||
|
((i32)buffer[1] << 8) |
|
||||||
|
((i32)buffer[2] << 16) |
|
||||||
|
((i32)buffer[3] << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u16 readU16FromBufferLE(u8 *buffer) {
|
||||||
|
return (u16)buffer[0] |
|
||||||
|
((u16)buffer[1] << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f32 readF32FromBufferLE(u8 *buf) {
|
||||||
|
u32 bits = 0;
|
||||||
|
bits |= (u32)(u8)buf[0] << 0;
|
||||||
|
bits |= (u32)(u8)buf[1] << 8;
|
||||||
|
bits |= (u32)(u8)buf[2] << 16;
|
||||||
|
bits |= (u32)(u8)buf[3] << 24;
|
||||||
|
|
||||||
|
f32 value;
|
||||||
|
memcpy(&value, &bits, sizeof(f32));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
#include "all.h"
|
||||||
|
|
||||||
|
fn bool stringsEq(String* a, String* b) {
|
||||||
|
if (a->length != b->length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (i32 i = 0; i < a->length; i++) {
|
||||||
|
if (a->bytes[i] != b->bytes[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool cStringEqString(str a, String* b) {
|
||||||
|
if (strlen(a) != b->length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (i32 i = 0; i < b->length; i++) {
|
||||||
|
if (a[i] != b->bytes[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Utf8Character classifyUtf8Character(u8 c) {
|
||||||
|
/*two_byte utf8 starts with 1100. 192
|
||||||
|
three_byte utf8 starts with 1110. 224
|
||||||
|
four_byte utf8 starts with 1111. 240*/
|
||||||
|
if (c <= 127) {
|
||||||
|
return Utf8CharacterAscii;
|
||||||
|
} else if (c >= 192 && c < 224) {
|
||||||
|
return Utf8CharacterTwoByte;
|
||||||
|
} else if (c >= 224 && c < 240) {
|
||||||
|
return Utf8CharacterThreeByte;
|
||||||
|
} else if (c >= 240) {
|
||||||
|
return Utf8CharacterFourByte;
|
||||||
|
} else {
|
||||||
|
assert(false && "Not a valid utf8 starting byte");
|
||||||
|
return Utf8Character_Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool isUtf8Ascii(u8 c) {
|
||||||
|
return classifyUtf8Character(c) == Utf8CharacterAscii;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool isUtf8TwoByte(u8 c) {
|
||||||
|
return classifyUtf8Character(c) == Utf8CharacterTwoByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool isUtf8ThreeByte(u8 c) {
|
||||||
|
return classifyUtf8Character(c) == Utf8CharacterThreeByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool isUtf8FourByte(u8 c) {
|
||||||
|
return classifyUtf8Character(c) == Utf8CharacterFourByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u8 lowerAscii(u8 c) {
|
||||||
|
if (c >= 65 && c <= 90) {
|
||||||
|
return c + 32;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u8 upperAscii(u8 c) {
|
||||||
|
if (c >= 97 && c <= 122) {
|
||||||
|
return c - 32;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool isAlphaUnderscoreSpace(u8 c) {
|
||||||
|
return ((c >= 'A' && c <= 'Z')
|
||||||
|
|| (c >= 'a' && c <= 'z')
|
||||||
|
|| c == ' '
|
||||||
|
|| c == '_');
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool isSimplePrintable(u8 c) {
|
||||||
|
return (c >= ' ' && c <= '~');
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct StrDecode {
|
||||||
|
u32 codepoint;
|
||||||
|
u32 size;
|
||||||
|
} StrDecode;
|
||||||
|
|
||||||
|
fn StrDecode strDecodeUTF8(u8 *str, u32 cap){
|
||||||
|
u8 length[] = {
|
||||||
|
1, 1, 1, 1, // 000xx
|
||||||
|
1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1,
|
||||||
|
0, 0, 0, 0, // 100xx
|
||||||
|
0, 0, 0, 0,
|
||||||
|
2, 2, 2, 2, // 110xx
|
||||||
|
3, 3, // 1110x
|
||||||
|
4, // 11110
|
||||||
|
0, // 11111
|
||||||
|
};
|
||||||
|
u8 first_byte_mask[] = { 0, 0x7F, 0x1F, 0x0F, 0x07 };
|
||||||
|
u8 final_shift[] = { 0, 18, 12, 6, 0 };
|
||||||
|
|
||||||
|
StrDecode result = {0};
|
||||||
|
if (cap > 0){
|
||||||
|
result.codepoint = '#';
|
||||||
|
result.size = 1;
|
||||||
|
|
||||||
|
u8 byte = str[0];
|
||||||
|
u8 l = length[byte >> 3];
|
||||||
|
if (0 < l && l <= cap){
|
||||||
|
u32 cp = (byte & first_byte_mask[l]) << 18;
|
||||||
|
switch (l){
|
||||||
|
case 4: cp |= ((str[3] & 0x3F) << 0);
|
||||||
|
case 3: cp |= ((str[2] & 0x3F) << 6);
|
||||||
|
case 2: cp |= ((str[1] & 0x3F) << 12);
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
cp >>= final_shift[l];
|
||||||
|
|
||||||
|
result.codepoint = cp;
|
||||||
|
result.size = l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u32 strEncodeUTF8(u8 *dst, u32 codepoint){
|
||||||
|
u32 size = 0;
|
||||||
|
if (codepoint < (1 << 8)) {
|
||||||
|
dst[0] = codepoint;
|
||||||
|
size = 1;
|
||||||
|
} else if (codepoint < (1 << 11)) {
|
||||||
|
dst[0] = 0xC0 | (codepoint >> 6);
|
||||||
|
dst[1] = 0x80 | (codepoint & 0x3F);
|
||||||
|
size = 2;
|
||||||
|
}
|
||||||
|
else if (codepoint < (1 << 16)) {
|
||||||
|
dst[0] = 0xE0 | (codepoint >> 12);
|
||||||
|
dst[1] = 0x80 | ((codepoint >> 6) & 0x3F);
|
||||||
|
dst[2] = 0x80 | (codepoint & 0x3F);
|
||||||
|
size = 3;
|
||||||
|
} else if (codepoint < (1 << 21)) {
|
||||||
|
dst[0] = 0xF0 | (codepoint >> 18);
|
||||||
|
dst[1] = 0x80 | ((codepoint >> 12) & 0x3F);
|
||||||
|
dst[2] = 0x80 | ((codepoint >> 6) & 0x3F);
|
||||||
|
dst[3] = 0x80 | (codepoint & 0x3F);
|
||||||
|
size = 4;
|
||||||
|
} else {
|
||||||
|
dst[0] = '#';
|
||||||
|
size = 1;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn StrDecode strDecodeUTF16(u16 *str, u32 cap){
|
||||||
|
StrDecode result = {'#', 1};
|
||||||
|
u16 x = str[0];
|
||||||
|
if (x < 0xD800 || 0xDFFF < x) {
|
||||||
|
result.codepoint = x;
|
||||||
|
} else if (cap >= 2) {
|
||||||
|
u16 y = str[1];
|
||||||
|
if (0xD800 <= x && x < 0xDC00 &&
|
||||||
|
0xDC00 <= y && y < 0xE000
|
||||||
|
) {
|
||||||
|
u16 xj = x - 0xD800;
|
||||||
|
u16 yj = y - 0xDc00;
|
||||||
|
u32 xy = (xj << 10) | yj;
|
||||||
|
result.codepoint = xy + 0x10000;
|
||||||
|
result.size = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u32 strEncodeUTF16(u16 *dst, u32 codepoint){
|
||||||
|
u32 size = 0;
|
||||||
|
if (codepoint < 0x10000) {
|
||||||
|
dst[0] = codepoint;
|
||||||
|
size = 1;
|
||||||
|
} else {
|
||||||
|
u32 cpj = codepoint - 0x10000;
|
||||||
|
dst[0] = (cpj >> 10) + 0xD800;
|
||||||
|
dst[1] = (cpj & 0x3FF) + 0xDC00;
|
||||||
|
size = 2;
|
||||||
|
}
|
||||||
|
return(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn StringUTF16Const str16FromStr8(Arena* arena, String string) {
|
||||||
|
u16* memory = arenaAllocArray(arena, u16, string.length * 2 + 1);
|
||||||
|
|
||||||
|
u16* dptr = memory;
|
||||||
|
u8* ptr = (u8*)string.bytes;
|
||||||
|
u8* opl = (u8*)string.bytes + string.length;
|
||||||
|
for (; ptr < opl;){
|
||||||
|
StrDecode decode = strDecodeUTF8(ptr, (u64)(opl - ptr));
|
||||||
|
u32 enc_size = strEncodeUTF16(dptr, decode.codepoint);
|
||||||
|
ptr += decode.size;
|
||||||
|
dptr += enc_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dptr = 0;
|
||||||
|
|
||||||
|
u64 alloc_count = string.length*2 + 1;
|
||||||
|
u64 string_count = (u64)(dptr - memory);
|
||||||
|
u64 unused_count = alloc_count - string_count - 1;
|
||||||
|
arenaDealloc(arena, unused_count * sizeof(*memory));
|
||||||
|
|
||||||
|
StringUTF16Const result = { memory, string_count };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
+162
@@ -0,0 +1,162 @@
|
|||||||
|
#include "all.h"
|
||||||
|
|
||||||
|
fn StringChunkList allocStringChunkList(StringArena* a, String string) {
|
||||||
|
StringChunkList result = {0};
|
||||||
|
u64 needed_chunks = (string.length + (STRING_CHUNK_PAYLOAD_SIZE-1)) / STRING_CHUNK_PAYLOAD_SIZE;
|
||||||
|
u64 bytes_left = string.length;
|
||||||
|
u64 string_offset = 0;
|
||||||
|
lockMutex(&a->mutex); {
|
||||||
|
for (u32 i = 0; i < needed_chunks; i++) {
|
||||||
|
StringChunk* chunk = a->first_free_str_chunk;
|
||||||
|
if (chunk == NULL) {
|
||||||
|
chunk = (StringChunk*)arenaAlloc(&a->a, sizeof(StringChunk)+STRING_CHUNK_PAYLOAD_SIZE);
|
||||||
|
} else {
|
||||||
|
a->first_free_str_chunk = a->first_free_str_chunk->next;
|
||||||
|
}
|
||||||
|
chunk->next = NULL; // makes sure we don't have a pointer to any other free_str_chunks
|
||||||
|
u64 bytes_to_copy = Min(bytes_left, STRING_CHUNK_PAYLOAD_SIZE);
|
||||||
|
// ryan's impl used chunk+1 which seems like a bug but what do I know he had a working demo
|
||||||
|
MemoryCopy(chunk+1, string.bytes+string_offset, bytes_to_copy);
|
||||||
|
QueuePush(result.first, result.last, chunk);
|
||||||
|
result.count += 1;
|
||||||
|
result.total_size += bytes_to_copy;
|
||||||
|
bytes_left -= bytes_to_copy;
|
||||||
|
string_offset += bytes_to_copy;
|
||||||
|
}
|
||||||
|
} unlockMutex(&a->mutex);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void releaseStringChunkList(StringArena* a, StringChunkList* list) {
|
||||||
|
StringChunk* chunk = list->first;
|
||||||
|
lockMutex(&a->mutex); {
|
||||||
|
for (StringChunk* next = NULL; chunk != NULL; chunk = next) {
|
||||||
|
next = chunk->next;
|
||||||
|
chunk->next = a->first_free_str_chunk;
|
||||||
|
a->first_free_str_chunk = chunk;
|
||||||
|
}
|
||||||
|
} unlockMutex(&a->mutex);
|
||||||
|
MemoryZeroStruct(list, StringChunkList);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn String stringChunkToString(Arena* a, StringChunkList list) {
|
||||||
|
String result = {
|
||||||
|
.length = list.total_size,
|
||||||
|
.capacity = list.total_size + 1,
|
||||||
|
.bytes = arenaAllocArray(a, u8, list.total_size+1),
|
||||||
|
};
|
||||||
|
// copy the string bytes out of the StringChunkList into the correctly-sized String
|
||||||
|
StringChunk* chunk = list.first;
|
||||||
|
for (u32 i = 0; i < list.total_size; i++) {
|
||||||
|
if (i > 0 && i % STRING_CHUNK_PAYLOAD_SIZE == 0) {
|
||||||
|
chunk = chunk->next;
|
||||||
|
}
|
||||||
|
result.bytes[i] = *((char*)(chunk + 1) + (i%STRING_CHUNK_PAYLOAD_SIZE));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void stringChunkListAppend(StringArena* a, StringChunkList* list, String string) {
|
||||||
|
u64 capacity = list->count * STRING_CHUNK_PAYLOAD_SIZE;
|
||||||
|
u64 remaining_space = capacity - list->total_size;
|
||||||
|
u64 bytes_in_last_chunk = (list->total_size % STRING_CHUNK_PAYLOAD_SIZE);
|
||||||
|
if (string.length < remaining_space) {
|
||||||
|
MemoryCopy(((u8*)list->last)+sizeof(StringChunk*)+(bytes_in_last_chunk), string.bytes, string.length);
|
||||||
|
list->total_size += string.length;
|
||||||
|
} else {
|
||||||
|
u64 string_offset = 0;
|
||||||
|
u64 bytes_left = string.length;
|
||||||
|
u64 bytes_to_copy = Min(bytes_left, remaining_space);
|
||||||
|
if (remaining_space > 0) {
|
||||||
|
// fill up the last chunk
|
||||||
|
MemoryCopy(((u8*)(list->last+1))+(bytes_in_last_chunk), string.bytes, bytes_to_copy);
|
||||||
|
bytes_left -= bytes_to_copy;
|
||||||
|
string_offset += bytes_to_copy;
|
||||||
|
list->total_size += bytes_to_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// then figure out how many more chunks we need
|
||||||
|
u64 needed_chunks = (bytes_left + (STRING_CHUNK_PAYLOAD_SIZE-1)) / STRING_CHUNK_PAYLOAD_SIZE;
|
||||||
|
lockMutex(&a->mutex); {
|
||||||
|
for (u32 i = 0; i < needed_chunks; i++) {
|
||||||
|
StringChunk* chunk = a->first_free_str_chunk;
|
||||||
|
if (chunk == NULL) {
|
||||||
|
chunk = (StringChunk*)arenaAlloc(&a->a, sizeof(StringChunk)+STRING_CHUNK_PAYLOAD_SIZE);
|
||||||
|
} else {
|
||||||
|
a->first_free_str_chunk = a->first_free_str_chunk->next;
|
||||||
|
}
|
||||||
|
chunk->next = NULL; // makes sure we don't have a pointer to any other free_str_chunks
|
||||||
|
bytes_to_copy = Min(bytes_left, STRING_CHUNK_PAYLOAD_SIZE);
|
||||||
|
// ryan's impl used chunk+1 which seems like a bug but what do I know he had a working demo
|
||||||
|
MemoryCopy(chunk+1, string.bytes+string_offset, bytes_to_copy);
|
||||||
|
QueuePush(list->first, list->last, chunk);
|
||||||
|
list->count += 1;
|
||||||
|
list->total_size += bytes_to_copy;
|
||||||
|
bytes_left -= bytes_to_copy;
|
||||||
|
string_offset += bytes_to_copy;
|
||||||
|
}
|
||||||
|
} unlockMutex(&a->mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void stringChunkListDeleteLast(StringArena* a, StringChunkList* list) {
|
||||||
|
if (list->total_size == 0) return;
|
||||||
|
|
||||||
|
u64 capacity = list->count * STRING_CHUNK_PAYLOAD_SIZE;
|
||||||
|
u64 remaining_space = capacity - list->total_size;
|
||||||
|
u64 bytes_in_last_chunk = STRING_CHUNK_PAYLOAD_SIZE - remaining_space;
|
||||||
|
|
||||||
|
bool theres_only_one_chunk = list->total_size <= STRING_CHUNK_PAYLOAD_SIZE;
|
||||||
|
bool last_chunk_only_has_one_byte = bytes_in_last_chunk == 1;
|
||||||
|
|
||||||
|
if (theres_only_one_chunk) {
|
||||||
|
ptr char_to_delete = ((char*)(list->last + 1) + (list->total_size-1));
|
||||||
|
char_to_delete[0] = '\0';
|
||||||
|
} else if (last_chunk_only_has_one_byte) {
|
||||||
|
// remove the last chunk when it's not the only chunk
|
||||||
|
StringChunk* second_to_last_chunk = list->first;
|
||||||
|
while (second_to_last_chunk->next != list->last && second_to_last_chunk->next != NULL) {
|
||||||
|
second_to_last_chunk = second_to_last_chunk->next;
|
||||||
|
}
|
||||||
|
second_to_last_chunk->next = NULL;
|
||||||
|
lockMutex(&a->mutex); {
|
||||||
|
list->last->next = a->first_free_str_chunk;
|
||||||
|
a->first_free_str_chunk = list->last;
|
||||||
|
} unlockMutex(&a->mutex);
|
||||||
|
list->last = second_to_last_chunk;
|
||||||
|
list->count -= 1;
|
||||||
|
} else {
|
||||||
|
ptr char_to_delete = ((char*)(list->last + 1) + ((list->total_size-1) % STRING_CHUNK_PAYLOAD_SIZE));
|
||||||
|
char_to_delete[0] = '\0';
|
||||||
|
}
|
||||||
|
list->total_size -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn StringChunkList stringChunkListInit(StringArena* a) {
|
||||||
|
StringChunkList result = {0};
|
||||||
|
lockMutex(&a->mutex); {
|
||||||
|
StringChunk* chunk = a->first_free_str_chunk;
|
||||||
|
if (chunk == NULL) {
|
||||||
|
chunk = (StringChunk*)arenaAlloc(&a->a, sizeof(StringChunk)+STRING_CHUNK_PAYLOAD_SIZE);
|
||||||
|
} else {
|
||||||
|
a->first_free_str_chunk = a->first_free_str_chunk->next;
|
||||||
|
}
|
||||||
|
chunk->next = NULL; // makes sure we don't have a pointer to any other free_str_chunks
|
||||||
|
MemoryZero(chunk+1, STRING_CHUNK_PAYLOAD_SIZE);
|
||||||
|
QueuePush(result.first, result.last, chunk);
|
||||||
|
result.count += 1;
|
||||||
|
} unlockMutex(&a->mutex);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void stringChunkCopyToBuffer(StringChunkList* list, u8* buffer, u32 len) {
|
||||||
|
assert(list->total_size <= len);
|
||||||
|
|
||||||
|
StringChunk* chunk = list->first;
|
||||||
|
for (u32 i = 0; i < list->total_size; i++) {
|
||||||
|
if (i > 0 && i % STRING_CHUNK_PAYLOAD_SIZE == 0) {
|
||||||
|
chunk = chunk->next;
|
||||||
|
}
|
||||||
|
buffer[i] = *((char*)(chunk + 1) + (i%STRING_CHUNK_PAYLOAD_SIZE));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
#include "all.h"
|
||||||
|
|
||||||
|
void tctxInit(ThreadContext* ctx) {
|
||||||
|
arenaInit(&ctx->arena);
|
||||||
|
osThreadContextSet(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tctxFree(ThreadContext* ctx) {
|
||||||
|
arenaFree(&ctx->arena);
|
||||||
|
osThreadContextSet(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ThreadContext *tctxSelected(void) {
|
||||||
|
return (ThreadContext*)osThreadContextGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
ScratchMem tctxScratchGet(ThreadContext* ctx) {
|
||||||
|
if (!ctx->free_list) {
|
||||||
|
ScratchMem scratch = {0};
|
||||||
|
|
||||||
|
scratch.arena.memory = arenaAlloc(&ctx->arena, M_SCRATCH_SIZE);
|
||||||
|
scratch.arena.max = M_SCRATCH_SIZE;
|
||||||
|
scratch.arena.alloc_position = 0;
|
||||||
|
scratch.arena.commit_position = M_SCRATCH_SIZE;
|
||||||
|
scratch.arena.static_size = true;
|
||||||
|
|
||||||
|
ctx->max_created++;
|
||||||
|
return scratch;
|
||||||
|
} else {
|
||||||
|
ScratchMem scratch = {0};
|
||||||
|
|
||||||
|
scratch.arena.memory = (u8*) ctx->free_list;
|
||||||
|
scratch.arena.max = M_SCRATCH_SIZE;
|
||||||
|
scratch.arena.alloc_position = 0;
|
||||||
|
scratch.arena.commit_position = M_SCRATCH_SIZE;
|
||||||
|
scratch.arena.static_size = true;
|
||||||
|
|
||||||
|
ctx->free_list = ctx->free_list->next;
|
||||||
|
return scratch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tctxScratchReset(ThreadContext* ctx, ScratchMem* scratch) {
|
||||||
|
scratch->arena.alloc_position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tctxScratchReturn(ThreadContext* ctx, ScratchMem* scratch) {
|
||||||
|
ScratchFreeListNode* prev_head = ctx->free_list;
|
||||||
|
ctx->free_list = (ScratchFreeListNode*) scratch->arena.memory;
|
||||||
|
ctx->free_list->next = prev_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn LaneCtx tctxSetLaneCtx(LaneCtx lane_ctx) {
|
||||||
|
ThreadContext *tctx = tctxSelected();
|
||||||
|
LaneCtx restore = tctx->lane_ctx;
|
||||||
|
tctx->lane_ctx = lane_ctx;
|
||||||
|
return restore;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void tctxLaneBarrierWait(void *broadcast_ptr, u64 broadcast_size, u64 broadcast_src_lane_idx) {
|
||||||
|
ThreadContext *tctx = tctxSelected();
|
||||||
|
|
||||||
|
// broadcasting -> copy to broadcast memory on source lane
|
||||||
|
u64 broadcast_size_clamped = Min(broadcast_size, sizeof(tctx->lane_ctx.broadcast_memory[0]));
|
||||||
|
if(broadcast_ptr != 0 && LaneIdx() == broadcast_src_lane_idx) {
|
||||||
|
MemoryCopy(tctx->lane_ctx.broadcast_memory, broadcast_ptr, broadcast_size_clamped);
|
||||||
|
}
|
||||||
|
|
||||||
|
// all cases: barrier
|
||||||
|
osBarrierWait(tctx->lane_ctx.barrier);
|
||||||
|
|
||||||
|
// broadcasting -> copy from broadcast memory on destination lanes
|
||||||
|
if(broadcast_ptr != 0 && LaneIdx() != broadcast_src_lane_idx)
|
||||||
|
{
|
||||||
|
MemoryCopy(broadcast_ptr, tctx->lane_ctx.broadcast_memory, broadcast_size_clamped);
|
||||||
|
}
|
||||||
|
|
||||||
|
// broadcasting -> barrier on all lanes
|
||||||
|
if(broadcast_ptr != 0)
|
||||||
|
{
|
||||||
|
osBarrierWait(tctx->lane_ctx.barrier);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#include "all.h"
|
||||||
|
|
||||||
|
Thread spawnThread(void * (*threadFn)(void *), void* thread_arg) {
|
||||||
|
pthread_t thread;
|
||||||
|
pthread_create(&thread, NULL, threadFn, thread_arg);
|
||||||
|
Thread result = { thread };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mutex newMutex() {
|
||||||
|
Mutex result = { PTHREAD_MUTEX_INITIALIZER };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cond newCond() {
|
||||||
|
Cond result = { 0 };
|
||||||
|
pthread_cond_init(&result.cond, NULL);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lockMutex(Mutex* m) {
|
||||||
|
pthread_mutex_lock(&m->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlockMutex(Mutex* m) {
|
||||||
|
pthread_mutex_unlock(&m->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void signalCond(Cond* cond) {
|
||||||
|
pthread_cond_signal(&cond->cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
void waitForCondSignal(Cond* cond, Mutex* mutex) {
|
||||||
|
pthread_cond_wait(&cond->cond, &mutex->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
#include "types.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#ifndef BASE_THREAD_CONTEXT_H
|
||||||
|
#define BASE_THREAD_CONTEXT_H
|
||||||
|
|
||||||
|
typedef struct LaneCtx {
|
||||||
|
u64 lane_idx;
|
||||||
|
u64 lane_count;
|
||||||
|
Barrier barrier;
|
||||||
|
u64 *broadcast_memory;
|
||||||
|
} LaneCtx;
|
||||||
|
|
||||||
|
typedef struct AccessPt AccessPt;
|
||||||
|
struct AccessPt
|
||||||
|
{
|
||||||
|
u64 access_refcount;
|
||||||
|
u64 last_time_touched_us;
|
||||||
|
u64 last_update_idx_touched;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct AccessPtExpireParams AccessPtExpireParams;
|
||||||
|
struct AccessPtExpireParams
|
||||||
|
{
|
||||||
|
u64 time;
|
||||||
|
u64 update_idxs;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Touch Touch;
|
||||||
|
struct Touch
|
||||||
|
{
|
||||||
|
Touch *next;
|
||||||
|
AccessPt *pt;
|
||||||
|
CondVar cv;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Access Access;
|
||||||
|
struct Access
|
||||||
|
{
|
||||||
|
Access *next;
|
||||||
|
Touch *top_touch;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct TCtx {
|
||||||
|
// scratch arenas
|
||||||
|
Arena *arenas[2];
|
||||||
|
u8 thread_name[32];
|
||||||
|
u64 thread_name_size;
|
||||||
|
|
||||||
|
LaneCtx lane_ctx;
|
||||||
|
|
||||||
|
// source location info
|
||||||
|
char *file_name;
|
||||||
|
u64 line_number;
|
||||||
|
|
||||||
|
// accesses
|
||||||
|
Arena *access_arena;
|
||||||
|
Access *free_access;
|
||||||
|
Touch *free_touch;
|
||||||
|
|
||||||
|
u64 *progress_counter_ptr;
|
||||||
|
u64 *progress_target_ptr;
|
||||||
|
} TCtx;
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Thread Context Functions
|
||||||
|
|
||||||
|
// thread-context allocation & selection
|
||||||
|
fn TCtx *tctxAlloc(void);
|
||||||
|
fn void tctxRelease(TCtx *tctx);
|
||||||
|
fn void tctxSelect(TCtx *tctx);
|
||||||
|
fn TCtx *tctxSelected(void);
|
||||||
|
|
||||||
|
//- rjf: scratch arenas
|
||||||
|
internal Arena *tctx_get_scratch(Arena **conflicts, U64 count);
|
||||||
|
#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count)))
|
||||||
|
#define scratch_end(scratch) temp_end(scratch)
|
||||||
|
|
||||||
|
//- rjf: lane metadata
|
||||||
|
internal LaneCtx tctx_set_lane_ctx(LaneCtx lane_ctx);
|
||||||
|
internal void tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_src_lane_idx);
|
||||||
|
#define lane_idx() (tctx_selected()->lane_ctx.lane_idx)
|
||||||
|
#define lane_count() (tctx_selected()->lane_ctx.lane_count)
|
||||||
|
#define lane_from_task_idx(idx) ((idx)%lane_count())
|
||||||
|
#define lane_ctx(ctx) tctx_set_lane_ctx((ctx))
|
||||||
|
#define lane_sync() tctx_lane_barrier_wait(0, 0, 0)
|
||||||
|
#define lane_sync_u64(ptr, src_lane_idx) tctx_lane_barrier_wait((ptr), sizeof(*(ptr)), (src_lane_idx))
|
||||||
|
#define lane_range(count) m_range_from_n_idx_m_count(lane_idx(), lane_count(), (count))
|
||||||
|
|
||||||
|
//- rjf: thread names
|
||||||
|
internal void tctx_set_thread_name(String8 name);
|
||||||
|
internal String8 tctx_get_thread_name(void);
|
||||||
|
|
||||||
|
//- rjf: thread source-locations
|
||||||
|
internal void tctx_write_srcloc(char *file_name, U64 line_number);
|
||||||
|
internal void tctx_read_srcloc(char **file_name, U64 *line_number);
|
||||||
|
#define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__)
|
||||||
|
|
||||||
|
//- rjf: access scopes
|
||||||
|
internal Access *access_open(void);
|
||||||
|
internal void access_close(Access *access);
|
||||||
|
internal void access_touch(Access *access, AccessPt *pt, CondVar cv);
|
||||||
|
|
||||||
|
//- rjf: access points
|
||||||
|
internal B32 access_pt_is_expired_(AccessPt *pt, AccessPtExpireParams *params);
|
||||||
|
#define access_pt_is_expired(pt, ...) access_pt_is_expired_((pt), &(AccessPtExpireParams){.time = 2000000, .update_idxs = 2, __VA_ARGS__})
|
||||||
|
|
||||||
|
//- rjf: progress counters
|
||||||
|
#define set_progress_ptr(ptr) (tctx_selected()->progress_counter_ptr = (ptr))
|
||||||
|
#define set_progress_target_ptr(ptr) (tctx_selected()->progress_target_ptr = (ptr))
|
||||||
|
#define set_progress(val) (tctx_selected()->progress_counter_ptr ? ins_atomic_u64_eval_assign(tctx_selected()->progress_counter_ptr, (val)) : (void)0)
|
||||||
|
#define add_progress(val) (tctx_selected()->progress_counter_ptr ? ins_atomic_u64_add_eval(tctx_selected()->progress_counter_ptr, (val)) : (void)0)
|
||||||
|
#define set_progress_target(val) (tctx_selected()->progress_target_ptr ? ins_atomic_u64_eval_assign(tctx_selected()->progress_target_ptr, (val)) : (void)0)
|
||||||
|
|
||||||
|
#endif // BASE_THREAD_CONTEXT_H
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
#include "all.h"
|
||||||
|
|
||||||
|
global pthread_key_t linux_thread_context_key;
|
||||||
|
// ThreadContext
|
||||||
|
void osInit() {
|
||||||
|
pthread_key_create(&linux_thread_context_key, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* osThreadContextGet() {
|
||||||
|
return pthread_getspecific(linux_thread_context_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void osThreadContextSet(void* ctx) {
|
||||||
|
pthread_setspecific(linux_thread_context_key, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool osThreadJoin(Thread handle, u64 endt_us) {
|
||||||
|
/*
|
||||||
|
if(MemoryIsZeroStruct(&handle)) { return 0; }
|
||||||
|
OS_LNX_Entity *entity = (OS_LNX_Entity *)handle.u64[0];
|
||||||
|
int join_result = pthread_join(entity->thread.handle, 0);
|
||||||
|
B32 result = (join_result == 0);
|
||||||
|
os_lnx_entity_release(entity);
|
||||||
|
return result;
|
||||||
|
*/
|
||||||
|
i32 join_result = pthread_join(handle.thread, NULL);
|
||||||
|
bool result = join_result == 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory
|
||||||
|
fn void* osMemoryReserve(u64 size) {
|
||||||
|
void* result = mmap(((void*)0), size, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||||
|
if(result == MAP_FAILED) {
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void osMemoryCommit(void* memory, u64 size) {
|
||||||
|
i32 result = mprotect(memory, size, PROT_READ | PROT_WRITE);
|
||||||
|
assert(result == 0 && "osMemoryCommit() failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void osMemoryDecommit(void* memory, u64 size) {
|
||||||
|
mprotect(memory, size, PROT_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void osMemoryRelease(void* memory, u64 size) {
|
||||||
|
munmap(memory, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TUI
|
||||||
|
TermIOs osStartTUI(bool blocking) {
|
||||||
|
// set up the TUI incantations
|
||||||
|
printf("\033[?1049h"); // go to alternate buffer
|
||||||
|
TermIOs terminal_attributes, old_terminal_attributes;
|
||||||
|
tcgetattr(STDOUT_FILENO, &terminal_attributes);
|
||||||
|
old_terminal_attributes = terminal_attributes;
|
||||||
|
terminal_attributes.c_lflag &= ~(ICANON | ECHO); // dont echo keypresses, dont wait for carriage return
|
||||||
|
tcsetattr(STDOUT_FILENO, TCSANOW, &terminal_attributes);
|
||||||
|
if (!blocking) {
|
||||||
|
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); // non-blocking input mode
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
return old_terminal_attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void osEndTUI(TermIOs old_terminal_attributes) {
|
||||||
|
tcsetattr(STDOUT_FILENO, TCSANOW, &old_terminal_attributes);
|
||||||
|
|
||||||
|
// cleanup terminal TUI incantations
|
||||||
|
printf("\033[?1049l");
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Dim2 osGetTerminalDimensions() {
|
||||||
|
Dim2 result = {0};
|
||||||
|
struct winsize ws;
|
||||||
|
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1) {
|
||||||
|
//perror("ioctl TIOCGWINSZ failed");
|
||||||
|
//exit(1);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result.width = ws.ws_col;
|
||||||
|
result.height = ws.ws_row;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void osBlitToTerminal(ptr writeable_output_ansi_string, i64 count) {
|
||||||
|
int flags = fcntl(STDOUT_FILENO, F_GETFL);
|
||||||
|
fcntl(STDOUT_FILENO, F_SETFL, flags & ~O_NONBLOCK);
|
||||||
|
|
||||||
|
u64 total = 0;
|
||||||
|
while (total < count) {
|
||||||
|
i64 written_bytes = write(STDOUT_FILENO, writeable_output_ansi_string + total, count - total);
|
||||||
|
/* TODO handle this error
|
||||||
|
if (written_bytes < 0) {
|
||||||
|
if (errno == EINTR) continue; // Interrupted, retry
|
||||||
|
return -1; // Real error
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
total += written_bytes;
|
||||||
|
}
|
||||||
|
fcntl(STDOUT_FILENO, F_SETFL, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool osInitNetwork() { return true; }
|
||||||
|
|
||||||
|
void osReadConsoleInput(u8* buffer, u32 len) {
|
||||||
|
MemoryZero(buffer, len); // reset the input so it's not contaminated by last keystroke
|
||||||
|
read(STDIN_FILENO, buffer, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LOCALHOST_127 16777343
|
||||||
|
i32 osLanIPAddress() { // returns as HOST byte-order
|
||||||
|
i32 result = 0;
|
||||||
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
|
if (getifaddrs(&ifaddr) != -1) {
|
||||||
|
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
|
||||||
|
if (ifa->ifa_addr == NULL) continue;
|
||||||
|
|
||||||
|
int family = ifa->ifa_addr->sa_family;
|
||||||
|
|
||||||
|
if (family == AF_INET) {
|
||||||
|
struct sockaddr_in addr = *(struct sockaddr_in*)ifa->ifa_addr;
|
||||||
|
if (addr.sin_addr.s_addr != LOCALHOST_127) {
|
||||||
|
freeifaddrs(ifaddr);
|
||||||
|
//printf("%s %d %d", inet_ntoa(addr.sin_addr), addr.sin_addr.s_addr, ntohl(addr.sin_addr.s_addr));
|
||||||
|
return ntohl(addr.sin_addr.s_addr);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
char host[NI_MAXHOST];
|
||||||
|
int s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in),
|
||||||
|
host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
|
||||||
|
|
||||||
|
if (s == 0) {
|
||||||
|
printf("Interface: %s\tAddress: %s\n", ifa->ifa_name, host);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs(ifaddr);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
+326
@@ -0,0 +1,326 @@
|
|||||||
|
#include "string.h"
|
||||||
|
#include "os.h"
|
||||||
|
#include <userenv.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static u64 w32_ticks_per_sec = 1;
|
||||||
|
static u32 w32_thread_context_index;
|
||||||
|
|
||||||
|
void osInit() {
|
||||||
|
LARGE_INTEGER perf_freq = {0};
|
||||||
|
if (QueryPerformanceFrequency(&perf_freq)) {
|
||||||
|
w32_ticks_per_sec = ((u64)perf_freq.HighPart << 32) | perf_freq.LowPart;
|
||||||
|
}
|
||||||
|
timeBeginPeriod(1);
|
||||||
|
|
||||||
|
w32_thread_context_index = TlsAlloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* osThreadContextGet() {
|
||||||
|
return TlsGetValue(w32_thread_context_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void osThreadContextSet(void* ctx) {
|
||||||
|
TlsSetValue(w32_thread_context_index, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory
|
||||||
|
fn void* osMemoryReserve(u64 size) {
|
||||||
|
return VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void osMemoryCommit(void* memory, u64 size) {
|
||||||
|
VirtualAlloc(memory, size, MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void osMemoryDecommit(void* memory, u64 size) {
|
||||||
|
VirtualFree(memory, size, MEM_DECOMMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void osMemoryRelease(void* memory, u64 size) {
|
||||||
|
VirtualFree(memory, 0, MEM_RELEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time
|
||||||
|
fn u64 osTimeMicrosecondsNow() {
|
||||||
|
u64 result = 0;
|
||||||
|
LARGE_INTEGER perf_counter = {0};
|
||||||
|
if (QueryPerformanceCounter(&perf_counter)) {
|
||||||
|
u64 ticks = ((u64)perf_counter.HighPart << 32) | perf_counter.LowPart;
|
||||||
|
result = ticks * 1000000 / w32_ticks_per_sec;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MICROSECONDS_PER_MILLISECOND 1000
|
||||||
|
fn void osSleepMicroseconds(u32 t) {
|
||||||
|
Sleep(t / MICROSECONDS_PER_MILLISECOND);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Files
|
||||||
|
fn bool osFileExists(String filename) {
|
||||||
|
assert(false && "Not Implemented");
|
||||||
|
ScratchMem scratch = scratchGet();
|
||||||
|
StringUTF16Const filename16 = str16FromStr8(&scratch.arena, filename);
|
||||||
|
DWORD ret = GetFileAttributesW((WCHAR*)filename16.string);
|
||||||
|
scratchReturn(&scratch);
|
||||||
|
return (ret != INVALID_FILE_ATTRIBUTES && !(ret & FILE_ATTRIBUTE_DIRECTORY));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn String osFileRead(Arena* arena, ptr filepath) {
|
||||||
|
assert(false && "Not Implemented");
|
||||||
|
String result = {0};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool osFileCreate(String filename) {
|
||||||
|
assert(false && "Not Implemented");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool osFileCreateWrite(String filename, String data) {
|
||||||
|
assert(false && "Not Implemented");
|
||||||
|
bool result = true;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bool osFileWrite(String filename, String data) {
|
||||||
|
assert(false && "Not Implemented");
|
||||||
|
bool result = true;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
fn void osDebugPrint(bool debug_mode, const char * format, ... ) {
|
||||||
|
if (debug_mode) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
vprintf(format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TUI
|
||||||
|
TermIOs osStartTUI(bool blocking) {
|
||||||
|
TermIOs old_settings;
|
||||||
|
|
||||||
|
// Windows implementation
|
||||||
|
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
|
||||||
|
// Save old console modes
|
||||||
|
GetConsoleMode(hStdin, &old_settings.input_mode);
|
||||||
|
GetConsoleMode(hStdout, &old_settings.output_mode);
|
||||||
|
|
||||||
|
// Set up alternate screen buffer
|
||||||
|
printf("\033[?1049h");
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
// Disable line input and echo (equivalent to ~ICANON and ~ECHO)
|
||||||
|
DWORD new_input_mode = old_settings.input_mode;
|
||||||
|
new_input_mode &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
|
||||||
|
|
||||||
|
// Enable virtual terminal processing for ANSI escape sequences
|
||||||
|
DWORD new_output_mode = old_settings.output_mode;
|
||||||
|
new_output_mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
|
|
||||||
|
SetConsoleMode(hStdin, new_input_mode);
|
||||||
|
SetConsoleMode(hStdout, new_output_mode);
|
||||||
|
|
||||||
|
SetConsoleOutputCP(CP_UTF8);
|
||||||
|
|
||||||
|
// Note: Windows console is inherently non-blocking when using
|
||||||
|
// ENABLE_LINE_INPUT disabled. You can check for input with:
|
||||||
|
// DWORD events;
|
||||||
|
// GetNumberOfConsoleInputEvents(hStdin, &events);
|
||||||
|
// Or use PeekConsoleInput() before ReadConsoleInput()
|
||||||
|
|
||||||
|
return old_settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void osEndTUI(TermIOs old_terminal_attributes) {
|
||||||
|
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
|
||||||
|
// Restore console modes
|
||||||
|
SetConsoleMode(hStdin, old_terminal_attributes.input_mode);
|
||||||
|
SetConsoleMode(hStdout, old_terminal_attributes.output_mode);
|
||||||
|
|
||||||
|
// cleanup terminal TUI incantations
|
||||||
|
printf("\033[?1049l");
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Dim2 osGetTerminalDimensions() {
|
||||||
|
Dim2 result = {0};
|
||||||
|
|
||||||
|
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
|
|
||||||
|
if (GetConsoleScreenBufferInfo(hStdout, &csbi)) {
|
||||||
|
result.width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
||||||
|
result.height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
|
||||||
|
} else {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void osBlitToTerminal(ptr writeable_output_ansi_string, i64 count) {
|
||||||
|
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
DWORD written;
|
||||||
|
WriteConsole(hStdout, writeable_output_ansi_string, count, &written, NULL);
|
||||||
|
assert(written == count);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool osInitNetwork() {
|
||||||
|
WSADATA wsaData;
|
||||||
|
|
||||||
|
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
|
||||||
|
WSACleanup();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void osReadConsoleInput(u8* buffer, u32 len) {
|
||||||
|
MemoryZero(buffer, len); // reset the input so it's not contaminated by last keystroke
|
||||||
|
|
||||||
|
if (_kbhit()) {
|
||||||
|
buffer[0] = _getch();
|
||||||
|
bool first_byte_is_special = buffer[0] == 0 || buffer[0] == 224;
|
||||||
|
if (first_byte_is_special && _kbhit()) {
|
||||||
|
u8 windows_key = _getch();
|
||||||
|
switch (windows_key) {
|
||||||
|
case 72: buffer[0] = 27; buffer[1] = 91; buffer[2] = 65; break; // up
|
||||||
|
case 75: buffer[0] = 27; buffer[1] = 91; buffer[2] = 68; break; // left
|
||||||
|
case 77: buffer[0] = 27; buffer[1] = 91; buffer[2] = 67; break; // right
|
||||||
|
case 80: buffer[0] = 27; buffer[1] = 91; buffer[2] = 66; break; // down
|
||||||
|
default: buffer[1] = windows_key;
|
||||||
|
}
|
||||||
|
/*if (_kbhit()) {
|
||||||
|
buffer[2] = _getch();
|
||||||
|
if (_kbhit()) {
|
||||||
|
buffer[3] = _getch();
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
INPUT_RECORD ir;
|
||||||
|
DWORD read;
|
||||||
|
if (PeekConsoleInput(hStdin, &ir, 1, &read) && read > 0) {
|
||||||
|
ReadConsole(hStdin, buffer, len, &read, NULL);
|
||||||
|
ReadConsoleInput(hStdin, &ir, 1, &read);
|
||||||
|
if (ir.EventType == KEY_EVENT) {
|
||||||
|
buffer[0] = ir.Event.KeyEvent.uChar.AsciiChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 osLanIPAddress() {
|
||||||
|
i32 result = 0;
|
||||||
|
/*
|
||||||
|
IP_ADAPTER_INFO *pAdapterInfo;
|
||||||
|
IP_ADAPTER_INFO *pAdapter = NULL;
|
||||||
|
DWORD dwRetVal = 0;
|
||||||
|
ULONG ulOutBufLen;
|
||||||
|
|
||||||
|
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
|
||||||
|
ulOutBufLen = sizeof(IP_ADAPTER_INFO);
|
||||||
|
|
||||||
|
// Make an initial call to GetAdaptersInfo to get the necessary size
|
||||||
|
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
|
||||||
|
free(pAdapterInfo);
|
||||||
|
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
|
||||||
|
pAdapter = pAdapterInfo;
|
||||||
|
printf("LAN Addresses:\n");
|
||||||
|
|
||||||
|
// TODO: test this on windows
|
||||||
|
while (pAdapter) {
|
||||||
|
printf("Interface: %s\n", pAdapter->AdapterName);
|
||||||
|
printf("Description: %s\n", pAdapter->Description);
|
||||||
|
printf("IP Address: %s\n", pAdapter->IpAddressList.IpAddress.String);
|
||||||
|
printf("IP Address: %d\n", pAdapter->Address[0] << 24 | pAdapter->Address[1] << 16 | pAdapter->Address[2] << 8 | pAdapter->Address[3]);
|
||||||
|
printf("\n");
|
||||||
|
pAdapter = pAdapter->Next;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("GetAdaptersInfo failed: %ld\n", dwRetVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pAdapterInfo) {
|
||||||
|
free(pAdapterInfo);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
WSADATA wsa;
|
||||||
|
char hostname[256];
|
||||||
|
struct addrinfo hints, *final = NULL, *ptr = NULL;
|
||||||
|
struct sockaddr_in *sockaddr_ipv4;
|
||||||
|
|
||||||
|
// Initialize Winsock
|
||||||
|
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get hostname
|
||||||
|
if (gethostname(hostname, sizeof(hostname)) == SOCKET_ERROR) {
|
||||||
|
WSACleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up hints for getaddrinfo
|
||||||
|
ZeroMemory(&hints, sizeof(hints));
|
||||||
|
hints.ai_family = AF_INET; // IPv4
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_protocol = IPPROTO_TCP;
|
||||||
|
|
||||||
|
// Get address info
|
||||||
|
if (getaddrinfo(hostname, NULL, &hints, &final) != 0) {
|
||||||
|
WSACleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through results to find a non-loopback address
|
||||||
|
for (ptr = final; ptr != NULL; ptr = ptr->ai_next) {
|
||||||
|
sockaddr_ipv4 = (struct sockaddr_in *)ptr->ai_addr;
|
||||||
|
unsigned long addr = ntohl(sockaddr_ipv4->sin_addr.s_addr);
|
||||||
|
|
||||||
|
// Skip loopback addresses (127.x.x.x)
|
||||||
|
if ((addr >> 24) != 127) {
|
||||||
|
result = sockaddr_ipv4->sin_addr.s_addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(final);
|
||||||
|
WSACleanup();
|
||||||
|
|
||||||
|
return ntohl(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool osThreadJoin(Thread handle, u64 endt_us) {
|
||||||
|
DWORD sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us);
|
||||||
|
OS_W32_Entity *entity = (OS_W32_Entity *)PtrFromInt(handle.u64[0]);
|
||||||
|
DWORD wait_result = WAIT_OBJECT_0;
|
||||||
|
if(entity != 0)
|
||||||
|
{
|
||||||
|
wait_result = WaitForSingleObject(entity->thread.handle, sleep_ms);
|
||||||
|
CloseHandle(entity->thread.handle);
|
||||||
|
os_w32_entity_release(entity);
|
||||||
|
}
|
||||||
|
return (wait_result == WAIT_OBJECT_0);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user