Skip to content

Commit

Permalink
timer: fix timeout over about 524s do not work as expected
Browse files Browse the repository at this point in the history
The problem is revealed by yangxingwu in pr iqiyi#901 and the fix
is fetched from pr iqiyi#29 authored by yangxingwu.
  • Loading branch information
ywc689 committed Sep 19, 2023
1 parent 6e4bbfe commit af249ea
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 18 deletions.
1 change: 1 addition & 0 deletions include/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ struct dpvs_timer {
* 'interval' for periodic timer.
*/
dpvs_tick_t delay;
dpvs_tick_t left;
};

dpvs_tick_t timeval_to_ticks(const struct timeval *tv);
Expand Down
39 changes: 21 additions & 18 deletions src/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ static int __dpvs_timer_sched(struct timer_scheduler *sched,
timer->delay = 1;
}

timer->left = timer->delay;
/* add to corresponding wheel, from higher level to lower. */
for (level = LEVEL_DEPTH - 1; level >= 0; level--) {
off = timer->delay / get_level_ticks(level);
Expand All @@ -196,6 +197,10 @@ static int __dpvs_timer_sched(struct timer_scheduler *sched,
#ifdef CONFIG_TIMER_DEBUG
assert(timer->handler == handler);
#endif
/* store the remainder */
timer->left = timer->left % get_level_ticks(level);
for (level = level - 1; level >= 0; level--)
timer->left += sched->cursors[level] * get_level_ticks(level);
return EDPVS_OK;
}
}
Expand Down Expand Up @@ -285,7 +290,7 @@ static void rte_timer_tick_cb(struct rte_timer *tim, void *arg)
struct timer_scheduler *sched = arg;
struct dpvs_timer *timer;
struct list_head *head;
uint64_t left, hash, off, remainder;
uint64_t hash, off;
int level, lower;
uint32_t *cursor;
bool carry;
Expand Down Expand Up @@ -314,36 +319,34 @@ static void rte_timer_tick_cb(struct rte_timer *tim, void *arg)
while (!list_empty(head)) {
timer = list_first_entry(head, struct dpvs_timer, list);
/* is all lower levels ticks empty ? */
left = timer->delay % get_level_ticks(level);
if (!left) {
if (!timer->left) {
timer_expire(sched, timer);
} else {
/* drop to lower level wheel, note it may not drop to
* "next" lower level wheel. */
list_del(&timer->list);

lower = level;
remainder = timer->delay % get_level_ticks(level);
while (--lower >= 0) {
off = remainder / get_level_ticks(lower);
if (!off)
continue; /* next lower level */

hash = (sched->cursors[lower] + off) % LEVEL_SIZE;
list_add_tail(&timer->list, &sched->hashs[lower][hash]);
break;
for (lower = level; lower >= 0; lower--) {
off = timer->left / get_level_ticks(lower);
if (off > 0) {
hash = (sched->cursors[lower] + off) % LEVEL_SIZE;
list_add_tail(&timer->list, &sched->hashs[lower][hash]);
/*
* store the remainder
* all lower cursor must be 0
* so it's not necessary to calculate the offset
* see __dpvs_timer_sched for details
*/
timer->left = timer->left % get_level_ticks(lower);
break;
}
}

assert(lower >= 0);
}
}

if (!carry)
break;
}
timer_sched_unlock(sched);

return;
}

static int timer_init_schedler(struct timer_scheduler *sched, lcoreid_t cid)
Expand Down

0 comments on commit af249ea

Please sign in to comment.