From 062285b1b30605da7a23946a983d03a67a0b3e34 Mon Sep 17 00:00:00 2001 From: jacob Date: Fri, 31 Jan 2025 10:26:07 -0600 Subject: [PATCH] socket progress --- build.c | 2 + src/app.c | 46 ++++- src/common.h | 8 +- src/font.c | 2 +- src/game.c | 49 ++++- src/game.h | 4 +- src/sock.h | 62 ++++++ src/sock_win32.c | 494 +++++++++++++++++++++++++++++++++++++++++++++++ src/sound.c | 2 +- src/sprite.c | 4 +- src/string.c | 18 +- src/string.h | 3 +- src/sys_win32.c | 136 ++++++------- src/user.c | 37 ++++ src/user.h | 2 + 15 files changed, 779 insertions(+), 90 deletions(-) create mode 100644 src/sock.h create mode 100644 src/sock_win32.c diff --git a/build.c b/build.c index 40be62e3..ee1006e8 100644 --- a/build.c +++ b/build.c @@ -725,12 +725,14 @@ void OnBuild(StringList cli_args) Bool is_cpp = !is_dir && !is_c && StringEqual(extension, Lit("cpp")); if (is_c || is_cpp) { if (StringBeginsWith(name, Lit("sys_")) || + StringBeginsWith(name, Lit("sock_")) || StringBeginsWith(name, Lit("renderer_")) || StringBeginsWith(name, Lit("playback_")) || StringBeginsWith(name, Lit("mp3_")) || StringBeginsWith(name, Lit("ttf_"))) { if (PlatformWindows) { ignore = !(StringEqual(name, Lit("sys_win32.c")) || + StringEqual(name, Lit("sock_win32.c")) || StringEqual(name, Lit("renderer_d3d11.c")) || StringEqual(name, Lit("playback_wasapi.c")) || StringEqual(name, Lit("mp3_mmf.c")) || diff --git a/src/app.c b/src/app.c index 3cd39c4c..0bf0c4b6 100644 --- a/src/app.c +++ b/src/app.c @@ -22,6 +22,7 @@ #include "renderer.h" #include "phys.h" #include "rng.h" +#include "sock.h" struct exit_callback { app_exit_callback_func *func; @@ -122,6 +123,45 @@ void app_register_exit_callback(app_exit_callback_func *func) * Entry point * ========================== */ + + + + + + + + +INTERNAL SOCK_RECEIVE_CALLBACK_FUNC_DEF(server_recv, address, msg) +{ + (UNUSED)address; + (UNUSED)msg; + DEBUGBREAKABLE; +} + +INTERNAL SOCK_RECEIVE_CALLBACK_FUNC_DEF(client_recv, address, msg) +{ + (UNUSED)address; + (UNUSED)msg; + DEBUGBREAKABLE; +} + + + + + + + + + + + + + + + + + + void app_entry_point(void) { struct temp_arena scratch = scratch_begin_no_conflict(); @@ -205,6 +245,7 @@ void app_entry_point(void) } /* Startup systems */ + struct sock_startup_receipt sock_sr = sock_startup(); struct resource_startup_receipt resource_sr = resource_startup(); struct rng_startup_receipt rng_sr = rng_startup(&resource_sr); struct renderer_startup_receipt renderer_sr = renderer_startup(&window); @@ -217,10 +258,11 @@ void app_entry_point(void) struct sound_startup_receipt sound_sr = sound_startup(&work_sr, &asset_cache_sr, &resource_sr); struct draw_startup_receipt draw_sr = draw_startup(&renderer_sr, &font_sr); struct phys_startup_receipt phys_sr = phys_startup(); - struct game_startup_receipt game_sr = game_startup(&mixer_sr, &sprite_sr, &sound_sr, &phys_sr); - struct user_startup_receipt user_sr = user_startup(&work_sr, &renderer_sr, &font_sr, &sprite_sr, &draw_sr, &game_sr, &asset_cache_sr, &mixer_sr, &window); + struct game_startup_receipt game_sr = game_startup(&mixer_sr, &sprite_sr, &sound_sr, &phys_sr, &sock_sr); + struct user_startup_receipt user_sr = user_startup(&work_sr, &renderer_sr, &font_sr, &sprite_sr, &draw_sr, &game_sr, &asset_cache_sr, &mixer_sr, &sock_sr, &window); struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr); + (UNUSED)sock_sr; (UNUSED)user_sr; (UNUSED)playback_sr; (UNUSED)rng_sr; diff --git a/src/common.h b/src/common.h index 8bab81af..586c0bed 100644 --- a/src/common.h +++ b/src/common.h @@ -377,8 +377,8 @@ GLOBAL const f64 *_f64_nan = (f64 *)&_f64_nan_u64; #if COMPILER_CLANG #define U128(hi64, lo64) (((u128)(hi64) << 64) | (lo64)) -#define U128_HI64(a) ((u64)((a) >> 64)) -#define U128_LO64(a) ((u64)(a)) +#define U128_HI(a) ((u64)((a) >> 64)) +#define U128_LO(a) ((u64)(a)) typedef __uint128_t u128; @@ -395,8 +395,8 @@ INLINE u128 u128_mul(u128 a, u128 b) { return a * b; } #else # define U128(hi64, lo64) ((u128) { .hi = (hi64), .lo = (lo64) }) #endif -#define U128_HI64(a) ((a).hi) -#define U128_LO64(a) ((a).lo) +#define U128_HI(a) ((a).hi) +#define U128_LO(a) ((a).lo) typedef struct { u64 hi; u64 lo; } u128; diff --git a/src/font.c b/src/font.c index fe05bb70..84c28b42 100644 --- a/src/font.c +++ b/src/font.c @@ -97,7 +97,7 @@ INTERNAL WORK_TASK_FUNC_DEF(font_load_asset_task, vparams) struct temp_arena scratch = scratch_begin_no_conflict(); struct font_task_params *params = (struct font_task_params *)vparams; - struct string path = string_from_cstr_len(params->path_cstr, params->path_len); + struct string path = STRING(params->path_len, (u8 *)params->path_cstr); f32 point_size = params->point_size; struct asset *asset = params->asset; diff --git a/src/game.c b/src/game.c index c31aa112..d7bd7989 100644 --- a/src/game.c +++ b/src/game.c @@ -15,6 +15,7 @@ #include "rng.h" #include "space.h" #include "byteio.h" +#include "sock.h" GLOBAL struct { struct atomic_i32 game_thread_shutdown; @@ -64,12 +65,14 @@ INTERNAL void reset_world(void); struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr, struct sprite_startup_receipt *sheet_sr, struct sound_startup_receipt *sound_sr, - struct phys_startup_receipt *phys_sr) + struct phys_startup_receipt *phys_sr, + struct sock_startup_receipt *sock_sr) { (UNUSED)mixer_sr; (UNUSED)sheet_sr; (UNUSED)sound_sr; (UNUSED)phys_sr; + (UNUSED)sock_sr; /* Initialize game input storage */ G.game_input_mutex = sys_mutex_alloc(); @@ -459,6 +462,50 @@ INTERNAL void game_update(struct game_cmd_list game_cmds) __prof; struct temp_arena scratch = scratch_begin_no_conflict(); + + + + + + + + + + + { + static struct sock sock = ZI; + if (!sock.handle) { + struct sock_address bind_addr = ZI; + bind_addr.ip = SOCK_IP_ANY_INTERFACE; + bind_addr.port = 12345; + sock = sock_alloc(bind_addr, SOCK_FLAG_NON_BLOCKING_RECV); + } + } + + + + + + + + + + + + + + + + + + + + + + + + + /* ========================== * * Reset level if necessary diff --git a/src/game.h b/src/game.h index 05129e73..5999c6e8 100644 --- a/src/game.h +++ b/src/game.h @@ -6,6 +6,7 @@ struct mixer_startup_receipt; struct sprite_startup_receipt; struct sound_startup_receipt; struct phys_startup_receipt; +struct sock_startup_receipt; /* Absolute layers */ #define GAME_LAYER_FLOOR_DECALS -300 @@ -21,7 +22,8 @@ struct game_startup_receipt { i32 _; }; struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr, struct sprite_startup_receipt *sheet_sr, struct sound_startup_receipt *sound_sr, - struct phys_startup_receipt *phys_sr); + struct phys_startup_receipt *phys_sr, + struct sock_startup_receipt *sock_sr); /* ========================== * diff --git a/src/sock.h b/src/sock.h new file mode 100644 index 00000000..538960e4 --- /dev/null +++ b/src/sock.h @@ -0,0 +1,62 @@ +#ifndef SOCK_H +#define SOCK_H + +#define SOCK_IP_ANY_INTERFACE CPPCOMPAT_INITLIST_TYPE(struct sock_ip) { 0 } +#define SOCK_PORT_DYNAMIC (0) + +struct sock_ip { + u8 b[16]; +}; + +struct sock_address { + struct sock_ip ip; + u32 port; +}; + +struct sock { + u64 handle; +}; + +enum sock_flag { + SOCK_FLAG_NONE = (1 << 0), + SOCK_FLAG_NON_BLOCKING_RECV = (1 << 1) +}; + +/* ========================== * + * Startup + * ========================== */ + +struct sock_startup_receipt { i32 _; }; +struct sock_startup_receipt sock_startup(void); + +/* ========================== * + * Address + * ========================== */ + +b32 sock_ip_is_ipv4(struct sock_ip ip); +b32 sock_string_is_ipv4(struct string s); +struct sock_ip sock_ip_from_string(struct string s); +struct string sock_ip_to_string(struct arena *arena, struct sock_ip addr); + + +/* ========================== * + * Sock + * ========================== */ + +struct sock sock_alloc(struct sock_address addr, sock_receive_callback_func *receive_callback, u64 flags); +void sock_release(struct sock *sock); +void sock_write(struct sock *sock, struct sock_address address, struct string msg); + + + + + + + + + +void sock_testsend(void); + +void sock_testrecv(void); + +#endif diff --git a/src/sock_win32.c b/src/sock_win32.c new file mode 100644 index 00000000..bc0a0474 --- /dev/null +++ b/src/sock_win32.c @@ -0,0 +1,494 @@ +#include "sock.h" +#include "sys.h" +#include "log.h" +#include "arena.h" +#include "scratch.h" + +#include +#include + +#pragma comment(lib, "ws2_32.lib") + +#define MAX_IP_STR_LEN 46 + +INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(win32_sock_receive_entry_point, arg); + +struct win32_sock { + SOCKET socket; + struct sockaddr_in6 sa6; + + sock_receive_callback_func *receive_callback; + struct sys_thread receive_thread; + + struct win32_sock *next_free; +}; + +/* ========================== * + * Global state + * ========================== */ + +GLOBAL struct { + struct sys_mutex win32_socks_mutex; + struct arena win32_socks_arena; + struct win32_sock *first_free_win32_sock; + + WSADATA wsa_data; +} G = ZI, DEBUG_ALIAS(G, G_sock_win32); + +/* ========================== * + * Startup + * ========================== */ + +struct sock_startup_receipt sock_startup(void) +{ + G.win32_socks_mutex = sys_mutex_alloc(); + G.win32_socks_arena = arena_alloc(GIGABYTE(64)); + + /* Initialize Winsock */ + WSAStartup(MAKEWORD(2, 2), &G.wsa_data); + //WSACleanup(); + + return (struct sock_startup_receipt) { 0 }; +} + +/* ========================== * + * Address + * ========================== */ + +#if 1 + +INTERNAL struct sockaddr_in6 win32_sa6_from_sock_address(struct sock_address sa) +{ + struct sockaddr_in6 res = ZI; + res.sin6_family = AF_INET6; + res.sin6_port = htons(sa.port); + CT_ASSERT(sizeof(res.sin6_addr.s6_addr) == 16); + CT_ASSERT(sizeof(sa.ip) == 16); + + b32 is_any = true; + for (u64 i = 0; i < 16; ++i) { + u8 b = sa.ip.b[i]; + res.sin6_addr.s6_addr[i] = b; + is_any = (is_any && b == 0); + } + if (is_any) { + res.sin6_addr = in6addr_any; + } + + return res; +} + +INTERNAL struct sock_address sock_address_from_win32_sa6(struct sockaddr_in6 sa6) +{ + struct sock_address res = ZI; + CT_ASSERT(sizeof(sa6.sin6_addr.s6_addr) == 16); + CT_ASSERT(sizeof(res.ip) == 16); + MEMCPY(res.ip.b, sa6.sin6_addr.s6_addr, 16); + res.port = ntohs(sa6.sin6_port); + return res; +} + +b32 sock_ip_is_ipv4(struct sock_ip ip) +{ + return ((ip.b[0] == 0x00) && + (ip.b[1] == 0x00) && + (ip.b[2] == 0x00) && + (ip.b[3] == 0x00) && + (ip.b[4] == 0x00) && + (ip.b[5] == 0x00) && + (ip.b[6] == 0x00) && + (ip.b[7] == 0x00) && + (ip.b[8] == 0x00) && + (ip.b[9] == 0x00) && + (ip.b[10] == 0xFF) && + (ip.b[11] == 0xFF)); +} + +b32 sock_string_is_ipv4(struct string s) +{ + b32 ipv4 = true; + for (u64 i = 0; i < s.len; ++i) { + u8 c = s.text[i]; + if (c == '.') { + ipv4 = true; + break; + } else if (c == ':') { + ipv4 = false; + break; + } + } + return ipv4; +} + +struct sock_ip sock_ip_from_string(struct string s) +{ + struct temp_arena scratch = scratch_begin_no_conflict(); + char *cstr = cstr_from_string(scratch.arena, s); + + u8 buff[16] = ZI; + if (sock_string_is_ipv4(s)) { + buff[10] = 0xFF; + buff[11] = 0xFF; + inet_pton(AF_INET, cstr, buff + 12); + } else { + inet_pton(AF_INET6, cstr, buff); + } + + struct sock_ip res = ZI; + CT_ASSERT(sizeof(res.b) == sizeof(buff)); + MEMCPY(res.b, buff, sizeof(buff)); + + scratch_end(scratch); + + return res; +} + +struct string sock_ip_to_string(struct arena *arena, struct sock_ip ip) +{ + char buff[MAX_IP_STR_LEN]; + if (sock_ip_is_ipv4(ip)) { + inet_ntop(AF_INET, ip.b + 12, buff, sizeof(buff)); + } else { + inet_ntop(AF_INET6, ip.b, buff, sizeof(buff)); + } + struct string res = string_copy(arena, string_from_cstr_limit(buff, sizeof(buff))); + return res; +} + +#else + +INTERNAL struct sockaddr_in6 win32_sa6_from_sock_address(struct sock_address sa) +{ + struct sockaddr_in6 res = ZI; + res.sin6_family = AF_INET6; + res.sin6_port = htons(sa.port); + if (u128_eq(sa.ip, SOCK_IP_ANY_INTERFACE)) { + res.sin6_addr = in6addr_any; + } else { + /* TODO: store address structure in network byte order by default */ + u64 hi = U128_HI(sa.ip); + u64 lo = U128_LO(sa.ip); + u8 *dst = res.sin6_addr.s6_addr; + dst[0] = (hi >> 56) & 0xFF; + dst[1] = (hi >> 48) & 0xFF; + dst[2] = (hi >> 40) & 0xFF; + dst[3] = (hi >> 32) & 0xFF; + dst[4] = (hi >> 24) & 0xFF; + dst[5] = (hi >> 16) & 0xFF; + dst[6] = (hi >> 8) & 0xFF; + dst[7] = (hi >> 0) & 0xFF; + dst[8] = (lo >> 56) & 0xFF; + dst[9] = (lo >> 48) & 0xFF; + dst[10] = (lo >> 40) & 0xFF; + dst[11] = (lo >> 32) & 0xFF; + dst[12] = (lo >> 24) & 0xFF; + dst[13] = (lo >> 16) & 0xFF; + dst[14] = (lo >> 8) & 0xFF; + dst[15] = (lo >> 0) & 0xFF; + } + res.sin6_port = htons(12345); + return res; +} + +INTERNAL struct sock_address sock_address_from_win32_sa6(struct sockaddr_in6 sa6) +{ + struct sock_address res = ZI; + u8 *src = sa6.sin6_addr.s6_addr; + /* TODO: store address structure in network byte order by default */ + u64 hi = ((u64)src[0] << 56) | + ((u64)src[1] << 48) | + ((u64)src[2] << 40) | + ((u64)src[3] << 32) | + ((u64)src[4] << 24) | + ((u64)src[5] << 16) | + ((u64)src[6] << 8) | + ((u64)src[7] << 0); + u64 lo = ((u64)src[8] << 56) | + ((u64)src[9] << 48) | + ((u64)src[10] << 40) | + ((u64)src[11] << 32) | + ((u64)src[12] << 24) | + ((u64)src[13] << 16) | + ((u64)src[14] << 8) | + ((u64)src[15] << 0); + res.ip = U128(hi, lo); + res.port = ntohs(sa6.sin6_port); + return res; +} + +struct sock_address sock_address_from_string(struct string s) +{ + u64 hi = 0; + u64 lo = 0; + + b32 ipv4 = true; + for (u64 i = 0; i < s.len; ++i) { + u8 c = s.text[i]; + if (c == '.') { + ipv4 = true; + break; + } else if (c == ':') { + ipv4 = false; + break; + } + } + + if (ipv4) { + struct string seq = ZI; + seq.text = s.text; + + u8 byte_index = 0; + u8 byte = 0; + u8 factor = 100; + for (u32 s_index = 0; s_index < s.len; ++s_index) { + u8 c = s.text[s_index]; + if (c == '.' || s_index == (s.len - 1)) { + if (byte_index < 8) { + lo |= (byte << (byte_index * 8)); + } else { + hi |= (byte << (byte_index * 8)); + } + + byte = 0; + factor = 100; + ++byte_index; + } else { + byte += ((c + 48) * factor); + factor *= 0.1; + } + } + } else { + /* TODO */ + ASSERT(false); + } + + return U128(hi, lo); +} +#endif + +/* ========================== * + * Sock + * ========================== */ + +INTERNAL struct win32_sock *win32_sock_alloc(void) +{ + struct win32_sock *ws = NULL; + { + struct sys_lock lock = sys_mutex_lock_e(&G.win32_socks_mutex); + if (G.first_free_win32_sock) { + ws = G.first_free_win32_sock; + G.first_free_win32_sock = ws->next_free; + } else { + ws = arena_push(&G.win32_socks_arena, struct win32_sock); + } + sys_mutex_unlock(&lock); + } + MEMZERO_STRUCT(ws); + return ws; +} + +INTERNAL void win32_sock_release(struct win32_sock *ws) +{ + struct sys_lock lock = sys_mutex_lock_e(&G.win32_socks_mutex); + ws->next_free = G.first_free_win32_sock; + G.first_free_win32_sock = ws; + sys_mutex_unlock(&lock); +} + +struct sock sock_alloc(struct sock_address bind_addr, u64 flags) +{ + struct win32_sock *ws = win32_sock_alloc(); + + struct sockaddr_in6 sa6 = win32_sa6_from_sock_address(bind_addr); + + ws->socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (bind_addr.) { + /* TODO: Error checking */ + bind(ws->socket, (struct sockaddr *)&ws->sa6, sizeof(ws->sa6)); + } + + if (receive_callback) { + /* Spin up receive thread */ + ws->receive_thread = sys_thread_alloc(win32_sock_receive_entry_point, ws, LIT("[P8] Sock receive thread")); + } + + struct sock res = ZI; + res.handle = (u64)ws; + return res; +} + +void sock_release(struct sock *sock) +{ + /* TODO */ + + struct win32_sock *ws = (struct win32_sock *)sock->handle; + + //ws->shutdown_receiver + + //closesocket(ws->socket); + + win32_sock_release(ws); + +} + +struct sock_packet { + struct sock_address addr; + struct string msg; +}; + +void sock_send(struct sock *sock, struct sock_packet p) +{ + struct win32_sock *ws = (struct win32_sock *)sock->handle; + struct sockaddr_in6 sa6 = win32_sa6_from_sock_address(p.addr); + sendto(ws->socket, (char *)p.msg.text, p.msg.len, 0, (struct sockaddr *)&sa6, sizeof(sa6)); +} + +struct sock_packet sock_recv(struct sock *sock, u8 *buffer, u64 buffer_size) +{ + struct sock_packet p = ZI; + struct win32_sock *ws = (struct win32_sock *)sock->handle; + + + + + return p; +} + +/* ========================== * + * Receive thread + * ========================== */ + +INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(win32_sock_receive_entry_point, arg) +{ + struct win32_sock *ws = (struct win32_sock *)arg; + struct temp_arena scratch = scratch_begin_no_conflict(); + u64 buffer_size = KILOBYTE(64); + u8 *buffer = arena_push_array(scratch.arena, u8, buffer_size); + + struct sockaddr_in6 client_sa6 = ZI; + i32 client_sa6_size = sizeof(client_sa6); + + + + + + + + + struct sock_address dummy = ZI; + dummy.ip = sock_ip_from_string(LIT("127.0.0.1")); + dummy.port = 12345; + struct sockaddr_in6 dummy_sa6 = win32_sa6_from_sock_address(dummy); + + char dummy_msg = 0; + sendto(ws->socket, &dummy_msg, 1, 0, (struct sockaddr *)&dummy_sa6, sizeof(dummy_sa6)); + + + + + + + /* TODO: Allow thread shutdown */ + volatile b32 shutdown = false; + while (!shutdown) { + i32 msg_len = recvfrom(ws->socket, (char *)buffer, buffer_size, 0, (struct sockaddr *)&client_sa6, &client_sa6_size); + if (msg_len == SOCKET_ERROR) { + i32 err = WSAGetLastError(); + (UNUSED)err; + ASSERT(false); + } else if (msg_len > 0) { + if (ws->receive_callback) { + struct sock_address address = sock_address_from_win32_sa6(client_sa6); + ws->receive_callback(address, STRING(msg_len, buffer)); + } + } + } + + scratch_end(scratch); +} + + + + + + + + + + + + + + + + + +/* ========================== * + * Test + * ========================== */ + +void sock_testsend(void) +{ + SOCKET sock; + struct sockaddr_in serverAddr; + char *message = "Hello, UDP!"; + + /* Create socket */ + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + + /* Set up the server address struct */ + serverAddr.sin_family = AF_INET; + serverAddr.sin_port = htons(12345); /* Port */ + // serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + if (inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr) <= 0) { + sys_panic(LIT("Invalid address")); + } + + /* Send a message */ + sendto(sock, message, strlen(message), 0, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); + + /* Clean up */ + closesocket(sock); + WSACleanup(); +} + +void sock_testrecv(void) +{ + SOCKET sock; + char clientIP[INET_ADDRSTRLEN]; + struct sockaddr_in serverAddr, clientAddr; + char buffer[1024]; + int clientAddrLen = sizeof(clientAddr); + + /* Create socket */ + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + + /* Set up the server address struct */ + serverAddr.sin_family = AF_INET; + serverAddr.sin_port = htons(12345); /* Port */ + serverAddr.sin_addr.s_addr = INADDR_ANY; /* Accept any incoming address */ + + /* Bind the socket to the address */ + bind(sock, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); + + /* Receive a message */ + volatile b32 run = true; + while (run) { + int recvLen = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&clientAddr, &clientAddrLen); + if (recvLen > 0) { + buffer[recvLen] = '\0'; /* Null-terminate the received message */ + + inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, sizeof(clientIP)); + + struct string addr = string_from_cstr(clientIP); + struct string msg = STRING((u64)recvLen, (u8 *)buffer); + i32 port = ntohs(clientAddr.sin_port); + + logf_info("Received from %F:%F - %F\n", FMT_STR(addr), FMT_SINT(port), FMT_STR(msg)); + } + } + + // Clean up + closesocket(sock); + WSACleanup(); +} diff --git a/src/sound.c b/src/sound.c index 85946cce..90b1471c 100644 --- a/src/sound.c +++ b/src/sound.c @@ -86,7 +86,7 @@ INTERNAL WORK_TASK_FUNC_DEF(sound_load_asset_task, vparams) __prof; struct sound_task_params *params = (struct sound_task_params *)vparams; struct temp_arena scratch = scratch_begin_no_conflict(); - struct string path = string_from_cstr_len(params->path_cstr, params->path_len); + struct string path = STRING(params->path_len, (u8 *)params->path_cstr); struct asset *asset = params->asset; u32 flags = params->flags; diff --git a/src/sprite.c b/src/sprite.c index e72212a4..225653a9 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -782,7 +782,7 @@ INTERNAL struct cache_node *node_lookup_touch(struct sprite_scope *scope, struct struct cache_node **nonmatching_next = NULL; struct cache_node_hash hash = cache_node_hash_from_tag_hash(tag.hash, kind); - u64 cache_bucket_index = U128_LO64(hash.v) % CACHE_BUCKETS_COUNT; + u64 cache_bucket_index = U128_LO(hash.v) % CACHE_BUCKETS_COUNT; struct cache_bucket *bucket = &G.cache.buckets[cache_bucket_index]; /* Lookup */ @@ -1076,7 +1076,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg) #if RESOURCE_RELOADING /* Check if file changed for resource reloading */ if (!consider_for_eviction) { - struct string path = string_from_cstr_len((char *)n->tag_path, n->tag_path_len); + struct string path = STRING(n->tag_path_len, n->tag_path); b32 file_changed = false; struct sys_datetime current_file_time; { diff --git a/src/string.c b/src/string.c index b505a7e6..9a844b48 100644 --- a/src/string.c +++ b/src/string.c @@ -658,6 +658,21 @@ u64 cstr_len(char *cstr) return end - cstr; } +u64 cstr_len_limit(char *cstr, u64 limit) +{ + char *end = cstr; + if (cstr) { + for (u64 i = 0; i < limit; ++i) { + if (*end) { + ++end; + } else { + break; + } + } + } + return end - cstr; +} + char *cstr_from_string(struct arena *arena, struct string src) { u8 *text = arena_push_array(arena, u8, src.len + 1); @@ -685,8 +700,9 @@ struct string string_from_cstr(char *cstr) }; } -struct string string_from_cstr_len(char *cstr, u64 len) +struct string string_from_cstr_limit(char *cstr, u64 limit) { + u64 len = cstr_len_limit(cstr, limit); return (struct string) { .text = (u8 *)cstr, .len = len diff --git a/src/string.h b/src/string.h index 48c2d923..db1a7a66 100644 --- a/src/string.h +++ b/src/string.h @@ -111,10 +111,11 @@ struct string32 string32_from_string(struct arena *arena, struct string str8); * ========================== */ u64 cstr_len(char *cstr); +u64 cstr_len_limit(char *cstr, u64 limit); char *cstr_from_string(struct arena *arena, struct string src); char *cstr_buff_from_string(struct string dest_buff, struct string src); struct string string_from_cstr(char *cstr); -struct string string_from_cstr_len(char *cstr, u64 len); +struct string string_from_cstr_limit(char *cstr, u64 limit); u64 wstr_len(wchar_t *wstr); wchar_t *wstr_from_string(struct arena *arena, struct string src); diff --git a/src/sys_win32.c b/src/sys_win32.c index 5e2e8eb2..731b15f8 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -1620,49 +1620,49 @@ struct thread_local_store *sys_thread_get_thread_local_store(void) * Threads * ========================== */ -INTERNAL struct win32_thread *win32_thread_alloc_locked(struct sys_lock *lock) +INTERNAL struct win32_thread *win32_thread_alloc(void) { - sys_assert_locked_e(lock, &G.threads_mutex); - (UNUSED)lock; - struct win32_thread *t = NULL; - if (G.threads_first_free) { - t = G.threads_first_free; - G.threads_first_free = t->next; - } else { - t = arena_push(&G.threads_arena, struct win32_thread); + struct sys_lock lock = sys_mutex_lock_e(&G.threads_mutex); + { + if (G.threads_first_free) { + t = G.threads_first_free; + G.threads_first_free = t->next; + } else { + t = arena_push(&G.threads_arena, struct win32_thread); + } + MEMZERO_STRUCT(t); + if (!G.threads_first) { + G.threads_first = t; + } else { + G.threads_last->next = t; + } + t->prev = G.threads_last; + G.threads_last = t; } - MEMZERO_STRUCT(t); - if (!G.threads_first) { - G.threads_first = t; - } else { - G.threads_last->next = t; - } - t->prev = G.threads_last; - G.threads_last = t; + sys_mutex_unlock(&lock); return t; } -INTERNAL void win32_thread_release_locked(struct sys_lock *lock, struct win32_thread *t) +INTERNAL void win32_thread_release(struct win32_thread *t) { - sys_assert_locked_e(lock, &G.threads_mutex); - (UNUSED)lock; - - if (t->prev) { - t->prev->next = t->next; + struct sys_lock lock = sys_mutex_lock_e(&G.threads_mutex); + { + if (t->prev) { + t->prev->next = t->next; + } + if (t->next) { + t->next->prev = t->prev; + } + if (G.threads_first == t) { + G.threads_first = t->next; + } + if (G.threads_last == t) { + G.threads_last = t->prev; + } + t->next = G.threads_first_free; } - if (t->next) { - t->next->prev = t->prev; - } - if (G.threads_first == t) { - G.threads_first = t->next; - } - if (G.threads_last == t) { - G.threads_last = t->prev; - } - *t = (struct win32_thread) { - .next = G.threads_first_free - }; + sys_mutex_unlock(&lock); } INTERNAL DWORD WINAPI win32_thread_proc(LPVOID vt) @@ -1680,6 +1680,7 @@ INTERNAL DWORD WINAPI win32_thread_proc(LPVOID vt) /* Set thread name */ struct string thread_name = string_from_cstr(t->thread_name_cstr); if (thread_name.len > 0) { + /* FIXME: Don't use scratch arena here, to avoid scratch TLS being initialized for threads that don't need them otherwise */ struct temp_arena scratch = scratch_begin_no_conflict(); wchar_t *wc_thread_name = wstr_from_string(scratch.arena, thread_name); SetThreadDescription(GetCurrentThread(), wc_thread_name); @@ -1688,16 +1689,9 @@ INTERNAL DWORD WINAPI win32_thread_proc(LPVOID vt) logf_info("New thread \"%F\" created with ID %F", FMT_STR(thread_name), FMT_UINT(sys_thread_id())); - /* Start thread */ + /* Enter thread entry point */ t->entry_point(t->thread_data); - /* Release thread object */ - struct sys_lock lock = sys_mutex_lock_e(&G.threads_mutex); - { - win32_thread_release_locked(&lock, t); - } - sys_mutex_unlock(&lock); - /* Release TLS */ win32_tls_release(&tls); @@ -1713,51 +1707,38 @@ struct sys_thread sys_thread_alloc(sys_thread_entry_point_func *entry_point, voi logf_info("Creating thread \"%F\"", FMT_STR(thread_name)); struct sys_thread res = ZI; - struct sys_lock lock = sys_mutex_lock_e(&G.threads_mutex); - { - /* Allocate thread object */ - struct win32_thread *t = win32_thread_alloc_locked(&lock); - t->entry_point = entry_point; - t->thread_data = thread_data; - /* Copy thread name to params */ - cstr_buff_from_string(STRING_FROM_ARRAY(t->thread_name_cstr), thread_name); + /* Allocate thread object */ + struct win32_thread *t = win32_thread_alloc(); + t->entry_point = entry_point; + t->thread_data = thread_data; - t->handle = CreateThread( - NULL, - SYS_THREAD_STACK_SIZE, - win32_thread_proc, - t, - 0, - NULL - ); + /* Copy thread name to params */ + cstr_buff_from_string(STRING_FROM_ARRAY(t->thread_name_cstr), thread_name); - if (!t->handle) { - sys_panic(LIT("Failed to create thread")); - } + t->handle = CreateThread( + NULL, + SYS_THREAD_STACK_SIZE, + win32_thread_proc, + t, + 0, + NULL + ); - res.handle = (u64)t; + if (!t->handle) { + sys_panic(LIT("Failed to create thread")); } - sys_mutex_unlock(&lock); + res.handle = (u64)t; return res; } void sys_thread_wait_release(struct sys_thread *thread) { - HANDLE handle = 0; + struct win32_thread *t = (struct win32_thread *)thread->handle; + HANDLE handle = t->handle; - /* Lookup */ - struct sys_lock lock = sys_mutex_lock_s(&G.threads_mutex); - { - struct win32_thread *t = (struct win32_thread *)thread->handle; - if (t) { - handle = t->handle; - } - } - sys_mutex_unlock(&lock); - - /* Wait */ + /* Wait for thread to stop */ if (handle) { DWORD res = WaitForSingleObject(handle, INFINITE); CloseHandle(handle); @@ -1765,6 +1746,9 @@ void sys_thread_wait_release(struct sys_thread *thread) ASSERT(res != WAIT_FAILED); (UNUSED)res; } + + /* Release thread struct */ + win32_thread_release(t); } u32 sys_thread_id(void) diff --git a/src/user.c b/src/user.c index 28908a7b..84a7b904 100644 --- a/src/user.c +++ b/src/user.c @@ -19,6 +19,7 @@ #include "collider.h" #include "rng.h" #include "log.h" +#include "sock.h" struct bind_state { b32 is_held; /* Is this bind held down this frame */ @@ -136,6 +137,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr, struct game_startup_receipt *game_sr, struct asset_cache_startup_receipt *asset_cache_sr, struct mixer_startup_receipt *mixer_sr, + struct sock_startup_receipt *sock_sr, struct sys_window *window) { (UNUSED)work_sr; @@ -146,6 +148,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr, (UNUSED)game_sr; (UNUSED)asset_cache_sr; (UNUSED)mixer_sr; + (UNUSED)sock_sr; G.arena = arena_alloc(GIGABYTE(64)); G.sys_events_mutex = sys_mutex_alloc(); @@ -468,6 +471,40 @@ INTERNAL void user_update(void) { struct temp_arena scratch = scratch_begin_no_conflict(); + + + + + + + + + + + + + + + { + static struct sock sock = ZI; + if (!sock.handle) { + struct sock_address bind_addr = ZI; + bind_addr.ip = SOCK_IP_ANY_INTERFACE; + bind_addr.port = SOCK_PORT_DYNAMIC; /* Dynamic port */ + sock = sock_alloc(bind_addr, SOCK_FLAG_NON_BLOCKING_RECV); + } + } + + + + + + + + + + + /* ========================== * * Begin frame * ========================== */ diff --git a/src/user.h b/src/user.h index 74bb2a29..08aa9ead 100644 --- a/src/user.h +++ b/src/user.h @@ -10,6 +10,7 @@ struct draw_startup_receipt; struct game_startup_receipt; struct asset_cache_startup_receipt; struct mixer_startup_receipt; +struct sock_startup_receipt; enum user_bind_kind { USER_BIND_KIND_NONE, @@ -56,6 +57,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr, struct game_startup_receipt *game_sr, struct asset_cache_startup_receipt *asset_cache_sr, struct mixer_startup_receipt *mixer_sr, + struct sock_startup_receipt *sock_sr, struct sys_window *window); #endif