Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timer Updates #56

Merged
merged 5 commits into from
Apr 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions include/discord-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

/**
Expand Down Expand Up @@ -728,6 +729,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
Expand Down Expand Up @@ -761,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. */
Expand Down
2 changes: 2 additions & 0 deletions include/discord.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

/**
Expand Down
67 changes: 37 additions & 30 deletions src/discord-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -337,23 +354,21 @@ 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);
}
}
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_us >= 0) {
if (trigger_ms <= now) {
poll_time = 0;
} else if (trigger_ms - now < poll_time) {
poll_time = (int)(trigger_ms - now);
}
}
}
}
Expand All @@ -372,16 +387,8 @@ discord_run(struct discord *client)
if (CCORD_OK != (code = io_poller_perform(client->io_poller)))
break;

now = (int64_t)cog_timestamp_ms();
discord_timers_run(client, &client->timers.internal);
discord_timers_run(client, &client->timers.user);

/* 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);
}
for (unsigned i = 0; i < sizeof timers / sizeof *timers; i++)
discord_timers_run(client, timers[i]);

if (next_run <= now) {
if (CCORD_OK != (code = discord_gateway_perform(&client->gw)))
Expand Down
40 changes: 35 additions & 5 deletions src/discord-timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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

Expand All @@ -108,24 +112,50 @@ 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
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,
.data = data,
.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);
}