#include "../twn_timer.h" #include "twn_engine_context_c.h" #include #include #include #include #include #include static timer_t timerid; static struct sigaction sa; static struct sigevent sev; static bool created; static uint64_t used_milliseconds_to_expire; #define SANITY_TIMER_MESSAGE_FMT "Game tick exeeded its allocated time (%lu milliseconds), application is closing" /* stop application */ static void sanity_timer_handler(int sig, siginfo_t *si, void *uc) { (void)uc; (void)sig; (void)si; size_t text_str_len = snprintf(NULL, 0, SANITY_TIMER_MESSAGE_FMT, used_milliseconds_to_expire) + 1; char *text_str = SDL_malloc(text_str_len); snprintf(text_str, text_str_len, SANITY_TIMER_MESSAGE_FMT, used_milliseconds_to_expire); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "sanity timer", text_str, ctx.window); SDL_free(text_str); 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; used_milliseconds_to_expire = milliseconds_to_expire; 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; }