diff options
| -rw-r--r-- | src/common/backend.c | 16 | ||||
| -rw-r--r-- | src/common/loop.c | 9 | ||||
| -rw-r--r-- | src/common/loop.h | 2 | ||||
| -rw-r--r-- | tests/common/test_timers.c | 11 |
4 files changed, 34 insertions, 4 deletions
diff --git a/src/common/backend.c b/src/common/backend.c index ad4d908..4c755bd 100644 --- a/src/common/backend.c +++ b/src/common/backend.c @@ -1,4 +1,5 @@ #include "backend.h" +#include "loop.h" #include <errno.h> #include <stdlib.h> @@ -369,6 +370,15 @@ yasl_timer_id yasl_surface_add_timer(struct yasl_surface *s, uint64_t interval_n yasl_timer_id id = yasl_loop_add_timer(s->display->loop, interval_ns, cb, ud); if (!id) return 0; + /* A one-shot timer retires itself in the loop. Drop retired ids before + * the list grows, so the list holds only armed timers. */ + if (s->timer_count >= s->timer_capacity) { + int kept = 0; + for (int i = 0; i < s->timer_count; i++) + if (yasl_loop_timer_armed(s->display->loop, s->timers[i])) + s->timers[kept++] = s->timers[i]; + s->timer_count = kept; + } if (s->timer_count >= s->timer_capacity) { int new_cap = s->timer_capacity ? s->timer_capacity * 2 : 4; yasl_timer_id *nt = realloc(s->timers, (size_t)new_cap * sizeof(*nt)); @@ -388,10 +398,8 @@ bool yasl_surface_del_timer(struct yasl_surface *s, yasl_timer_id id) if (!s || id == 0) return false; for (int i = 0; i < s->timer_count; i++) { if (s->timers[i] == id) { - s->timers[i] = 0; - if (s->display && s->display->loop) - yasl_loop_del_timer(s->display->loop, id); - return true; + s->timers[i] = s->timers[--s->timer_count]; + return s->display && yasl_loop_del_timer(s->display->loop, id); } } return false; diff --git a/src/common/loop.c b/src/common/loop.c index 3815e91..a63df16 100644 --- a/src/common/loop.c +++ b/src/common/loop.c @@ -208,6 +208,15 @@ static void timer_cleanup_deleted(struct yasl_loop *l) l->timer_count = dest; } +bool yasl_loop_timer_armed(const struct yasl_loop *l, yasl_timer_id id) +{ + if (!l || id == 0) return false; + for (int i = 0; i < l->timer_count; i++) + if (l->timers[i].id == id) + return !l->timers[i].deleted; + return false; +} + int yasl_loop_next_timeout_ms(const struct yasl_loop *l) { if (!l || l->timer_count <= 0) return -1; diff --git a/src/common/loop.h b/src/common/loop.h index 579fa2c..663417a 100644 --- a/src/common/loop.h +++ b/src/common/loop.h @@ -4,5 +4,7 @@ #include "yasl/loop.h" int yasl_loop_next_timeout_ms(const struct yasl_loop *l); +/* Whether id is armed: added, not deleted, and not retired by its callback. */ +bool yasl_loop_timer_armed(const struct yasl_loop *l, yasl_timer_id id); #endif /* YASL_COMMON_LOOP_H */ diff --git a/tests/common/test_timers.c b/tests/common/test_timers.c index d02bfe9..4e95c5a 100644 --- a/tests/common/test_timers.c +++ b/tests/common/test_timers.c @@ -264,6 +264,17 @@ static void test_surface_timers(void) yasl_display_dispatch(d, 10); assert(sctx.count == count_before); + /* A fired one-shot surface timer is retired, as a loop timer is. Many + * of them stay retired after the surface's id list compacts. */ + for (int i = 0; i < 64; i++) { + struct test_ctx octx = {0}; + octx.id = yasl_surface_add_timer(s, 1000000ull, oneshot_cb, &octx); + assert(octx.id > 0); + while (octx.count == 0) + yasl_display_dispatch(d, 50); + assert(!yasl_surface_del_timer(s, octx.id)); + } + /* Surface timer auto-cleanup on surface destruction */ struct test_ctx sctx2 = {0}; sctx2.id = yasl_surface_add_timer(s, 2000000ull, surface_timer_repeat_cb, &sctx2); |
