From 9ddc5c4a6690094c4886197e624101f6a7fe13c1 Mon Sep 17 00:00:00 2001 From: veclavtalica Date: Sun, 26 Jan 2025 02:37:21 +0300 Subject: [PATCH] twn_timer.c: time limiter for game ticks --- CMakeLists.txt | 1 + src/system/linux/twn_timer.c | 71 ++++++++++++++++++++++++++++++++++++ src/system/twn_timer.h | 10 +++++ src/twn_loop.c | 3 ++ 4 files changed, 85 insertions(+) create mode 100644 src/system/linux/twn_timer.c create mode 100644 src/system/twn_timer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 060b34b..6fc0c0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,6 +68,7 @@ add_subdirectory(third-party/libxm ${CMAKE_CURRENT_BINARY_DIR}/third-party/libxm if(LINUX) set(SYSTEM_SOURCE_FILES src/system/linux/twn_elf.c + src/system/linux/twn_timer.c $<$:src/game_object/twn_linux_game_object.c>) elseif(WIN32) set(SYSTEM_SOURCE_FILES diff --git a/src/system/linux/twn_timer.c b/src/system/linux/twn_timer.c new file mode 100644 index 0000000..3fc51e9 --- /dev/null +++ b/src/system/linux/twn_timer.c @@ -0,0 +1,71 @@ +#include "../twn_timer.h" +#include "twn_engine_context_c.h" + +#include + +#include +#include +#include +#include +#include + + +static timer_t timerid; +static sigset_t mask; +static struct sigaction sa; +static struct sigevent sev; + +static bool created; + + +/* stop application */ +static void sanity_timer_handler(int sig, siginfo_t *si, void *uc) { + (void)uc; (void)sig; (void)si; + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, + "sanity timer", "Your game tick exceeded its allocated time, application is closing", + ctx.window); + raise(SIGKILL); +} + + +bool start_sanity_timer(uint64_t milliseconds_to_expire) { + if (!created) { + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = sanity_timer_handler; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGRTMIN, &sa, NULL) == -1) + goto ERR_SIGACTION; + + sev.sigev_notify = SIGEV_SIGNAL; + sev.sigev_signo = SIGRTMIN; + sev.sigev_value.sival_ptr = &timerid; + if (timer_create(CLOCK_MONOTONIC, &sev, &timerid) == -1) + goto ERR_TIMERCREATE; + + created = true; + + ERR_TIMERCREATE: + // ERR_SIGPROCMASK: + ERR_SIGACTION: + return false; + } + + struct itimerspec its = {0}; + its.it_value.tv_sec = milliseconds_to_expire / 1000; + its.it_value.tv_nsec = (milliseconds_to_expire * 1000000 % 1000000000); + if (timer_settime(timerid, 0, &its, NULL) == -1) + return false; + + return true; +} + + +bool end_sanity_timer(void) { + struct itimerspec its = {0}; + its.it_value.tv_sec = 0; + its.it_value.tv_nsec = 0; + if (timer_settime(timerid, 0, &its, NULL) == -1) + return false; + + return false; +} diff --git a/src/system/twn_timer.h b/src/system/twn_timer.h new file mode 100644 index 0000000..2cabcaf --- /dev/null +++ b/src/system/twn_timer.h @@ -0,0 +1,10 @@ +#ifndef TWN_TIMER_H +#define TWN_TIMER_H + +#include +#include + +bool start_sanity_timer(uint64_t milliseconds_to_expire); +bool end_sanity_timer(void); + +#endif // TWN_TIMER_H diff --git a/src/twn_loop.c b/src/twn_loop.c index f3b1849..ab49e36 100644 --- a/src/twn_loop.c +++ b/src/twn_loop.c @@ -5,6 +5,7 @@ #include "twn_util_c.h" #include "twn_game_object_c.h" #include "twn_textures_c.h" +#include "system/twn_timer.h" #include #include @@ -216,7 +217,9 @@ static void main_loop(void) { input_state_update(&ctx.input); profile_start("game tick"); + start_sanity_timer(2000); game_object_tick(); + end_sanity_timer(); profile_end("game tick"); input_state_update_postframe(&ctx.input);