buddy progress
This commit is contained in:
parent
6f7c19e053
commit
78ace4b38a
@ -51,7 +51,7 @@ void arena_release(struct arena *arena)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: Application will exit if arena fails to commit memory */
|
/* NOTE: Application will exit if arena fails to commit memory */
|
||||||
void *_arena_push_bytes(struct arena *arena, u64 size, u64 align)
|
void *arena_push_bytes(struct arena *arena, u64 size, u64 align)
|
||||||
{
|
{
|
||||||
ASSERT(align > 0);
|
ASSERT(align > 0);
|
||||||
ASSERT(!arena->readonly);
|
ASSERT(!arena->readonly);
|
||||||
@ -101,7 +101,7 @@ void arena_copy_replace(struct arena *dest, struct arena *src)
|
|||||||
arena_reset(dest);
|
arena_reset(dest);
|
||||||
u64 data_size = src->pos;
|
u64 data_size = src->pos;
|
||||||
u8 *data_src = src->base;
|
u8 *data_src = src->base;
|
||||||
u8 *data_dest = _arena_push_bytes(dest, data_size, 1);
|
u8 *data_dest = arena_push_bytes(dest, data_size, 1);
|
||||||
MEMCPY(data_dest, data_src, data_size);
|
MEMCPY(data_dest, data_src, data_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
24
src/arena.h
24
src/arena.h
@ -3,21 +3,19 @@
|
|||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
#define arena_push(a, type) ((type *)_arena_push_bytes((a), sizeof(type), alignof(type)))
|
#define arena_push(a, type) ((type *)arena_push_bytes((a), sizeof(type), alignof(type)))
|
||||||
#define arena_push_zero(a, type) ((type *)_arena_push_bytes_zero((a), sizeof(type), alignof(type)))
|
#define arena_push_zero(a, type) ((type *)arena_push_bytes_zero((a), sizeof(type), alignof(type)))
|
||||||
|
|
||||||
#define arena_push_array(a, type, n) ((type *)_arena_push_bytes((a), (sizeof(type) * (n)), alignof(type)))
|
#define arena_push_array(a, type, n) ((type *)arena_push_bytes((a), (sizeof(type) * (n)), alignof(type)))
|
||||||
#define arena_push_array_zero(a, type, n) ((type *)_arena_push_bytes_zero((a), (sizeof(type) * (n)), alignof(type)))
|
#define arena_push_array_zero(a, type, n) ((type *)arena_push_bytes_zero((a), (sizeof(type) * (n)), alignof(type)))
|
||||||
|
|
||||||
#define arena_pop(a, type, dest) _arena_pop_struct((a), sizeof(type), dest)
|
#define arena_pop(a, type, dest) arena_pop_struct((a), sizeof(type), dest)
|
||||||
#define arena_pop_array(a, type, n, dest) _arena_pop_struct((a), sizeof(type) * (n), dest)
|
#define arena_pop_array(a, type, n, dest) arena_pop_struct((a), sizeof(type) * (n), dest)
|
||||||
|
|
||||||
/* Returns a pointer to where the next allocation would be (at alignment of type).
|
/* Returns a pointer to where the next allocation would be (at alignment of type).
|
||||||
* Equivalent arena_push but without actually allocating anything. */
|
* Equivalent arena_push but without actually allocating anything. */
|
||||||
#define arena_dry_push(a, type) (type *)(_arena_dry_push((a), alignof(type)))
|
#define arena_dry_push(a, type) (type *)(_arena_dry_push((a), alignof(type)))
|
||||||
|
|
||||||
#define arena_align(a, align) (void *)(_arena_align((a), align))
|
|
||||||
|
|
||||||
struct temp_arena {
|
struct temp_arena {
|
||||||
struct arena *arena;
|
struct arena *arena;
|
||||||
u64 start_pos;
|
u64 start_pos;
|
||||||
@ -29,15 +27,15 @@ struct temp_arena {
|
|||||||
|
|
||||||
struct arena arena_alloc(u64 reserve);
|
struct arena arena_alloc(u64 reserve);
|
||||||
void arena_release(struct arena *arena);
|
void arena_release(struct arena *arena);
|
||||||
void *_arena_push_bytes(struct arena *arena, u64 size, u64 align);
|
void *arena_push_bytes(struct arena *arena, u64 size, u64 align);
|
||||||
void arena_copy_replace(struct arena *dest, struct arena *src);
|
void arena_copy_replace(struct arena *dest, struct arena *src);
|
||||||
void arena_decommit_unused_blocks(struct arena *arena);
|
void arena_decommit_unused_blocks(struct arena *arena);
|
||||||
void arena_set_readonly(struct arena *arena);
|
void arena_set_readonly(struct arena *arena);
|
||||||
void arena_set_readwrite(struct arena *arena);
|
void arena_set_readwrite(struct arena *arena);
|
||||||
|
|
||||||
INLINE void *_arena_push_bytes_zero(struct arena *arena, u64 size, u64 align)
|
INLINE void *arena_push_bytes_zero(struct arena *arena, u64 size, u64 align)
|
||||||
{
|
{
|
||||||
void *p = _arena_push_bytes(arena, size, align);
|
void *p = arena_push_bytes(arena, size, align);
|
||||||
MEMZERO(p, size);
|
MEMZERO(p, size);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -51,7 +49,7 @@ INLINE void arena_pop_to(struct arena *arena, u64 pos)
|
|||||||
arena->pos = pos;
|
arena->pos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE void _arena_pop_struct(struct arena *arena, u64 size, void *copy_dest)
|
INLINE void arena_pop_struct(struct arena *arena, u64 size, void *copy_dest)
|
||||||
{
|
{
|
||||||
ASSERT(arena->pos >= size);
|
ASSERT(arena->pos >= size);
|
||||||
ASSERT(!arena->readonly);
|
ASSERT(!arena->readonly);
|
||||||
@ -64,7 +62,7 @@ INLINE void _arena_pop_struct(struct arena *arena, u64 size, void *copy_dest)
|
|||||||
arena->pos = new_pos;
|
arena->pos = new_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE void *_arena_align(struct arena *arena, u64 align)
|
INLINE void *arena_align(struct arena *arena, u64 align)
|
||||||
{
|
{
|
||||||
ASSERT(!arena->readonly);
|
ASSERT(!arena->readonly);
|
||||||
|
|
||||||
|
|||||||
200
src/buddy.c
Normal file
200
src/buddy.c
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
#include "buddy.h"
|
||||||
|
#include "arena.h"
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Ctx
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct buddy_ctx *buddy_ctx_alloc(u64 reserve)
|
||||||
|
{
|
||||||
|
/* TODO: Determine meta reserve dynamically */
|
||||||
|
struct arena meta_arena = arena_alloc(GIGABYTE(64));
|
||||||
|
struct buddy_ctx *ctx = arena_push_zero(&meta_arena, struct buddy_ctx);
|
||||||
|
ctx->meta_arena = meta_arena;
|
||||||
|
ctx->data_arena = arena_alloc(reserve);
|
||||||
|
|
||||||
|
/* TODO: Minimum block size */
|
||||||
|
ctx->levels = arena_push_array_zero(&ctx->meta_arena, struct buddy_level, 64);
|
||||||
|
for (u64 i = 0; i < 64; ++i) {
|
||||||
|
struct buddy_level *level = &ctx->levels[i];
|
||||||
|
level->ctx = ctx;
|
||||||
|
level->tier = i;
|
||||||
|
level->size = (u64)1 << i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void buddy_ctx_release(struct buddy_ctx *ctx)
|
||||||
|
{
|
||||||
|
arena_release(&ctx->data_arena);
|
||||||
|
arena_release(&ctx->meta_arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Block
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
INTERNAL struct buddy_block *buddy_block_alloc_internal(struct buddy_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct buddy_block *block;
|
||||||
|
if (ctx->first_free_block) {
|
||||||
|
block = ctx->first_free_block;
|
||||||
|
ctx->first_free_block = block->next;
|
||||||
|
} else {
|
||||||
|
block = arena_push(&ctx->meta_arena, struct buddy_block);
|
||||||
|
}
|
||||||
|
MEMZERO_STRUCT(block);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
INTERNAL void buddy_block_release_internal(struct buddy_ctx *ctx, struct buddy_level *level, struct buddy_block *block)
|
||||||
|
{
|
||||||
|
/* Remove from unused list */
|
||||||
|
{
|
||||||
|
struct buddy_block *prev = block->prev;
|
||||||
|
struct buddy_block *next = block->next;
|
||||||
|
if (prev) {
|
||||||
|
prev->next = next;
|
||||||
|
} else {
|
||||||
|
level->first_unused_block = next;
|
||||||
|
}
|
||||||
|
if (next) {
|
||||||
|
next->prev = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
block->next = ctx->first_free_block;
|
||||||
|
ctx->first_free_block = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
INTERNAL struct buddy_block *buddy_block_get_unused(struct buddy_ctx *ctx, struct buddy_level *level)
|
||||||
|
{
|
||||||
|
struct buddy_block *block = NULL;
|
||||||
|
|
||||||
|
/* TODO: Tier oob check */
|
||||||
|
if (level->first_unused_block) {
|
||||||
|
block = level->first_unused_block;
|
||||||
|
level->first_unused_block = block->next;
|
||||||
|
if (level->first_unused_block) {
|
||||||
|
level->first_unused_block->prev = NULL;
|
||||||
|
}
|
||||||
|
block->used = true;
|
||||||
|
block->next = NULL;
|
||||||
|
ASSERT(block->memory);
|
||||||
|
} else {
|
||||||
|
if (level->backed) {
|
||||||
|
struct buddy_level *parent_level = &ctx->levels[level->tier + 1];
|
||||||
|
struct buddy_block *parent_block = buddy_block_get_unused(ctx, parent_level);
|
||||||
|
ASSERT(parent_block->memory);
|
||||||
|
|
||||||
|
/* Create left block from parent block */
|
||||||
|
struct buddy_block *left = buddy_block_alloc_internal(ctx);
|
||||||
|
left->used = true;
|
||||||
|
left->level = level;
|
||||||
|
left->parent = parent_block;
|
||||||
|
left->memory = parent_block->memory;
|
||||||
|
|
||||||
|
/* Create right (unused) block from parent block */
|
||||||
|
struct buddy_block *right = buddy_block_alloc_internal(ctx);
|
||||||
|
right->used = false;
|
||||||
|
right->level = level;
|
||||||
|
right->parent = parent_block;
|
||||||
|
right->memory = left->memory + level->size;
|
||||||
|
if (level->first_unused_block) {
|
||||||
|
right->next = level->first_unused_block;
|
||||||
|
level->first_unused_block->prev = right;
|
||||||
|
}
|
||||||
|
level->first_unused_block = right;
|
||||||
|
|
||||||
|
left->sibling = right;
|
||||||
|
right->sibling = left;
|
||||||
|
block = left;
|
||||||
|
ASSERT(block->memory);
|
||||||
|
} else {
|
||||||
|
#if 0
|
||||||
|
/* Create left block from arena */
|
||||||
|
struct buddy_block *left = buddy_block_alloc_internal(ctx);
|
||||||
|
left->used = true;
|
||||||
|
left->level = level;
|
||||||
|
left->memory = arena_push_array(&ctx->data_arena, u8, level->size * 2);
|
||||||
|
|
||||||
|
/* Create right (unused) block from arena */
|
||||||
|
struct buddy_block *right = buddy_block_alloc_internal(ctx);
|
||||||
|
right->used = false;
|
||||||
|
right->level = level;
|
||||||
|
right->memory = left->memory + level->size;
|
||||||
|
if (level->first_unused_block) {
|
||||||
|
right->next = level->first_unused_block;
|
||||||
|
level->first_unused_block->prev = right;
|
||||||
|
}
|
||||||
|
level->first_unused_block = right;
|
||||||
|
|
||||||
|
left->sibling = right;
|
||||||
|
right->sibling = left;
|
||||||
|
block = left;
|
||||||
|
|
||||||
|
level->backed = true;
|
||||||
|
ASSERT(block->memory);
|
||||||
|
#else
|
||||||
|
/* Create block by growing arena */
|
||||||
|
block = buddy_block_alloc_internal(ctx);
|
||||||
|
block->used = true;
|
||||||
|
block->memory = arena_push_array(&ctx->data_arena, u8, level->size);
|
||||||
|
block->level = level;
|
||||||
|
level->backed = true;
|
||||||
|
ASSERT(block->memory);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(block->memory);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
INTERNAL void buddy_block_mark_unused(struct buddy_block *block)
|
||||||
|
{
|
||||||
|
block->used = false;
|
||||||
|
struct buddy_block *sibling = block->sibling;
|
||||||
|
struct buddy_level *level = block->level;
|
||||||
|
if (sibling && !sibling->used) {
|
||||||
|
/* Merge siblings */
|
||||||
|
struct buddy_ctx *ctx = level->ctx;
|
||||||
|
struct buddy_block *parent = block->parent;
|
||||||
|
buddy_block_release_internal(ctx, level, block);
|
||||||
|
buddy_block_release_internal(ctx, level, sibling);
|
||||||
|
if (parent) {
|
||||||
|
buddy_block_mark_unused(parent);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (level->first_unused_block) {
|
||||||
|
block->next = level->first_unused_block;
|
||||||
|
level->first_unused_block->prev = block;
|
||||||
|
}
|
||||||
|
level->first_unused_block = block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct buddy_block *buddy_alloc(struct buddy_ctx *ctx, u64 size)
|
||||||
|
{
|
||||||
|
if (size > 0x00FFFFFFFFFFFFFFULL) {
|
||||||
|
/* TODO: Error */
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 desired_block_size = 1;
|
||||||
|
u64 desired_level_tier = 0;
|
||||||
|
while (desired_block_size < size && desired_level_tier < 64) {
|
||||||
|
desired_block_size <<= 1;
|
||||||
|
++desired_level_tier;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct buddy_block *block = buddy_block_get_unused(ctx, &ctx->levels[desired_level_tier]);
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
void buddy_release(struct buddy_block *block)
|
||||||
|
{
|
||||||
|
buddy_block_mark_unused(block);
|
||||||
|
}
|
||||||
38
src/buddy.h
Normal file
38
src/buddy.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef BUDDY_H
|
||||||
|
#define BUDDY_H
|
||||||
|
|
||||||
|
struct buddy_block {
|
||||||
|
b32 used;
|
||||||
|
struct buddy_level *level;
|
||||||
|
struct buddy_block *parent;
|
||||||
|
struct buddy_block *sibling;
|
||||||
|
|
||||||
|
/* Links to block in level's unused list or in ctx's free list */
|
||||||
|
struct buddy_block *prev;
|
||||||
|
struct buddy_block *next;
|
||||||
|
|
||||||
|
u8 *memory;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct buddy_level {
|
||||||
|
struct buddy_ctx *ctx;
|
||||||
|
b32 backed; /* Is this level backed by memory in the ctx arena */
|
||||||
|
u32 tier;
|
||||||
|
u64 size;
|
||||||
|
struct buddy_block *first_unused_block;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct buddy_ctx {
|
||||||
|
struct arena meta_arena;
|
||||||
|
struct arena data_arena;
|
||||||
|
struct buddy_level *levels;
|
||||||
|
struct buddy_block *first_free_block;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct buddy_ctx *buddy_ctx_alloc(u64 reserve);
|
||||||
|
void buddy_ctx_release(struct buddy_ctx *ctx);
|
||||||
|
|
||||||
|
struct buddy_block *buddy_alloc(struct buddy_ctx *ctx, u64 size);
|
||||||
|
void buddy_release(struct buddy_block *block);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1327,7 +1327,7 @@ INTERNAL void game_update(void)
|
|||||||
l.last = &snapshot_event;
|
l.last = &snapshot_event;
|
||||||
struct string msg = game_string_from_events(temp.arena, l);
|
struct string msg = game_string_from_events(temp.arena, l);
|
||||||
|
|
||||||
host_queue_write(G.host, HOST_CHANNEL_ID_ALL, msg);
|
host_queue_write(G.host, HOST_CHANNEL_ID_ALL, msg, 0);
|
||||||
|
|
||||||
arena_temp_end(temp);
|
arena_temp_end(temp);
|
||||||
}
|
}
|
||||||
|
|||||||
62
src/host.c
62
src/host.c
@ -5,6 +5,7 @@
|
|||||||
#include "sys.h"
|
#include "sys.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "buddy.h"
|
||||||
|
|
||||||
//#define HOST_NETWORK_ADDRESS_STRING(str)
|
//#define HOST_NETWORK_ADDRESS_STRING(str)
|
||||||
//#define HOST_NETWORK_ADDRESS_ALL_LOCAL_INTERFACES(port)
|
//#define HOST_NETWORK_ADDRESS_ALL_LOCAL_INTERFACES(port)
|
||||||
@ -104,13 +105,9 @@ struct host_recv_buffer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct host_msg_assembler {
|
struct host_msg_assembler {
|
||||||
struct host *host;
|
|
||||||
struct host_channel *channel;
|
struct host_channel *channel;
|
||||||
b32 is_reliable;
|
b32 is_reliable;
|
||||||
|
|
||||||
/* TODO: Remove this (testing) */
|
|
||||||
struct arena testarena;
|
|
||||||
|
|
||||||
/* Free list */
|
/* Free list */
|
||||||
struct host_msg_assembler *next_free;
|
struct host_msg_assembler *next_free;
|
||||||
|
|
||||||
@ -131,8 +128,9 @@ struct host_msg_assembler {
|
|||||||
|
|
||||||
i64 touched_ns;
|
i64 touched_ns;
|
||||||
|
|
||||||
u8 *chunks_received_bitmap;
|
struct buddy_block *buddy_block;
|
||||||
u8 *data;
|
u8 *chunk_bitmap;
|
||||||
|
u8 *chunk_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct host_msg_assembler_lookup_bucket {
|
struct host_msg_assembler_lookup_bucket {
|
||||||
@ -173,6 +171,11 @@ struct host *host_alloc(u16 listen_port)
|
|||||||
host->cmd_arena = arena_alloc(GIGABYTE(64));
|
host->cmd_arena = arena_alloc(GIGABYTE(64));
|
||||||
host->queued_event_arena = arena_alloc(GIGABYTE(64));
|
host->queued_event_arena = arena_alloc(GIGABYTE(64));
|
||||||
host->channel_arena = arena_alloc(GIGABYTE(64));
|
host->channel_arena = arena_alloc(GIGABYTE(64));
|
||||||
|
host->recv_buffer_read = arena_push_zero(&host->arena, struct host_recv_buffer);
|
||||||
|
host->recv_buffer_write = arena_push_zero(&host->arena, struct host_recv_buffer);
|
||||||
|
host->recv_buffer_read->arena = arena_alloc(GIGABYTE(64));
|
||||||
|
host->recv_buffer_write->arena = arena_alloc(GIGABYTE(64));
|
||||||
|
host->buddy = buddy_ctx_alloc(GIGABYTE(64));
|
||||||
|
|
||||||
host->channels = arena_dry_push(&host->channel_arena, struct host_channel);
|
host->channels = arena_dry_push(&host->channel_arena, struct host_channel);
|
||||||
|
|
||||||
@ -182,12 +185,6 @@ struct host *host_alloc(u16 listen_port)
|
|||||||
host->num_msg_assembler_lookup_buckets = NUM_MSG_ASSEMBLER_LOOKUP_BUCKETS;
|
host->num_msg_assembler_lookup_buckets = NUM_MSG_ASSEMBLER_LOOKUP_BUCKETS;
|
||||||
host->msg_assembler_lookup_buckets = arena_push_array_zero(&host->arena, struct host_msg_assembler_lookup_bucket, host->num_msg_assembler_lookup_buckets);
|
host->msg_assembler_lookup_buckets = arena_push_array_zero(&host->arena, struct host_msg_assembler_lookup_bucket, host->num_msg_assembler_lookup_buckets);
|
||||||
|
|
||||||
|
|
||||||
host->recv_buffer_read = arena_push_zero(&host->arena, struct host_recv_buffer);
|
|
||||||
host->recv_buffer_write = arena_push_zero(&host->arena, struct host_recv_buffer);
|
|
||||||
host->recv_buffer_read->arena = arena_alloc(GIGABYTE(64));
|
|
||||||
host->recv_buffer_write->arena = arena_alloc(GIGABYTE(64));
|
|
||||||
|
|
||||||
host->sock = sock_alloc(listen_port);
|
host->sock = sock_alloc(listen_port);
|
||||||
|
|
||||||
host->recv_buffer_write_mutex = sys_mutex_alloc();
|
host->recv_buffer_write_mutex = sys_mutex_alloc();
|
||||||
@ -205,6 +202,7 @@ void host_release(struct host *host)
|
|||||||
|
|
||||||
sock_release(host->sock);
|
sock_release(host->sock);
|
||||||
|
|
||||||
|
buddy_ctx_release(host->buddy);
|
||||||
arena_release(&host->recv_buffer_write->arena);
|
arena_release(&host->recv_buffer_write->arena);
|
||||||
arena_release(&host->recv_buffer_read->arena);
|
arena_release(&host->recv_buffer_read->arena);
|
||||||
arena_release(&host->channel_arena);
|
arena_release(&host->channel_arena);
|
||||||
@ -390,19 +388,27 @@ INTERNAL struct host_msg_assembler *host_msg_assembler_alloc(struct host_channel
|
|||||||
ma = arena_push(&host->arena, struct host_msg_assembler);
|
ma = arena_push(&host->arena, struct host_msg_assembler);
|
||||||
}
|
}
|
||||||
MEMZERO_STRUCT(ma);
|
MEMZERO_STRUCT(ma);
|
||||||
ma->host = channel->host;
|
|
||||||
ma->channel = channel;
|
ma->channel = channel;
|
||||||
ma->msg_id = msg_id;
|
ma->msg_id = msg_id;
|
||||||
|
|
||||||
ma->num_chunks_total = chunk_count;
|
ma->num_chunks_total = chunk_count;
|
||||||
|
|
||||||
/* FIXME: Use buddy allocator or something */
|
u64 chunk_bitmap_size = ((chunk_count - 1) / 8) + 1;
|
||||||
u64 data_size = chunk_count * PACKET_MSG_CHUNK_MAX_LEN;
|
if ((chunk_bitmap_size % 16) != 0) {
|
||||||
u64 bitmap_size = ((chunk_count - 1) / 8) + 1;
|
/* Align chunk bitmap to 16 so msg data is aligned */
|
||||||
ma->testarena = arena_alloc(data_size + bitmap_size);
|
chunk_bitmap_size += 16 - (chunk_bitmap_size % 16);
|
||||||
|
}
|
||||||
|
u64 chunk_data_size = chunk_count * PACKET_MSG_CHUNK_MAX_LEN;
|
||||||
|
|
||||||
|
/* Allocate msg data using buddy allocator since the assembler has
|
||||||
|
* arbitrary lifetime and data needs to stay contiguous for random
|
||||||
|
* access as packets are received */
|
||||||
|
ma->buddy_block = buddy_alloc(host->buddy, chunk_bitmap_size + chunk_data_size);
|
||||||
|
ma->chunk_bitmap = ma->buddy_block->memory;
|
||||||
|
MEMZERO(ma->chunk_bitmap, chunk_bitmap_size);
|
||||||
|
ma->chunk_data = ma->chunk_bitmap + chunk_bitmap_size;
|
||||||
|
|
||||||
/* FIXME: Ensure chunk_count > 0 */
|
/* FIXME: Ensure chunk_count > 0 */
|
||||||
ma->chunks_received_bitmap = arena_push_array_zero(&ma->testarena, u8, bitmap_size);
|
|
||||||
ma->data = arena_push_array(&ma->testarena, u8, data_size);
|
|
||||||
ma->is_reliable = is_reliable;
|
ma->is_reliable = is_reliable;
|
||||||
|
|
||||||
/* Insert into channel list */
|
/* Insert into channel list */
|
||||||
@ -432,11 +438,9 @@ INTERNAL struct host_msg_assembler *host_msg_assembler_alloc(struct host_channel
|
|||||||
|
|
||||||
INTERNAL void host_msg_assembler_release(struct host_msg_assembler *ma)
|
INTERNAL void host_msg_assembler_release(struct host_msg_assembler *ma)
|
||||||
{
|
{
|
||||||
struct host *host = ma->host;
|
|
||||||
struct host_channel *channel = ma->channel;
|
struct host_channel *channel = ma->channel;
|
||||||
|
struct host *host = channel->host;
|
||||||
/* FIXME: Data should be in buddy allocator or something */
|
buddy_release(ma->buddy_block);
|
||||||
arena_release(&ma->testarena);
|
|
||||||
|
|
||||||
/* Release from channel list */
|
/* Release from channel list */
|
||||||
{
|
{
|
||||||
@ -471,7 +475,6 @@ INTERNAL void host_msg_assembler_release(struct host_msg_assembler *ma)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ma->next_free = host->first_free_msg_assembler;
|
ma->next_free = host->first_free_msg_assembler;
|
||||||
host->first_free_msg_assembler = ma;
|
host->first_free_msg_assembler = ma;
|
||||||
}
|
}
|
||||||
@ -513,7 +516,7 @@ INTERNAL void host_msg_assembler_touch(struct host_msg_assembler *ma, i64 now_ns
|
|||||||
INTERNAL b32 host_msg_assembler_is_chunk_filled(struct host_msg_assembler *ma, u64 chunk_id)
|
INTERNAL b32 host_msg_assembler_is_chunk_filled(struct host_msg_assembler *ma, u64 chunk_id)
|
||||||
{
|
{
|
||||||
if (chunk_id < ma->num_chunks_total) {
|
if (chunk_id < ma->num_chunks_total) {
|
||||||
return (ma->chunks_received_bitmap[chunk_id / 8] & (1 << (chunk_id % 8))) != 0;
|
return (ma->chunk_bitmap[chunk_id / 8] & (1 << (chunk_id % 8))) != 0;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -521,7 +524,7 @@ INTERNAL b32 host_msg_assembler_is_chunk_filled(struct host_msg_assembler *ma, u
|
|||||||
INTERNAL void host_msg_assembler_set_chunk_received(struct host_msg_assembler *ma, u64 chunk_id)
|
INTERNAL void host_msg_assembler_set_chunk_received(struct host_msg_assembler *ma, u64 chunk_id)
|
||||||
{
|
{
|
||||||
if (chunk_id < ma->num_chunks_total) {
|
if (chunk_id < ma->num_chunks_total) {
|
||||||
ma->chunks_received_bitmap[chunk_id / 8] |= (1 << (chunk_id % 8));
|
ma->chunk_bitmap[chunk_id / 8] |= (1 << (chunk_id % 8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -593,12 +596,13 @@ void host_queue_disconnect(struct host *host, struct host_channel_id channel_id)
|
|||||||
cmd->channel_id = channel_id;
|
cmd->channel_id = channel_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void host_queue_write(struct host *host, struct host_channel_id channel_id, struct string msg)
|
void host_queue_write(struct host *host, struct host_channel_id channel_id, struct string msg, u32 flags)
|
||||||
{
|
{
|
||||||
struct host_cmd *cmd = host_cmd_alloc_and_append(host);
|
struct host_cmd *cmd = host_cmd_alloc_and_append(host);
|
||||||
cmd->kind = HOST_CMD_KIND_WRITE;
|
cmd->kind = HOST_CMD_KIND_WRITE;
|
||||||
cmd->channel_id = channel_id;
|
cmd->channel_id = channel_id;
|
||||||
cmd->write_msg = string_copy(&host->cmd_arena, msg);
|
cmd->write_msg = string_copy(&host->cmd_arena, msg);
|
||||||
|
cmd->write_reliable = flags & HOST_WRITE_FLAG_RELIABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -728,7 +732,7 @@ void host_update(struct host *host)
|
|||||||
if (!host_msg_assembler_is_chunk_filled(ma, chunk_id)) {
|
if (!host_msg_assembler_is_chunk_filled(ma, chunk_id)) {
|
||||||
u8 *src = br_seek(&br, data_len);
|
u8 *src = br_seek(&br, data_len);
|
||||||
if (src) {
|
if (src) {
|
||||||
u8 *dst = &ma->data[chunk_id * PACKET_MSG_CHUNK_MAX_LEN];
|
u8 *dst = &ma->chunk_data[chunk_id * PACKET_MSG_CHUNK_MAX_LEN];
|
||||||
MEMCPY(dst, src, data_len);
|
MEMCPY(dst, src, data_len);
|
||||||
if (is_last_chunk) {
|
if (is_last_chunk) {
|
||||||
ma->last_chunk_len = data_len;
|
ma->last_chunk_len = data_len;
|
||||||
@ -743,7 +747,7 @@ void host_update(struct host *host)
|
|||||||
struct string data = ZI;
|
struct string data = ZI;
|
||||||
data.len = ((chunk_count - 1) * PACKET_MSG_CHUNK_MAX_LEN) + ma->last_chunk_len;
|
data.len = ((chunk_count - 1) * PACKET_MSG_CHUNK_MAX_LEN) + ma->last_chunk_len;
|
||||||
data.text = arena_push_array(&host->queued_event_arena, u8, data.len);
|
data.text = arena_push_array(&host->queued_event_arena, u8, data.len);
|
||||||
MEMCPY(data.text, ma->data, data.len);
|
MEMCPY(data.text, ma->chunk_data, data.len);
|
||||||
queued_event->event.kind = HOST_EVENT_KIND_MSG;
|
queued_event->event.kind = HOST_EVENT_KIND_MSG;
|
||||||
queued_event->event.msg = data;
|
queued_event->event.msg = data;
|
||||||
queued_event->event.channel_id = channel->id;
|
queued_event->event.channel_id = channel->id;
|
||||||
|
|||||||
11
src/host.h
11
src/host.h
@ -7,6 +7,7 @@
|
|||||||
#define HOST_CHANNEL_ID_NIL (struct host_channel_id) { .gen = 0, .idx = 0 }
|
#define HOST_CHANNEL_ID_NIL (struct host_channel_id) { .gen = 0, .idx = 0 }
|
||||||
#define HOST_CHANNEL_ID_ALL (struct host_channel_id) { .gen = U32_MAX, .idx = U32_MAX }
|
#define HOST_CHANNEL_ID_ALL (struct host_channel_id) { .gen = U32_MAX, .idx = U32_MAX }
|
||||||
|
|
||||||
|
struct buddy_ctx;
|
||||||
struct host_packet;
|
struct host_packet;
|
||||||
struct host_channel_lookup_bucket;
|
struct host_channel_lookup_bucket;
|
||||||
struct host_recv_buffer;
|
struct host_recv_buffer;
|
||||||
@ -28,6 +29,12 @@ enum host_event_kind {
|
|||||||
HOST_EVENT_KIND_MSG
|
HOST_EVENT_KIND_MSG
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum host_write_flag {
|
||||||
|
HOST_WRITE_FLAG_NONE = 0,
|
||||||
|
|
||||||
|
HOST_WRITE_FLAG_RELIABLE = (1 << 0)
|
||||||
|
};
|
||||||
|
|
||||||
struct host_cmd {
|
struct host_cmd {
|
||||||
enum host_cmd_kind kind;
|
enum host_cmd_kind kind;
|
||||||
struct host_channel_id channel_id;
|
struct host_channel_id channel_id;
|
||||||
@ -53,6 +60,8 @@ struct host {
|
|||||||
struct arena arena;
|
struct arena arena;
|
||||||
struct sock *sock;
|
struct sock *sock;
|
||||||
|
|
||||||
|
struct buddy_ctx *buddy; /* For storing msg assembler data */
|
||||||
|
|
||||||
struct arena cmd_arena;
|
struct arena cmd_arena;
|
||||||
struct host_cmd *first_cmd;
|
struct host_cmd *first_cmd;
|
||||||
struct host_cmd *last_cmd;
|
struct host_cmd *last_cmd;
|
||||||
@ -108,7 +117,7 @@ void host_queue_connect_to_address(struct host *host, struct sock_address connec
|
|||||||
|
|
||||||
void host_queue_disconnect(struct host *host, struct host_channel_id channel_id);
|
void host_queue_disconnect(struct host *host, struct host_channel_id channel_id);
|
||||||
|
|
||||||
void host_queue_write(struct host *host, struct host_channel_id channel_id, struct string msg);
|
void host_queue_write(struct host *host, struct host_channel_id channel_id, struct string msg, u32 flags);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Update
|
* Update
|
||||||
|
|||||||
@ -1668,7 +1668,7 @@ INTERNAL void user_update(void)
|
|||||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||||
|
|
||||||
struct string cmds_str = game_string_from_cmds(temp.arena, cmd_list);
|
struct string cmds_str = game_string_from_cmds(temp.arena, cmd_list);
|
||||||
host_queue_write(G.host, HOST_CHANNEL_ID_ALL, cmds_str);
|
host_queue_write(G.host, HOST_CHANNEL_ID_ALL, cmds_str, 0);
|
||||||
|
|
||||||
arena_temp_end(temp);
|
arena_temp_end(temp);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user