@@ -43,6 +43,7 @@ int timer_event_wrapper_cont(lua_State *L, [[maybe_unused]] int status)
4343// Forward declarations for timer wrapper management
4444static void register_timer_wrapper (lua_State *L, lua_LLTimers *lltimers);
4545static void unregister_timer_wrapper (lua_State *L, lua_LLTimers *lltimers);
46+ static void schedule_next_tick (lua_State *L, lua_LLTimers *lltimers);
4647
4748static void lltimers_dtor (lua_State *L, void *data)
4849{
@@ -144,12 +145,15 @@ static int lltimers_on(lua_State *L)
144145 // Add to the end of the timers array
145146 lua_rawseti (L, -2 , old_len + 1 );
146147
147- lua_pop (L, 1 ); // Pop timers array
148-
149148 // Register timer wrapper with LLEvents when adding first timer
150149 if (old_len == 0 )
151150 register_timer_wrapper (L, lltimers);
152151
152+ // Reschedule timer tick since we added a new timer
153+ schedule_next_tick (L, lltimers);
154+
155+ lua_pop (L, 1 ); // Pop timers array
156+
153157 // Return the passed-in handler so it can be unregistered later
154158 lua_pushvalue (L, 3 );
155159 return 1 ;
@@ -190,6 +194,10 @@ static int lltimers_once(lua_State *L)
190194
191195 // Add to the timers array
192196 lua_rawseti (L, -2 , old_len + 1 );
197+
198+ // Reschedule timer tick since we added a new timer
199+ schedule_next_tick (L, lltimers);
200+
193201 lua_pop (L, 1 ); // Pop timers array
194202
195203 // Register timer wrapper with LLEvents when adding first timer
@@ -247,10 +255,11 @@ static int lltimers_off(lua_State *L)
247255
248256 lua_pop (L, 1 ); // Pop timers array
249257
250- // Check if we just removed the last timer
251- if (found && len == 1 )
258+ // Reschedule timer tick since we may have removed a timer
259+ // (this will also unregister the wrapper if we removed the last timer)
260+ if (found)
252261 {
253- unregister_timer_wrapper (L, lltimers);
262+ schedule_next_tick (L, lltimers);
254263 }
255264
256265 lua_pushboolean (L, found);
@@ -313,23 +322,26 @@ static void unregister_timer_wrapper(lua_State *L, lua_LLTimers *lltimers)
313322}
314323
315324// Helper function to schedule the next timer tick
316- // Expects timers_tab to be on the stack at the given index
317- static void schedule_next_tick (lua_State *L)
325+ // Accepts LLTimers userdata as parameter and manages its own stack
326+ static void schedule_next_tick (lua_State *L, lua_LLTimers *lltimers )
318327{
319328 auto *sl_state = LUAU_GET_SL_VM_STATE (lua_mainthread (L));
320329
321330 if (!sl_state->setTimerEventCb )
322331 return ; // No callback set, can't schedule
323332
324- int len = lua_objlen (L, LIVE_TIMERS_ARRAY);
333+ // Get timers array on the stack
334+ lua_getref (L, lltimers->timers_tab_ref );
335+ int len = lua_objlen (L, -1 );
325336
326337 if (len == 0 )
327338 {
339+ lua_pop (L, 1 ); // Pop timers array
340+
328341 // No timers pending, unsubscribe from the parent timer event
329342 sl_state->setTimerEventCb (L, 0.0 );
330343
331344 // Unregister timer wrapper from LLEvents
332- auto *lltimers = (lua_LLTimers *)lua_touserdata (L, LLTIMERS_USERDATA);
333345 unregister_timer_wrapper (L, lltimers);
334346
335347 return ;
@@ -339,13 +351,15 @@ static void schedule_next_tick(lua_State *L)
339351 double min_time = HUGE_VAL;
340352 for (int i = 1 ; i <= len; i++)
341353 {
342- lua_rawgeti (L, LIVE_TIMERS_ARRAY , i);
354+ lua_rawgeti (L, - 1 , i); // Get timer from timers array
343355 lua_rawgeti (L, -1 , TIMER_NEXT_RUN);
344356 double next_run = lua_tonumber (L, -1 );
345357 lua_pop (L, 2 ); // Pop nextRun and timer data
346358 min_time = fmin (min_time, next_run);
347359 }
348360
361+ lua_pop (L, 1 ); // Pop timers array
362+
349363 // Get current time
350364 double current_time = sl_state->clockProvider ? sl_state->clockProvider (L) : 0.0 ;
351365
@@ -589,7 +603,8 @@ static int lltimers_tick_cont(lua_State *L, [[maybe_unused]]int status)
589603 }
590604
591605 // Done processing all timers, schedule the next tick
592- schedule_next_tick (L);
606+ auto *lltimers = (lua_LLTimers *)lua_touserdata (L, LLTIMERS_USERDATA);
607+ schedule_next_tick (L, lltimers);
593608
594609 return 0 ;
595610}
0 commit comments