more proper sys_panic
This commit is contained in:
parent
511364ee05
commit
228bef5a68
@ -235,11 +235,11 @@ void app_entry_point(void)
|
|||||||
{
|
{
|
||||||
/* Start callback threads */
|
/* Start callback threads */
|
||||||
for (struct exit_callback *callback = G.exit_callbacks_head; callback; callback = callback->next) {
|
for (struct exit_callback *callback = G.exit_callbacks_head; callback; callback = callback->next) {
|
||||||
callback->thread = sys_thread_init(&exit_callback_thread_entry_point, callback, STR("[P4] Exit callback thread"));
|
callback->thread = sys_thread_alloc(&exit_callback_thread_entry_point, callback, STR("[P4] Exit callback thread"));
|
||||||
}
|
}
|
||||||
/* Wait on callback threads */
|
/* Wait on callback threads */
|
||||||
for (struct exit_callback *callback = G.exit_callbacks_head; callback; callback = callback->next) {
|
for (struct exit_callback *callback = G.exit_callbacks_head; callback; callback = callback->next) {
|
||||||
sys_thread_join(&callback->thread);
|
sys_thread_wait_release(&callback->thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sys_mutex_unlock(&G.exit_callbacks_mutex);
|
sys_mutex_unlock(&G.exit_callbacks_mutex);
|
||||||
|
|||||||
@ -5,9 +5,12 @@
|
|||||||
typedef APP_EXIT_CALLBACK_FUNC_DEF(app_exit_callback_func);
|
typedef APP_EXIT_CALLBACK_FUNC_DEF(app_exit_callback_func);
|
||||||
|
|
||||||
struct string app_write_path_cat(struct arena *arena, struct string filename);
|
struct string app_write_path_cat(struct arena *arena, struct string filename);
|
||||||
|
|
||||||
/* Register a function that will be called when the application exits */
|
/* Register a function that will be called when the application exits */
|
||||||
void app_register_exit_callback(app_exit_callback_func *func);
|
void app_register_exit_callback(app_exit_callback_func *func);
|
||||||
|
|
||||||
void app_entry_point(void);
|
void app_entry_point(void);
|
||||||
|
|
||||||
void app_exit(void);
|
void app_exit(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -21,7 +21,7 @@ struct arena arena_alloc(u64 reserve)
|
|||||||
arena.base = sys_memory_reserve(reserve);
|
arena.base = sys_memory_reserve(reserve);
|
||||||
if (!arena.base) {
|
if (!arena.base) {
|
||||||
/* Hard fail on memory reserve failure for now */
|
/* Hard fail on memory reserve failure for now */
|
||||||
sys_panic_raw("Failed to reserve memory");
|
sys_panic(STR("Failed to reserve memory"));
|
||||||
}
|
}
|
||||||
arena.reserved = reserve;
|
arena.reserved = reserve;
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ struct arena arena_alloc(u64 reserve)
|
|||||||
ASAN_POISON(arena.base, ARENA_BLOCK_SIZE);
|
ASAN_POISON(arena.base, ARENA_BLOCK_SIZE);
|
||||||
if (!arena.base) {
|
if (!arena.base) {
|
||||||
/* Hard fail on commit failure */
|
/* Hard fail on commit failure */
|
||||||
sys_panic_raw("Failed to commit initial memory block: System may be out of memory");
|
sys_panic(STR("Failed to commit initial memory block: System may be out of memory"));
|
||||||
}
|
}
|
||||||
arena.committed = ARENA_BLOCK_SIZE;
|
arena.committed = ARENA_BLOCK_SIZE;
|
||||||
|
|
||||||
@ -68,12 +68,12 @@ void *_arena_push_bytes(struct arena *arena, u64 size, u64 align)
|
|||||||
u64 new_capacity = arena->committed + commit_bytes;
|
u64 new_capacity = arena->committed + commit_bytes;
|
||||||
if (new_capacity > arena->reserved) {
|
if (new_capacity > arena->reserved) {
|
||||||
/* Hard fail if we overflow reserved memory for now */
|
/* Hard fail if we overflow reserved memory for now */
|
||||||
sys_panic_raw("Failed to commit new memory block: Overflow of reserved memory");
|
sys_panic(STR("Failed to commit new memory block: Overflow of reserved memory"));
|
||||||
}
|
}
|
||||||
void *commit_address = arena->base + arena->committed;
|
void *commit_address = arena->base + arena->committed;
|
||||||
if (!sys_memory_commit(commit_address, commit_bytes)) {
|
if (!sys_memory_commit(commit_address, commit_bytes)) {
|
||||||
/* Hard fail on memory allocation failure for now */
|
/* Hard fail on memory allocation failure for now */
|
||||||
sys_panic_raw("Failed to commit new memory block: System may be out of memory");
|
sys_panic(STR("Failed to commit new memory block: System may be out of memory"));
|
||||||
}
|
}
|
||||||
__proffree(arena->base);
|
__proffree(arena->base);
|
||||||
__profalloc(arena->base, arena->committed + commit_bytes);
|
__profalloc(arena->base, arena->committed + commit_bytes);
|
||||||
|
|||||||
@ -53,7 +53,7 @@ struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr,
|
|||||||
G.published_tick_mutex = sys_mutex_alloc();
|
G.published_tick_mutex = sys_mutex_alloc();
|
||||||
|
|
||||||
G.world.timescale = GAME_TIMESCALE;
|
G.world.timescale = GAME_TIMESCALE;
|
||||||
G.game_thread = sys_thread_init(&game_thread_entry_point, NULL, STR("[P2] Game thread"));
|
G.game_thread = sys_thread_alloc(&game_thread_entry_point, NULL, STR("[P2] Game thread"));
|
||||||
app_register_exit_callback(&game_shutdown);
|
app_register_exit_callback(&game_shutdown);
|
||||||
|
|
||||||
return (struct game_startup_receipt) { 0 };
|
return (struct game_startup_receipt) { 0 };
|
||||||
@ -63,7 +63,7 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(game_shutdown)
|
|||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
atomic_i32_eval_exchange(&G.game_thread_shutdown, true);
|
atomic_i32_eval_exchange(&G.game_thread_shutdown, true);
|
||||||
sys_thread_join(&G.game_thread);
|
sys_thread_wait_release(&G.game_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
|
|||||||
14
src/log.c
14
src/log.c
@ -102,6 +102,18 @@ INTERNAL void append_to_logfile(struct string msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Panic log function is separate to enforce zero side effects other than
|
||||||
|
* writing to log file. */
|
||||||
|
void _log_panic(struct string msg)
|
||||||
|
{
|
||||||
|
if (!atomic_i32_eval(&G.initialized)) { return; }
|
||||||
|
|
||||||
|
if (G.file_valid) {
|
||||||
|
sys_file_write(G.file, BUFFER_FROM_STRING(STR("** PANICKING **\n")));
|
||||||
|
sys_file_write(G.file, BUFFER_FROM_STRING(msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if LOG_INCLUDE_SOURCE_LOCATION
|
#if LOG_INCLUDE_SOURCE_LOCATION
|
||||||
void _log(i32 level, struct string file, u32 line, struct string msg)
|
void _log(i32 level, struct string file, u32 line, struct string msg)
|
||||||
#else
|
#else
|
||||||
@ -112,7 +124,7 @@ void _log(i32 level, struct string msg)
|
|||||||
if (!atomic_i32_eval(&G.initialized)) { return; }
|
if (!atomic_i32_eval(&G.initialized)) { return; }
|
||||||
|
|
||||||
if (level < 0 || level >= LOG_LEVEL_COUNT) {
|
if (level < 0 || level >= LOG_LEVEL_COUNT) {
|
||||||
sys_panic_raw("Invalid log level");
|
sys_panic(STR("Invalid log level"));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||||
|
|||||||
@ -54,6 +54,8 @@ void log_register_callback(log_event_callback_func *func);
|
|||||||
* Logging macros
|
* Logging macros
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
|
#define log_panic(msg) _log_panic(msg)
|
||||||
|
|
||||||
#if LOG_LEVEL(LOG_LEVEL_CRITICAL)
|
#if LOG_LEVEL(LOG_LEVEL_CRITICAL)
|
||||||
# if LOG_INCLUDE_SOURCE_LOCATION
|
# if LOG_INCLUDE_SOURCE_LOCATION
|
||||||
# define log_critical(msg) _log(LOG_LEVEL_CRITICAL, STR(__FILE__), __LINE__, msg)
|
# define log_critical(msg) _log(LOG_LEVEL_CRITICAL, STR(__FILE__), __LINE__, msg)
|
||||||
@ -127,6 +129,8 @@ void log_register_callback(log_event_callback_func *func);
|
|||||||
struct log_startup_receipt { i32 _; };
|
struct log_startup_receipt { i32 _; };
|
||||||
struct log_startup_receipt log_startup(struct string logfile_path);
|
struct log_startup_receipt log_startup(struct string logfile_path);
|
||||||
|
|
||||||
|
void _log_panic(struct string msg);
|
||||||
|
|
||||||
#if LOG_INCLUDE_SOURCE_LOCATION
|
#if LOG_INCLUDE_SOURCE_LOCATION
|
||||||
void _log(i32 level, struct string file, u32 line, struct string msg);
|
void _log(i32 level, struct string file, u32 line, struct string msg);
|
||||||
#else
|
#else
|
||||||
|
|||||||
@ -59,7 +59,7 @@ struct playback_startup_receipt playback_startup(struct mixer_startup_receipt *m
|
|||||||
(UNUSED)mixer_sr;
|
(UNUSED)mixer_sr;
|
||||||
|
|
||||||
wasapi_initialize();
|
wasapi_initialize();
|
||||||
G.playback_thread = sys_thread_init(&playback_thread_entry_point, NULL, STR("[P3] Audio thread"));
|
G.playback_thread = sys_thread_alloc(&playback_thread_entry_point, NULL, STR("[P3] Audio thread"));
|
||||||
app_register_exit_callback(&playback_shutdown);
|
app_register_exit_callback(&playback_shutdown);
|
||||||
|
|
||||||
return (struct playback_startup_receipt) { 0 };
|
return (struct playback_startup_receipt) { 0 };
|
||||||
@ -69,7 +69,7 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(playback_shutdown)
|
|||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
atomic_i32_eval_exchange(&G.playback_thread_shutdown, true);
|
atomic_i32_eval_exchange(&G.playback_thread_shutdown, true);
|
||||||
sys_thread_join(&G.playback_thread);
|
sys_thread_wait_release(&G.playback_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
|
|||||||
@ -32,7 +32,7 @@ INLINE void scratch_dbg_push(struct scratch_ctx *ctx, struct temp_arena *temp)
|
|||||||
{
|
{
|
||||||
#if RTC
|
#if RTC
|
||||||
if (ctx->scratch_id_stack_count >= ARRAY_COUNT(ctx->scratch_id_stack)) {
|
if (ctx->scratch_id_stack_count >= ARRAY_COUNT(ctx->scratch_id_stack)) {
|
||||||
sys_panic_raw("Max debug scratch depth reached");
|
sys_panic(STR("Max debug scratch depth reached"));
|
||||||
}
|
}
|
||||||
temp->scratch_id = ctx->next_scratch_id++;
|
temp->scratch_id = ctx->next_scratch_id++;
|
||||||
ctx->scratch_id_stack[ctx->scratch_id_stack_count++] = temp->scratch_id;
|
ctx->scratch_id_stack[ctx->scratch_id_stack_count++] = temp->scratch_id;
|
||||||
|
|||||||
@ -401,14 +401,14 @@ struct sys_thread {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Creates a new thread running in the supplied `entry_point` */
|
/* Creates a new thread running in the supplied `entry_point` */
|
||||||
struct sys_thread sys_thread_init(
|
struct sys_thread sys_thread_alloc(
|
||||||
sys_thread_entry_point_func *entry_point,
|
sys_thread_entry_point_func *entry_point,
|
||||||
void *thread_data, /* Passed as arg to `entry_point` */
|
void *thread_data, /* Passed as arg to `entry_point` */
|
||||||
struct string thread_name
|
struct string thread_name
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Halt and wait for a thread to finish */
|
/* Halt and wait for a thread to finish */
|
||||||
void sys_thread_join(struct sys_thread *thread);
|
void sys_thread_wait_release(struct sys_thread *thread);
|
||||||
|
|
||||||
/* Gets the current executing thread's ID */
|
/* Gets the current executing thread's ID */
|
||||||
u32 sys_thread_id(void);
|
u32 sys_thread_id(void);
|
||||||
@ -472,11 +472,6 @@ void sys_exit(void);
|
|||||||
|
|
||||||
u32 sys_rand_u32(void);
|
u32 sys_rand_u32(void);
|
||||||
|
|
||||||
/* Implementation of this function should have minimal side effects (e.g. avoid
|
|
||||||
* memory allocation), since it may be called in circumstances where those side
|
|
||||||
* effects are non-functioning. */
|
|
||||||
void sys_panic_raw(char *msg_cstr);
|
|
||||||
|
|
||||||
void sys_panic(struct string msg);
|
void sys_panic(struct string msg);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
|
|||||||
134
src/sys_win32.c
134
src/sys_win32.c
@ -102,6 +102,11 @@ GLOBAL struct {
|
|||||||
i32 scheduler_period_ms;
|
i32 scheduler_period_ms;
|
||||||
DWORD thread_tls_index;
|
DWORD thread_tls_index;
|
||||||
|
|
||||||
|
/* Panic */
|
||||||
|
struct atomic_i32 panicking;
|
||||||
|
wchar_t panic_wstr[4096];
|
||||||
|
HANDLE panic_event;
|
||||||
|
|
||||||
/* Lookup tables */
|
/* Lookup tables */
|
||||||
enum sys_btn vk_btn_table[256];
|
enum sys_btn vk_btn_table[256];
|
||||||
|
|
||||||
@ -405,7 +410,7 @@ void sys_file_write(struct sys_file file, struct buffer data)
|
|||||||
sys_panic(string_format(scratch.arena,
|
sys_panic(string_format(scratch.arena,
|
||||||
STR("Tried to write too many bytes to disk (%F)"),
|
STR("Tried to write too many bytes to disk (%F)"),
|
||||||
FMT_UINT(data.size)));
|
FMT_UINT(data.size)));
|
||||||
//scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* WriteFile returns TRUE on success */
|
/* WriteFile returns TRUE on success */
|
||||||
@ -598,7 +603,7 @@ INTERNAL HWND win32_create_window(struct win32_window *window)
|
|||||||
return hwnd;
|
return hwnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void window_thread_entry_point(void *arg)
|
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(window_thread_entry_point, arg)
|
||||||
{
|
{
|
||||||
struct win32_window *window = (struct win32_window *)arg;
|
struct win32_window *window = (struct win32_window *)arg;
|
||||||
|
|
||||||
@ -701,7 +706,7 @@ INTERNAL struct win32_window *win32_window_alloc(void)
|
|||||||
window->event_callbacks_mutex = sys_mutex_alloc();
|
window->event_callbacks_mutex = sys_mutex_alloc();
|
||||||
|
|
||||||
/* Start window thread for processing events */
|
/* Start window thread for processing events */
|
||||||
window->event_thread = sys_thread_init(&window_thread_entry_point, window, STR("[P8] Window thread"));
|
window->event_thread = sys_thread_alloc(&window_thread_entry_point, window, STR("[P8] Window thread"));
|
||||||
|
|
||||||
/* Wait for event thread to create actual window */
|
/* Wait for event thread to create actual window */
|
||||||
sync_flag_wait(&window->ready_sf);
|
sync_flag_wait(&window->ready_sf);
|
||||||
@ -718,7 +723,7 @@ INTERNAL void win32_window_release(struct win32_window *window)
|
|||||||
|
|
||||||
/* Stop window thread */
|
/* Stop window thread */
|
||||||
window->event_thread_shutdown = true;
|
window->event_thread_shutdown = true;
|
||||||
sys_thread_join(&window->event_thread);
|
sys_thread_wait_release(&window->event_thread);
|
||||||
|
|
||||||
/* Release mutexes */
|
/* Release mutexes */
|
||||||
sys_mutex_release(&window->event_callbacks_mutex);
|
sys_mutex_release(&window->event_callbacks_mutex);
|
||||||
@ -1518,10 +1523,13 @@ INTERNAL struct win32_thread *win32_thread_alloc_assume_locked(void)
|
|||||||
t = arena_push_zero(&G.threads_arena, struct win32_thread);
|
t = arena_push_zero(&G.threads_arena, struct win32_thread);
|
||||||
t->gen = 1;
|
t->gen = 1;
|
||||||
}
|
}
|
||||||
if (G.threads_last) {
|
if (!G.threads_first) {
|
||||||
|
G.threads_first = t;
|
||||||
|
} else {
|
||||||
G.threads_last->next = t;
|
G.threads_last->next = t;
|
||||||
}
|
}
|
||||||
t->prev = G.threads_last;
|
t->prev = G.threads_last;
|
||||||
|
G.threads_last = t;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1606,7 +1614,7 @@ INTERNAL DWORD WINAPI win32_thread_proc(LPVOID vt)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sys_thread sys_thread_init(sys_thread_entry_point_func *entry_point, void *thread_data, struct string thread_name)
|
struct sys_thread sys_thread_alloc(sys_thread_entry_point_func *entry_point, void *thread_data, struct string thread_name)
|
||||||
{
|
{
|
||||||
ASSERT(entry_point != NULL);
|
ASSERT(entry_point != NULL);
|
||||||
logf_info("Creating thread \"%F\"", FMT_STR(thread_name));
|
logf_info("Creating thread \"%F\"", FMT_STR(thread_name));
|
||||||
@ -1641,7 +1649,7 @@ struct sys_thread sys_thread_init(sys_thread_entry_point_func *entry_point, void
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_thread_join(struct sys_thread *thread)
|
void sys_thread_wait_release(struct sys_thread *thread)
|
||||||
{
|
{
|
||||||
HANDLE handle = 0;
|
HANDLE handle = 0;
|
||||||
|
|
||||||
@ -1660,8 +1668,8 @@ void sys_thread_join(struct sys_thread *thread)
|
|||||||
DWORD res = WaitForSingleObject(handle, INFINITE);
|
DWORD res = WaitForSingleObject(handle, INFINITE);
|
||||||
CloseHandle(handle);
|
CloseHandle(handle);
|
||||||
|
|
||||||
(UNUSED)res;
|
|
||||||
ASSERT(res != WAIT_FAILED);
|
ASSERT(res != WAIT_FAILED);
|
||||||
|
(UNUSED)res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1684,32 +1692,33 @@ void sys_thread_assert(u32 tid)
|
|||||||
void sys_message_box(enum sys_message_box_kind kind, struct string message)
|
void sys_message_box(enum sys_message_box_kind kind, struct string message)
|
||||||
{
|
{
|
||||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||||
wchar_t *message_wstr = wstr_from_string(scratch.arena, message);
|
|
||||||
|
|
||||||
|
wchar_t *message_wstr = wstr_from_string(scratch.arena, message);
|
||||||
const wchar_t *title = L"";
|
const wchar_t *title = L"";
|
||||||
UINT mbox_type = 0;
|
UINT mbox_type = MB_SETFOREGROUND;
|
||||||
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case SYS_MESSAGE_BOX_KIND_OK: {
|
case SYS_MESSAGE_BOX_KIND_OK: {
|
||||||
mbox_type = MB_ICONINFORMATION;
|
mbox_type |= MB_ICONINFORMATION;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case SYS_MESSAGE_BOX_KIND_WARNING: {
|
case SYS_MESSAGE_BOX_KIND_WARNING: {
|
||||||
title = L"Warning";
|
title = L"Warning";
|
||||||
mbox_type = MB_ICONWARNING;
|
mbox_type |= MB_ICONWARNING;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case SYS_MESSAGE_BOX_KIND_ERROR: {
|
case SYS_MESSAGE_BOX_KIND_ERROR: {
|
||||||
title = L"Error";
|
title = L"Error";
|
||||||
mbox_type = MB_ICONERROR;
|
mbox_type |= MB_ICONERROR;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case SYS_MESSAGE_BOX_KIND_FATAL: {
|
case SYS_MESSAGE_BOX_KIND_FATAL: {
|
||||||
title = L"Fatal error";
|
title = L"Fatal error";
|
||||||
mbox_type = MB_ICONSTOP;
|
mbox_type |= MB_ICONSTOP;
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logf_info("Showing message box: \"%F\"", FMT_STR(message));
|
||||||
MessageBoxExW(NULL, message_wstr, title, mbox_type, 0);
|
MessageBoxExW(NULL, message_wstr, title, mbox_type, 0);
|
||||||
|
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
@ -1816,31 +1825,41 @@ u32 sys_rand_u32(void)
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void panic_exit(void)
|
|
||||||
{
|
|
||||||
ASSERT(false);
|
|
||||||
sys_exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void sys_panic_raw(char *msg_cstr)
|
|
||||||
{
|
|
||||||
/* FIXME: Exit other threads before showing message box */
|
|
||||||
MessageBoxExA(NULL, msg_cstr, "Fatal error", MB_ICONSTOP, 0);
|
|
||||||
panic_exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void sys_panic(struct string msg)
|
void sys_panic(struct string msg)
|
||||||
{
|
{
|
||||||
/* FIXME: Exit other threads before showing message box */
|
if (atomic_i32_eval_compare_exchange(&G.panicking, 0, 1) == 0) {
|
||||||
logf_critical("Panicking: %F", FMT_STR(msg));
|
log_panic(msg);
|
||||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
|
||||||
msg = string_cat(scratch.arena,
|
wchar_t *wstr = G.panic_wstr;
|
||||||
STR("A fatal error has occured and the application needs to exit:\n\n"),
|
u64 wstr_len = 0;
|
||||||
msg);
|
|
||||||
wchar_t *msg_wstr = wstr_from_string(scratch.arena, msg);
|
wchar_t prefix[] = L"A fatal error has occured and the application needs to exit:\n\n";
|
||||||
MessageBoxExW(NULL, msg_wstr, L"Fatal error", MB_ICONSTOP, 0);
|
MEMCPY(wstr, prefix, min_u64(ARRAY_COUNT(G.panic_wstr), (ARRAY_COUNT(prefix) << 1)));
|
||||||
panic_exit();
|
wstr_len += ARRAY_COUNT(prefix) - 1;
|
||||||
scratch_end(scratch);
|
|
||||||
|
struct string str8 = msg;
|
||||||
|
u64 pos8 = 0;
|
||||||
|
while (pos8 < str8.len) {
|
||||||
|
struct string str8_remaining = { .len = (str8.len - pos8), .text = str8.text + pos8 };
|
||||||
|
struct uni_decode_utf8_result decoded = uni_decode_utf8(str8_remaining);
|
||||||
|
struct uni_encode_utf16_result encoded = uni_encode_utf16(decoded.codepoint);
|
||||||
|
|
||||||
|
u64 wstr_new_len = wstr_len + encoded.count16;
|
||||||
|
if (wstr_new_len < (ARRAY_COUNT(G.panic_wstr) - 1)) {
|
||||||
|
u16 *dest = wstr + wstr_len;
|
||||||
|
MEMCPY(dest, encoded.chars16, (encoded.count16 << 1));
|
||||||
|
wstr_len = wstr_new_len;
|
||||||
|
pos8 += decoded.advance8;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wstr[wstr_len] = 0;
|
||||||
|
|
||||||
|
WRITE_BARRIER();
|
||||||
|
SetEvent(G.panic_event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -1978,6 +1997,9 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
|
|||||||
|
|
||||||
SetThreadDescription(GetCurrentThread(), L"Main thread");
|
SetThreadDescription(GetCurrentThread(), L"Main thread");
|
||||||
|
|
||||||
|
/* Set up panic event */
|
||||||
|
G.panic_event = CreateEventW(NULL, true, false, NULL);
|
||||||
|
|
||||||
/* Query system info */
|
/* Query system info */
|
||||||
GetSystemInfo(&G.info);
|
GetSystemInfo(&G.info);
|
||||||
QueryPerformanceFrequency(&G.timer_frequency);
|
QueryPerformanceFrequency(&G.timer_frequency);
|
||||||
@ -2062,8 +2084,40 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
|
|||||||
win32_thread_set_tls(&main_thread_tls);
|
win32_thread_set_tls(&main_thread_tls);
|
||||||
|
|
||||||
/* Call app thread and wait for return */
|
/* Call app thread and wait for return */
|
||||||
struct sys_thread app_thread = sys_thread_init(&app_thread_entry_point, NULL, STR("[P9] App thread"));
|
{
|
||||||
sys_thread_join(&app_thread);
|
struct sys_thread app_thread = sys_thread_alloc(&app_thread_entry_point, NULL, STR("[P9] App thread"));
|
||||||
|
|
||||||
|
HANDLE app_thread_handle = 0;
|
||||||
|
sys_rw_mutex_lock_shared(&G.threads_rw_mutex);
|
||||||
|
{
|
||||||
|
struct win32_thread *wt = win32_thread_from_sys_thread_assume_locked(app_thread);
|
||||||
|
app_thread_handle = wt->handle;
|
||||||
|
}
|
||||||
|
sys_rw_mutex_unlock_shared(&G.threads_rw_mutex);
|
||||||
|
|
||||||
|
/* Wait for thread exit or panic */
|
||||||
|
if (app_thread_handle) {
|
||||||
|
HANDLE wait_handles[] = {
|
||||||
|
app_thread_handle,
|
||||||
|
G.panic_event
|
||||||
|
};
|
||||||
|
DWORD res = WaitForMultipleObjects(ARRAY_COUNT(wait_handles), wait_handles, false, INFINITE);
|
||||||
|
ASSERT(res != WAIT_FAILED);
|
||||||
|
(UNUSED)res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Panic message was set */
|
||||||
|
if (atomic_i32_eval(&G.panicking)) {
|
||||||
|
/* Force stop threads */
|
||||||
|
for (struct win32_thread *t = G.threads_last; t; t = t->prev) {
|
||||||
|
HANDLE handle = t->handle;
|
||||||
|
TerminateThread(handle, 0);
|
||||||
|
CloseHandle(handle);
|
||||||
|
}
|
||||||
|
error_msg = G.panic_wstr;
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
/* Release main thread context */
|
/* Release main thread context */
|
||||||
win32_tls_release(&main_thread_tls);
|
win32_tls_release(&main_thread_tls);
|
||||||
@ -2075,7 +2129,7 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
|
|||||||
abort:
|
abort:
|
||||||
|
|
||||||
if (error_msg) {
|
if (error_msg) {
|
||||||
MessageBoxExW(NULL, error_msg, L"Fatal initialization error", MB_ICONSTOP, 0);
|
MessageBoxExW(NULL, error_msg, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND, 0);
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,7 +72,7 @@ void *_thread_local_eval(struct thread_local_var_meta *meta)
|
|||||||
if (id_plus_one == 0) {
|
if (id_plus_one == 0) {
|
||||||
id = G.metas_count++;
|
id = G.metas_count++;
|
||||||
if (id >= MAX_THREAD_LOCAL_VARS) {
|
if (id >= MAX_THREAD_LOCAL_VARS) {
|
||||||
sys_panic_raw("Maximum number of thread local variables reached");
|
sys_panic(STR("Maximum number of thread local variables reached"));
|
||||||
}
|
}
|
||||||
atomic_u64_eval_exchange(&meta->id_plus_one, id + 1);
|
atomic_u64_eval_exchange(&meta->id_plus_one, id + 1);
|
||||||
G.metas[id] = *meta;
|
G.metas[id] = *meta;
|
||||||
|
|||||||
@ -133,7 +133,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
|||||||
G.window = window;
|
G.window = window;
|
||||||
sys_window_register_event_callback(G.window, &window_event_callback);
|
sys_window_register_event_callback(G.window, &window_event_callback);
|
||||||
|
|
||||||
G.user_thread = sys_thread_init(&user_thread_entry_point, NULL, STR("[P1] User thread"));
|
G.user_thread = sys_thread_alloc(&user_thread_entry_point, NULL, STR("[P1] User thread"));
|
||||||
app_register_exit_callback(&user_shutdown);
|
app_register_exit_callback(&user_shutdown);
|
||||||
|
|
||||||
return (struct user_startup_receipt) { 0 };
|
return (struct user_startup_receipt) { 0 };
|
||||||
@ -143,7 +143,7 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(user_shutdown)
|
|||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
atomic_i32_eval_exchange(&G.user_thread_shutdown, true);
|
atomic_i32_eval_exchange(&G.user_thread_shutdown, true);
|
||||||
sys_thread_join(&G.user_thread);
|
sys_thread_wait_release(&G.user_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -2175,7 +2175,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
|||||||
G.window = window;
|
G.window = window;
|
||||||
sys_window_register_event_callback(G.window, &window_event_callback);
|
sys_window_register_event_callback(G.window, &window_event_callback);
|
||||||
|
|
||||||
G.user_thread = sys_thread_init(&user_thread_entry_point, NULL, STR("[P1] User thread"));
|
G.user_thread = sys_thread_alloc(&user_thread_entry_point, NULL, STR("[P1] User thread"));
|
||||||
|
|
||||||
return (struct user_startup_receipt) { 0 };
|
return (struct user_startup_receipt) { 0 };
|
||||||
}
|
}
|
||||||
@ -2183,7 +2183,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
|||||||
void user_shutdown(void)
|
void user_shutdown(void)
|
||||||
{
|
{
|
||||||
G.shutdown = true;
|
G.shutdown = true;
|
||||||
sys_thread_join(&G.user_thread);
|
sys_thread_wait_release(&G.user_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -132,7 +132,7 @@ struct work_startup_receipt work_startup(u32 num_worker_threads)
|
|||||||
FMT_UINT(i));
|
FMT_UINT(i));
|
||||||
|
|
||||||
struct worker *worker = arena_push_zero(&G.arena, struct worker);
|
struct worker *worker = arena_push_zero(&G.arena, struct worker);
|
||||||
worker->thread = sys_thread_init(&worker_thread_entry_point, NULL, thread_name);
|
worker->thread = sys_thread_alloc(&worker_thread_entry_point, NULL, thread_name);
|
||||||
if (prev) {
|
if (prev) {
|
||||||
prev->next = worker;
|
prev->next = worker;
|
||||||
} else {
|
} else {
|
||||||
@ -155,7 +155,7 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(work_shutdown)
|
|||||||
atomic_i32_eval_exchange(&G.workers_shutdown, true);
|
atomic_i32_eval_exchange(&G.workers_shutdown, true);
|
||||||
sys_semaphore_signal(&G.semaphore, G.worker_count);
|
sys_semaphore_signal(&G.semaphore, G.worker_count);
|
||||||
for (struct worker *worker = G.worker_head; (worker = worker->next);) {
|
for (struct worker *worker = G.worker_head; (worker = worker->next);) {
|
||||||
sys_thread_join(&worker->thread);
|
sys_thread_wait_release(&worker->thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user