From 2a0b3f79843f92a33d7286424182f57c48f26dee Mon Sep 17 00:00:00 2001 From: Anotra Date: Sun, 3 Apr 2022 15:57:13 -0400 Subject: [PATCH 1/5] fix(discord-client.c): internal timer should update poll time --- src/discord-client.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/discord-client.c b/src/discord-client.c index ff902dedd..ecc2f3d88 100644 --- a/src/discord-client.c +++ b/src/discord-client.c @@ -346,14 +346,18 @@ discord_run(struct discord *client) poll_time = (int)(client->wakeup_timer.next - now); } } - int64_t key; - if (priority_queue_peek(client->timers.user.q, &key, NULL)) { - key /= 1000; - if (key >= 0) { - if (key <= now) { - poll_time = 0; - } else if (key - now < poll_time) { - poll_time = (int)(key - now); + struct discord_timers *const timers[] = + { &client->timers.internal, &client->timers.user }; + for (unsigned i = 0; i < sizeof timers / sizeof *timers; i++) { + int64_t trigger_us, trigger_ms; + if (priority_queue_peek(timers[i]->q, &trigger_us, NULL)) { + trigger_ms = trigger_us / 1000; + if (trigger_ms >= 0) { + if (trigger_ms <= now) { + poll_time = 0; + } else if (trigger_ms - now < poll_time) { + poll_time = (int)(trigger_ms - now); + } } } } @@ -373,8 +377,9 @@ discord_run(struct discord *client) break; now = (int64_t)cog_timestamp_ms(); - discord_timers_run(client, &client->timers.internal); - discord_timers_run(client, &client->timers.user); + + for (unsigned i = 0; i < sizeof timers / sizeof *timers; i++) + discord_timers_run(client, timers[i]); /* check for pending wakeup timers */ if (client->wakeup_timer.next != -1 From 80107950a5e3651a08c4757f7519f7ee31211db1 Mon Sep 17 00:00:00 2001 From: Anotra Date: Sun, 3 Apr 2022 16:13:33 -0400 Subject: [PATCH 2/5] feat(discord-timers): add discord_internal_timer functions --- include/discord-internal.h | 24 ++++++++++++++++++++++++ src/discord-timer.c | 30 +++++++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/include/discord-internal.h b/include/discord-internal.h index 72e23abf2..ae17604df 100644 --- a/include/discord-internal.h +++ b/include/discord-internal.h @@ -728,6 +728,30 @@ unsigned _discord_timer_ctl( struct discord_timers *timers, struct discord_timer *timer); +/** + * @brief modifies or creates a timer + * + * @param client the client created with discord_init() + * @param timer the timer that should be modified + * @return unsigned the id of the timer + */ +unsigned discord_internal_timer_ctl( + struct discord *client, + struct discord_timer *timer); + +/** + * @brief creates a one shot timer that automatically + * deletes itself upon completion + * + * @param client the client created with discord_init() + * @param cb the callback that should be called when timer triggers + * @param data user data + * @param delay delay before timer should start in milliseconds + * @return unsigned + */ +unsigned discord_internal_timer(struct discord *client, discord_ev_timer cb, + void *data, int64_t delay); + /** @} DiscordInternalTimer */ /** * @brief The Discord client handler diff --git a/src/discord-timer.c b/src/discord-timer.c index 4a5e5b657..091371bb4 100644 --- a/src/discord-timer.c +++ b/src/discord-timer.c @@ -112,14 +112,23 @@ discord_timers_run(struct discord *client, struct discord_timers *timers) priority_queue_update(timers->q, timer.id, &next, &timer); } } + unsigned discord_timer_ctl(struct discord *client, struct discord_timer *timer) { return _discord_timer_ctl(client, &client->timers.user, timer); } -unsigned discord_timer(struct discord *client, discord_ev_timer cb, - void *data, int64_t delay) +unsigned +discord_internal_timer_ctl(struct discord *client, + struct discord_timer *timer) +{ + return _discord_timer_ctl(client, &client->timers.internal, timer); +} + +static unsigned +_discord_timer(struct discord *client, struct discord_timers *timers, + discord_ev_timer cb, void *data, int64_t delay) { struct discord_timer timer = { .cb = cb, @@ -127,5 +136,20 @@ unsigned discord_timer(struct discord *client, discord_ev_timer cb, .delay = delay, .flags = DISCORD_TIMER_DELETE_AUTO, }; - return discord_timer_ctl(client, &timer); + return _discord_timer_ctl(client, timers, &timer); +} + +unsigned +discord_timer(struct discord *client, discord_ev_timer cb, + void *data, int64_t delay) +{ + return _discord_timer(client, &client->timers.user, cb, data, delay); +} + + +unsigned +discord_internal_timer(struct discord *client, discord_ev_timer cb, + void *data, int64_t delay) +{ + return _discord_timer(client, &client->timers.internal, cb, data, delay); } From 22e94210fe596db027ae427f32ee0b6da7516f4e Mon Sep 17 00:00:00 2001 From: Anotra Date: Sun, 3 Apr 2022 16:40:46 -0400 Subject: [PATCH 3/5] feat(discord-timers.c): added DISCORD_TIMERS_DONT_UPDATE flag to prevent auto updating from the timer callback --- include/discord-internal.h | 1 + include/discord.h | 2 ++ src/discord-timer.c | 10 ++++++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/discord-internal.h b/include/discord-internal.h index ae17604df..32b933241 100644 --- a/include/discord-internal.h +++ b/include/discord-internal.h @@ -691,6 +691,7 @@ void discord_gateway_send_presence_update(struct discord_gateway *gw); struct discord_timers { priority_queue *q; + struct discord_timer *currently_being_run; }; /** diff --git a/include/discord.h b/include/discord.h index cce2307c5..768e22dad 100644 --- a/include/discord.h +++ b/include/discord.h @@ -310,6 +310,8 @@ enum discord_timer_flags { DISCORD_TIMER_DELETE_AUTO = 1 << 2, /** timer has been canceled. user should cleanup only */ DISCORD_TIMER_CANCELED = 1 << 3, + /** used in the timer callback to skip update phase */ + DISCORD_TIMER_DONT_UPDATE = 1 << 4, }; /** diff --git a/src/discord-timer.c b/src/discord-timer.c index 091371bb4..7ee80d5dc 100644 --- a/src/discord-timer.c +++ b/src/discord-timer.c @@ -69,6 +69,9 @@ _discord_timer_ctl( if (!timer->id) { return priority_queue_push(timers->q, &now, timer); } else { + if (timers->currently_being_run + && timers->currently_being_run->id == timer->id) + timers->currently_being_run->flags |= DISCORD_TIMER_DONT_UPDATE; if (priority_queue_update(timers->q, timer->id, &now, timer)) return timer->id; return 0; @@ -86,10 +89,11 @@ discord_timers_run(struct discord *client, struct discord_timers *timers) { int64_t now = (int64_t)discord_timestamp_us(client); struct discord_timer timer; + timers->currently_being_run = &timer; for (int64_t trigger; (timer.id = priority_queue_peek(timers->q, &trigger, &timer));) { - if (trigger > now || trigger == -1) return; + if (trigger > now || trigger == -1) break; TIMER_TRY_DELETE @@ -108,9 +112,11 @@ discord_timers_run(struct discord *client, struct discord_timers *timers) } if (priority_queue_peek(timers->q, NULL, NULL) != timer.id) continue; - + if (timer.flags & DISCORD_TIMER_DONT_UPDATE) + continue; priority_queue_update(timers->q, timer.id, &next, &timer); } + timers->currently_being_run = NULL; } unsigned From e23959e7399b6f40c9131724b0d076192ca72ea3 Mon Sep 17 00:00:00 2001 From: Anotra Date: Sun, 3 Apr 2022 16:57:55 -0400 Subject: [PATCH 4/5] refactor(discord-client): convert wakeup timer to use a real timer --- include/discord-internal.h | 4 ++-- src/discord-client.c | 44 ++++++++++++++++++++------------------ 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/include/discord-internal.h b/include/discord-internal.h index 32b933241..b7ab5a018 100644 --- a/include/discord-internal.h +++ b/include/discord-internal.h @@ -786,8 +786,8 @@ struct discord { struct { /** callback to be triggered on timer's timeout */ discord_ev_idle cb; - /** when `cb` should be called in milliseconds */ - int64_t next; + /** the id of the wake timer */ + unsigned id; } wakeup_timer; /** triggers when idle. */ diff --git a/src/discord-client.c b/src/discord-client.c index ecc2f3d88..adc84dded 100644 --- a/src/discord-client.c +++ b/src/discord-client.c @@ -288,20 +288,37 @@ discord_set_event_scheduler(struct discord *client, client->gw.cmds.scheduler = callback; } + +static void +discord_wake_timer_cb(struct discord *client, struct discord_timer *timer) { + if (~timer->flags & DISCORD_TIMER_CANCELED && client->wakeup_timer.cb) + client->wakeup_timer.cb(client); +} + void discord_set_next_wakeup(struct discord *client, int64_t delay) { - if (delay == -1) - client->wakeup_timer.next = -1; - else if (delay >= 0) - client->wakeup_timer.next = (int64_t)cog_timestamp_ms() + delay; + unsigned id = discord_internal_timer_ctl(client, + &(struct discord_timer) { + .id = client->wakeup_timer.id, + .cb = discord_wake_timer_cb, + .delay = delay, + }); + client->wakeup_timer.id = id; } void discord_set_on_wakeup(struct discord *client, discord_ev_idle callback) { client->wakeup_timer.cb = callback; - client->wakeup_timer.next = -1; + if (client->wakeup_timer.id) { + discord_internal_timer_ctl(client, + &(struct discord_timer) { + .id = client->wakeup_timer.id, + .cb = discord_wake_timer_cb, + .delay = -1, + }); + } } void @@ -337,15 +354,9 @@ discord_run(struct discord *client) now = (int64_t)cog_timestamp_ms(); - if (!client->on_idle) { + if (!client->on_idle) poll_time = now < next_run ? (int)(next_run - now) : 0; - if (client->wakeup_timer.next != -1 - && client->wakeup_timer.next <= now + poll_time) - { - poll_time = (int)(client->wakeup_timer.next - now); - } - } struct discord_timers *const timers[] = { &client->timers.internal, &client->timers.user }; for (unsigned i = 0; i < sizeof timers / sizeof *timers; i++) { @@ -376,18 +387,9 @@ discord_run(struct discord *client) if (CCORD_OK != (code = io_poller_perform(client->io_poller))) break; - now = (int64_t)cog_timestamp_ms(); - for (unsigned i = 0; i < sizeof timers / sizeof *timers; i++) discord_timers_run(client, timers[i]); - /* check for pending wakeup timers */ - if (client->wakeup_timer.next != -1 - && now >= client->wakeup_timer.next) { - client->wakeup_timer.next = -1; - if (client->wakeup_timer.cb) client->wakeup_timer.cb(client); - } - if (next_run <= now) { if (CCORD_OK != (code = discord_gateway_perform(&client->gw))) break; From f80ce89d5783aee5d024fa44ae6394ef93c1b3e5 Mon Sep 17 00:00:00 2001 From: Anotra Date: Sun, 3 Apr 2022 17:11:22 -0400 Subject: [PATCH 5/5] fix(discord-client.c): prevent a disabled timer from creating a busy loop --- src/discord-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/discord-client.c b/src/discord-client.c index adc84dded..14b519426 100644 --- a/src/discord-client.c +++ b/src/discord-client.c @@ -363,7 +363,7 @@ discord_run(struct discord *client) int64_t trigger_us, trigger_ms; if (priority_queue_peek(timers[i]->q, &trigger_us, NULL)) { trigger_ms = trigger_us / 1000; - if (trigger_ms >= 0) { + if (trigger_us >= 0) { if (trigger_ms <= now) { poll_time = 0; } else if (trigger_ms - now < poll_time) {