From b6360516e4bbd65447e70899a03454c4435699f3 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 26 May 2024 17:56:29 -0700 Subject: [PATCH] Added the timerID to the SDL timer callback Fixes https://github.com/libsdl-org/SDL/issues/2593 --- docs/README-migration.md | 7 +++++++ include/SDL3/SDL_timer.h | 32 +++++++++++++++----------------- src/dynapi/SDL_dynapi_procs.h | 2 +- src/timer/SDL_timer.c | 32 ++++++++++++++++++-------------- test/testautomation_timer.c | 10 +++++----- test/testlock.c | 2 +- test/testtimer.c | 10 ++++++---- 7 files changed, 53 insertions(+), 42 deletions(-) diff --git a/docs/README-migration.md b/docs/README-migration.md index 020b1fffc..e141b844f 100644 --- a/docs/README-migration.md +++ b/docs/README-migration.md @@ -1677,6 +1677,13 @@ If you were using this macro for other things besides SDL ticks values, you can #define SDL_TICKS_PASSED(A, B) ((Sint32)((B) - (A)) <= 0) ``` +The callback passed to SDL_AddTimer() has changed parameters to: +```c +Uint32 SDLCALL TimerCallback(void *userdata, SDL_TimerID timerID, Uint32 interval); +```` + +The return value of SDL_RemoveTimer() has changed to the standard int error code. + ## SDL_touch.h SDL_GetTouchName is replaced with SDL_GetTouchDeviceName(), which takes an SDL_TouchID instead of an index. diff --git a/include/SDL3/SDL_timer.h b/include/SDL3/SDL_timer.h index ecaa305c0..200a7fba0 100644 --- a/include/SDL3/SDL_timer.h +++ b/include/SDL3/SDL_timer.h @@ -124,6 +124,13 @@ extern SDL_DECLSPEC void SDLCALL SDL_Delay(Uint32 ms); */ extern SDL_DECLSPEC void SDLCALL SDL_DelayNS(Uint64 ns); +/** + * Definition of the timer ID type. + * + * \since This datatype is available since SDL 3.0.0. + */ +typedef Uint32 SDL_TimerID; + /** * Function prototype for the timer callback function. * @@ -132,9 +139,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_DelayNS(Uint64 ns); * the one passed in, the periodic alarm continues, otherwise a new alarm is * scheduled. If the callback returns 0, the periodic alarm is cancelled. * + * \param userdata an arbitrary pointer provided by the app through SDL_AddTimer, for its own use. + * \param timerID the current timer being processed * \param interval the current callback time interval. - * \param param an arbitrary pointer provided by the app through SDL_AddTimer, - * for its own use. * \returns the new callback time interval, or 0 to disable further runs of * the callback. * @@ -146,14 +153,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_DelayNS(Uint64 ns); * * \sa SDL_AddTimer */ -typedef Uint32 (SDLCALL *SDL_TimerCallback)(Uint32 interval, void *param); - -/** - * Definition of the timer ID type. - * - * \since This datatype is available since SDL 3.0.0. - */ -typedef Uint32 SDL_TimerID; +typedef Uint32 (SDLCALL *SDL_TimerCallback)(void *userdata, SDL_TimerID timerID, Uint32 interval); /** * Call a callback function at a future time. @@ -179,7 +179,7 @@ typedef Uint32 SDL_TimerID; * \param interval the timer delay, in milliseconds, passed to `callback` * \param callback the SDL_TimerCallback function to call when the specified * `interval` elapses - * \param param a pointer that is passed to `callback` + * \param userdata a pointer that is passed to `callback` * \returns a timer ID or 0 if an error occurs; call SDL_GetError() for more * information. * @@ -189,22 +189,20 @@ typedef Uint32 SDL_TimerID; * * \sa SDL_RemoveTimer */ -extern SDL_DECLSPEC SDL_TimerID SDLCALL SDL_AddTimer(Uint32 interval, - SDL_TimerCallback callback, - void *param); +extern SDL_DECLSPEC SDL_TimerID SDLCALL SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *userdata); /** * Remove a timer created with SDL_AddTimer(). * * \param id the ID of the timer to remove - * \returns SDL_TRUE if the timer is removed or SDL_FALSE if the timer wasn't - * found. + * \returns 0 on success or a negative error code on failure; call + * SDL_GetError() for more information. * * \since This function is available since SDL 3.0.0. * * \sa SDL_AddTimer */ -extern SDL_DECLSPEC SDL_bool SDLCALL SDL_RemoveTimer(SDL_TimerID id); +extern SDL_DECLSPEC int SDLCALL SDL_RemoveTimer(SDL_TimerID id); /* Ends C function definitions when using C++ */ diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index c69b84796..a2e016c00 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -662,7 +662,7 @@ SDL_DYNAPI_PROC(int,SDL_ReleaseCameraFrame,(SDL_Camera *a, SDL_Surface *b),(a,b) SDL_DYNAPI_PROC(int,SDL_ReloadGamepadMappings,(void),(),return) SDL_DYNAPI_PROC(int,SDL_RemovePath,(const char *a),(a),return) SDL_DYNAPI_PROC(int,SDL_RemoveStoragePath,(SDL_Storage *a, const char *b),(a,b),return) -SDL_DYNAPI_PROC(SDL_bool,SDL_RemoveTimer,(SDL_TimerID a),(a),return) +SDL_DYNAPI_PROC(int,SDL_RemoveTimer,(SDL_TimerID a),(a),return) SDL_DYNAPI_PROC(int,SDL_RenamePath,(const char *a, const char *b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_RenameStoragePath,(SDL_Storage *a, const char *b, const char *c),(a,b,c),return) SDL_DYNAPI_PROC(int,SDL_RenderClear,(SDL_Renderer *a),(a),return) diff --git a/src/timer/SDL_timer.c b/src/timer/SDL_timer.c index b779c7c3f..9043a2052 100644 --- a/src/timer/SDL_timer.c +++ b/src/timer/SDL_timer.c @@ -31,7 +31,7 @@ typedef struct SDL_Timer { SDL_TimerID timerID; SDL_TimerCallback callback; - void *param; + void *userdata; Uint64 interval; Uint64 scheduled; SDL_AtomicInt canceled; @@ -161,7 +161,7 @@ static int SDLCALL SDL_TimerThread(void *_data) interval = 0; } else { /* FIXME: We could potentially support sub-millisecond timers now */ - interval = SDL_MS_TO_NS(current->callback((Uint32)SDL_NS_TO_MS(current->interval), current->param)); + interval = SDL_MS_TO_NS(current->callback(current->userdata, current->timerID, (Uint32)SDL_NS_TO_MS(current->interval))); } if (interval > 0) { @@ -269,7 +269,7 @@ void SDL_QuitTimers(void) } } -SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param) +SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *userdata) { SDL_TimerData *data = &SDL_timer_data; SDL_Timer *timer; @@ -299,7 +299,7 @@ SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *para } timer->timerID = SDL_GetNextObjectID(); timer->callback = callback; - timer->param = param; + timer->userdata = userdata; timer->interval = SDL_MS_TO_NS(interval); timer->scheduled = SDL_GetTicksNS() + timer->interval; SDL_AtomicSet(&timer->canceled, 0); @@ -329,7 +329,7 @@ SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *para return entry->timerID; } -SDL_bool SDL_RemoveTimer(SDL_TimerID id) +int SDL_RemoveTimer(SDL_TimerID id) { SDL_TimerData *data = &SDL_timer_data; SDL_TimerMap *prev, *entry; @@ -357,7 +357,11 @@ SDL_bool SDL_RemoveTimer(SDL_TimerID id) } SDL_free(entry); } - return canceled; + if (canceled) { + return 0; + } else { + return SDL_SetError("Timer not found"); + } } #else @@ -371,7 +375,7 @@ typedef struct SDL_TimerMap int timeoutID; Uint32 interval; SDL_TimerCallback callback; - void *param; + void *userdata; struct SDL_TimerMap *next; } SDL_TimerMap; @@ -385,7 +389,7 @@ static SDL_TimerData SDL_timer_data; static void SDL_Emscripten_TimerHelper(void *userdata) { SDL_TimerMap *entry = (SDL_TimerMap *)userdata; - entry->interval = entry->callback(entry->interval, entry->param); + entry->interval = entry->callback(entry->userdata, entry->timerID, entry->interval); if (entry->interval > 0) { entry->timeoutID = emscripten_set_timeout(&SDL_Emscripten_TimerHelper, entry->interval, @@ -410,7 +414,7 @@ void SDL_QuitTimers(void) } } -SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param) +SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *userdata) { SDL_TimerData *data = &SDL_timer_data; SDL_TimerMap *entry; @@ -421,7 +425,7 @@ SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *para } entry->timerID = SDL_GetNextObjectID(); entry->callback = callback; - entry->param = param; + entry->userdata = userdata; entry->interval = interval; entry->timeoutID = emscripten_set_timeout(&SDL_Emscripten_TimerHelper, @@ -434,7 +438,7 @@ SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *para return entry->timerID; } -SDL_bool SDL_RemoveTimer(SDL_TimerID id) +int SDL_RemoveTimer(SDL_TimerID id) { SDL_TimerData *data = &SDL_timer_data; SDL_TimerMap *prev, *entry; @@ -455,10 +459,10 @@ SDL_bool SDL_RemoveTimer(SDL_TimerID id) if (entry) { emscripten_clear_timeout(entry->timeoutID); SDL_free(entry); - - return SDL_TRUE; + return 0; + } else { + return SDL_SetError("Timer not found"); } - return SDL_FALSE; } #endif /* !defined(SDL_PLATFORM_EMSCRIPTEN) || !SDL_THREADS_DISABLED */ diff --git a/test/testautomation_timer.c b/test/testautomation_timer.c index e2925e97e..23d971218 100644 --- a/test/testautomation_timer.c +++ b/test/testautomation_timer.c @@ -101,7 +101,7 @@ static int timer_delayAndGetTicks(void *arg) } /* Test callback */ -static Uint32 SDLCALL timerTestCallback(Uint32 interval, void *param) +static Uint32 SDLCALL timerTestCallback(void *param, SDL_TimerID timerID, Uint32 interval) { g_timerCallbackCalled = 1; @@ -121,7 +121,7 @@ static Uint32 SDLCALL timerTestCallback(Uint32 interval, void *param) static int timer_addRemoveTimer(void *arg) { SDL_TimerID id; - SDL_bool result; + int result; int param; /* Reset state */ @@ -136,13 +136,13 @@ static int timer_addRemoveTimer(void *arg) /* Remove timer again and check that callback was not called */ result = SDL_RemoveTimer(id); SDLTest_AssertPass("Call to SDL_RemoveTimer()"); - SDLTest_AssertCheck(result == SDL_TRUE, "Check result value, expected: %i, got: %i", SDL_TRUE, result); + SDLTest_AssertCheck(result == 0, "Check result value, expected: 0, got: %i", result); SDLTest_AssertCheck(g_timerCallbackCalled == 0, "Check callback WAS NOT called, expected: 0, got: %i", g_timerCallbackCalled); /* Try to remove timer again (should be a NOOP) */ result = SDL_RemoveTimer(id); SDLTest_AssertPass("Call to SDL_RemoveTimer()"); - SDLTest_AssertCheck(result == SDL_FALSE, "Check result value, expected: %i, got: %i", SDL_FALSE, result); + SDLTest_AssertCheck(result < 0, "Check result value, expected: <0, got: %i", result); /* Reset state */ param = SDLTest_RandomIntegerInRange(-1024, 1024); @@ -162,7 +162,7 @@ static int timer_addRemoveTimer(void *arg) /* Remove timer again and check that callback was called */ result = SDL_RemoveTimer(id); SDLTest_AssertPass("Call to SDL_RemoveTimer()"); - SDLTest_AssertCheck(result == SDL_FALSE, "Check result value, expected: %i, got: %i", SDL_FALSE, result); + SDLTest_AssertCheck(result < 0, "Check result value, expected: <0, got: %i", result); SDLTest_AssertCheck(g_timerCallbackCalled == 1, "Check callback WAS called, expected: 1, got: %i", g_timerCallbackCalled); return TEST_COMPLETED; diff --git a/test/testlock.c b/test/testlock.c index 28baa522f..f645802b4 100644 --- a/test/testlock.c +++ b/test/testlock.c @@ -100,7 +100,7 @@ Run(void *data) } #ifndef _WIN32 -static Uint32 hit_timeout(Uint32 interval, void *param) { +static Uint32 hit_timeout(void *param, SDL_TimerID timerID, Uint32 interval) { SDL_Log("Hit timeout! Sending SIGINT!"); (void)raise(SIGINT); return 0; diff --git a/test/testtimer.c b/test/testtimer.c index 5714ea334..63456f7fc 100644 --- a/test/testtimer.c +++ b/test/testtimer.c @@ -50,16 +50,18 @@ static int test_sdl_delay_within_bounds(void) { static int ticks = 0; static Uint32 SDLCALL -ticktock(Uint32 interval, void *param) +ticktock(void *param, SDL_TimerID timerID, Uint32 interval) { ++ticks; return interval; } static Uint32 SDLCALL -callback(Uint32 interval, void *param) +callback(void *param, SDL_TimerID timerID, Uint32 interval) { - SDL_Log("Timer %" SDL_PRIu32 " : param = %d\n", interval, (int)(uintptr_t)param); + int value = (int)(uintptr_t)param; + SDL_assert( value == 1 || value == 2 || value == 3 ); + SDL_Log("Timer %" SDL_PRIu32 " : param = %d\n", interval, value); return interval; } @@ -182,7 +184,7 @@ int main(int argc, char *argv[]) start_perf = SDL_GetPerformanceCounter(); for (i = 0; i < 1000000; ++i) { - ticktock(0, NULL); + ticktock(NULL, 0, 0); } now_perf = SDL_GetPerformanceCounter(); SDL_Log("1 million iterations of ticktock took %f ms\n", (double)((now_perf - start_perf) * 1000) / SDL_GetPerformanceFrequency());