X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Ftimer%2Ftimer.c;h=2c58a4e5238df00b7bd88abc8cee76feb284eab2;hb=63f770591286a5a61ef2857377eeab5e0e75d115;hp=f0e017ba6ed8decba4ac4abcf0ecce07f01abf48;hpb=bd9a48e7ffca063e21d580e9e0d94b1691c03687;p=ccan diff --git a/ccan/timer/timer.c b/ccan/timer/timer.c index f0e017ba..2c58a4e5 100644 --- a/ccan/timer/timer.c +++ b/ccan/timer/timer.c @@ -131,7 +131,10 @@ static void add_level(struct timers *timers, unsigned int level) timer_add_raw(timers, t); } +/* We don't need to search past the first at level 0, since the + * bucket range is 1; they're all the same. */ static const struct timer *find_first(const struct list_head *list, + unsigned int level, const struct timer *prev) { struct timer *t; @@ -139,67 +142,56 @@ static const struct timer *find_first(const struct list_head *list, list_for_each(list, t, list) { if (!prev || t->time < prev->time) prev = t; + if (level == 0) + break; } return prev; } -static const struct timer *get_first(const struct timers *timers) +/* FIXME: Suboptimal */ +static const struct timer *brute_force_first(const struct timers *timers) { - unsigned int level, i, off; - bool need_next; - uint64_t base; + unsigned int l, i; const struct timer *found = NULL; - struct list_head *h; - - if (timers->first < timers->base) { - base = timers->base; - level = 0; - } else { - /* May not be accurate, due to timer_del / expiry. */ - level = level_of(timers, timers->first); - base = timers->first >> (TIMER_LEVEL_BITS * level); - } - -next: - if (!timers->level[level]) - return find_first(&timers->far, NULL); - - need_next = false; - off = base % PER_LEVEL; - for (i = 0; i < PER_LEVEL; i++) { - h = &timers->level[level]->list[(i+off) % PER_LEVEL]; - - if (!list_empty(h)) - break; - /* We haven't cascaded yet, so if we wrap, we'll need to - * check next level, too. */ - if (i + off == PER_LEVEL) - need_next = true; - } - if (i == PER_LEVEL) { - level++; - base >>= TIMER_LEVEL_BITS; - goto next; + for (l = 0; l < ARRAY_SIZE(timers->level) && timers->level[l]; l++) { + for (i = 0; i < PER_LEVEL; i++) + found = find_first(&timers->level[l]->list[i], l, + found); } - /* Level 0 is exact, so they're all the same. */ - if (level == 0) - found = list_top(h, struct timer, list); + found = find_first(&timers->far, -1U, found); + return found; +} + +static const struct timer *get_first(const struct timers *timers) +{ + uint64_t time; + + /* Where can we start from? */ + if (timers->first < timers->base) + time = timers->base; else - found = find_first(h, NULL); - - if (need_next) { - if (!timers->level[level+1]) { - found = find_first(&timers->far, found); - } else { - base >>= TIMER_LEVEL_BITS; - off = base % PER_LEVEL; - h = &timers->level[level+1]->list[off]; - found = find_first(h, found); + time = timers->first; + + /* We can have just far timers, for example. */ + if (timers->level[0]) { + /* First search rest of lower buckets; we've already spilled + * so if we find one there we don't need to search further. */ + unsigned int i, off = time % PER_LEVEL; + + for (i = off; i < PER_LEVEL; i++) { + struct list_head *h = &timers->level[0]->list[i]; + if (!list_empty(h)) + return find_first(h, 0, NULL); } } - return found; + + /* From here on, we're searching non-normalized parts of the + * data structure, which is much subtler. + * + * So we brute force. */ + return brute_force_first(timers); } static bool update_first(struct timers *timers)