srt, work_queue, mutex

This commit is contained in:
Krzosa Karol
2025-07-27 16:35:15 +02:00
parent 6724814440
commit 869af3f6dd
9 changed files with 236 additions and 6 deletions

View File

@@ -15,6 +15,7 @@ struct thread_ctx_t {
void *te_ctx;
logger_t log;
int thread_index;
};
typedef enum {

View File

@@ -27,7 +27,7 @@ fn void log_basef(log_level_t level, s8_t file_and_line, const char *str, ...);
#if PLATFORM_DEBUG_ASSERT
#define assert_expr(x) (!(x) && (os_error_box(FILE_AND_LINE ": assertion failed: " #x "\n"), debug_break()))
#define assert(x) do { static int once = 1; for (;once;once=0) assert_expr(x); } while(0)
#define assert(x) do { assert_expr(x); } while(0)
#else
#define assert_expr(x) (void)(x)
#define assert(x) do { (void)(x); } while(0)

View File

@@ -429,7 +429,14 @@ fn sb8_t s8_split(ma_arena_t *ma, s8_t string, s8_t find, s8_split_t flags) {
s8_seek_t find_flag = flags & s8_split_ignore_case ? s8_seek_ignore_case : s8_seek_none;
while (s8_seek(string, find, find_flag, &index)) {
s8_t before_match = s8_make(string.str, index);
sb8_append(&result, before_match);
if (flags & s8_split_cleanup) {
before_match = s8_trim(before_match);
if (before_match.len) {
sb8_append(&result, before_match);
}
} else {
sb8_append(&result, before_match);
}
if (flags & s8_split_inclusive) {
s8_t match = s8_make(string.str + index, find.len);
sb8_append(&result, match);

View File

@@ -35,6 +35,7 @@ enum {
s8_split_none = 0,
s8_split_ignore_case = 1,
s8_split_inclusive = 2,
s8_split_cleanup = 4,
};
enum { s8_ignore_case = 1 };

View File

@@ -15,7 +15,7 @@
fn_export b32 app_update(thread_ctx_t *thread_ctx, app_frame_t *frame) {
tcx = thread_ctx;
if (frame->first_event->kind == app_event_kind_init) {
// run_all_tests();
run_all_tests();
mt_tweak_f32(font_size, 30, 4, 200);
mt_tweak_f32(_font_size, 30, 30, 30);

View File

@@ -13,4 +13,5 @@ void run_all_tests(void) {
test_array();
ui_test_text_replace();
buffer16_test();
testing_out_things();
}// run_all_tests()

View File

@@ -92,3 +92,223 @@ fn void transcript_browser_update(app_frame_t *frame, mt_tweak_t *tweak_table, i
rn_end();
ui_end_frame();
}
///////////////////////////////
// work queue
#define WORK_FUNCTION(name) void name(void *data)
typedef WORK_FUNCTION(work_queue_callback_t);
typedef struct {
work_queue_callback_t *callback;
void *data;
} work_queue_entry_t;
typedef struct work_queue_t work_queue_t;
struct work_queue_t {
int32_t thread_count;
work_queue_entry_t entries[256];
int64_t volatile index_to_write;
int64_t volatile index_to_read;
int64_t volatile completion_index;
int64_t volatile completion_goal;
void *semaphore;
};
typedef struct thread_startup_info_t thread_startup_info_t;
struct thread_startup_info_t {
uint32_t thread_id;
int32_t thread_index;
work_queue_t *queue;
};
fn int64_t atomic_increment(volatile int64_t *i) {
return InterlockedIncrement64(i);
}
fn int64_t atomic_compare_and_swap(volatile int64_t *dst, int64_t exchange, int64_t comperand) {
return InterlockedCompareExchange64(dst, exchange, comperand);
}
fn void work_queue_push(work_queue_t *wq, void *data, work_queue_callback_t *callback) {
uint32_t new_index = (wq->index_to_write + 1) % lengthof(wq->entries);
assert(new_index != wq->index_to_read);
work_queue_entry_t *entry = wq->entries + wq->index_to_write;
entry->data = data;
entry->callback = callback;
wq->completion_goal += 1;
_WriteBarrier();
wq->index_to_write = new_index;
ReleaseSemaphore(wq->semaphore, 1, 0);
}
fn b8 work_queue_try_doing_work(work_queue_t *wq) {
b8 should_sleep = false;
int64_t original_index_to_read = wq->index_to_read;
int64_t new_index_to_read = (original_index_to_read + 1) % lengthof(wq->entries);
if (original_index_to_read != wq->index_to_write) {
int64_t index = atomic_compare_and_swap(&wq->index_to_read, new_index_to_read, original_index_to_read);
if (index == original_index_to_read) {
work_queue_entry_t *entry = wq->entries + index;
entry->callback(entry->data);
atomic_increment(&wq->completion_index);
}
} else {
should_sleep = true;
}
return should_sleep;
}
fn DWORD WINAPI work_queue_thread_entry(LPVOID param) {
thread_startup_info_t *ti = (thread_startup_info_t *)param;
os_core_init();
tcx->thread_index = ti->thread_index;
for (;;) {
if (work_queue_try_doing_work(ti->queue)) {
WaitForSingleObject(ti->queue->semaphore, INFINITE);
}
}
}
fn void work_queue_init(work_queue_t *queue, uint32_t thread_count, thread_startup_info_t *info) {
queue->thread_count = thread_count;
queue->index_to_read = 0;
queue->index_to_write = 0;
queue->completion_index = 0;
queue->completion_goal = 0;
queue->semaphore = CreateSemaphoreExA(0, 0, thread_count, 0, 0, SEMAPHORE_ALL_ACCESS);
assert(queue->semaphore != INVALID_HANDLE_VALUE);
for (uint32_t i = 0; i < thread_count; i++) {
thread_startup_info_t *ti = info + i;
ti->thread_index = i;
ti->queue = queue;
DWORD thread_id = 0;
HANDLE thread_handle = CreateThread(0, 0, work_queue_thread_entry, ti, 0, &thread_id);
assert(thread_handle != INVALID_HANDLE_VALUE);
ti->thread_id = thread_id;
CloseHandle(thread_handle);
}
}
fn b8 work_queue_is_complete(work_queue_t *wq) {
b8 result = wq->completion_goal == wq->completion_index;
return result;
}
fn void work_queue_wait(work_queue_t *wq) {
while (!work_queue_is_complete(wq)) {
work_queue_try_doing_work(wq);
}
}
///////////////////////////////
// mutex
typedef struct mutex_t mutex_t;
struct mutex_t {
void *platform;
};
fn mutex_t mutex_create(void) {
HANDLE handle = CreateMutex(NULL, FALSE, NULL);
assert(handle);
mutex_t result = (mutex_t){(void *)handle};
return result;
}
fn void mutex_destroy(mutex_t mutex) {
BOOL result = CloseHandle(mutex.platform);
assert(result != 0);
unused(result);
}
fn void mutex_lock(mutex_t mutex) {
DWORD result = WaitForSingleObject(mutex.platform, INFINITE);
assert(result == WAIT_OBJECT_0);
unused(result);
}
fn void mutex_unlock(mutex_t mutex) {
BOOL result = ReleaseMutex(mutex.platform);
assert(result != 0);
unused(result);
}
///////////////////////////////
// parse srt
typedef struct srt_entry_t srt_entry_t;
struct srt_entry_t {
srt_entry_t *next;
u16 hour, minute, second;
s8_t string;
};
typedef struct srt_result_t srt_result_t;
struct srt_result_t {
srt_entry_t *first;
srt_entry_t *last;
};
srt_result_t srt_parse(ma_arena_t *arena, s8_t filename) {
s8_t content = os_read(arena, filename);
sb8_t lines = s8_split(arena, content, s8("\n"), s8_split_cleanup);
// srt format looks like this:
// 1
// 00:00:01,000 --> 00:00:05,000
// This is the first subtitle.
//
// or:
// section number
// time interval
// text
int section_number = 1;
srt_result_t result = {0};
for (sb8_node_t *it = lines.first; it;) {
// parse section number
long num = strtol(it->str, NULL, 10);
assert(section_number == num);
section_number += 1;
it = it->next;
// parse start of time interval
srt_entry_t entry = {0};
entry.hour = (u16)strtol(it->str, NULL, 10);
entry.minute = (u16)strtol(it->str + 3, NULL, 10);
entry.second = (u16)strtol(it->str + 6, NULL, 10);
it = it->next;
// parse text
s8_t next_section_number = s8_printf(arena, "%d", section_number);
while (it && !s8_are_equal(next_section_number, it->string)) {
b8 duplicate = result.last && s8_are_equal(it->string, result.last->string);
if (!duplicate) {
srt_entry_t *entry_copy = ma_push_type(arena, srt_entry_t);
entry_copy[0] = entry;
entry_copy->string = it->string;
SLLQ_APPEND(result.first, result.last, entry_copy);
}
it = it->next;
}
}
return result;
}
fn_test void testing_out_things(void) {
mutex_t mutex = mutex_create();
mutex_lock(mutex);
mutex_unlock(mutex);
mutex_destroy(mutex);
ma_temp_t scratch = ma_begin_scratch();
srt_result_t result = srt_parse(scratch.arena, s8("D:\\videos\\zizek\\Hegel and the Spirit of Distrust Sven-Olov Wallenstein & Slavoj Žižek in Conversation [a7gEN-Rxr4c].en.srt"));
unused(result);
ma_end_scratch(scratch);
}

View File

@@ -947,6 +947,4 @@ fn_test void buffer16_test(void) {
}
ma_end_scratch(scratch);
exit(0);
}

View File

@@ -454,7 +454,9 @@ fn void ui_text_input_draw(ui_box_t *box) {
r2f32_t caret_rect = r2f32(co.rect.min.x + size_front.x, co.rect.min.y, co.rect.min.x + size_front.x + 1, co.rect.min.y + ui_em(1));
rn_draw_rect(caret_rect, co.text_color);
}
rn_draw_rect_border(co.rect, co.border_color, box->border_thickness);
// rn_draw_rect_border(co.rect, co.border_color, 1);
r2f32_t bottom = r2f32_cut_bottom(&co.rect, box->border_thickness);
rn_draw_rect(bottom, co.text_color);
}
fn void ui_default_draw_box(ui_box_t *box) {