Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * Timer Wheel |
4 | | * Copyright (C) 2016 Cumulus Networks, Inc. |
5 | | * Donald Sharp |
6 | | */ |
7 | | #include "zebra.h" |
8 | | #include "linklist.h" |
9 | | #include "frrevent.h" |
10 | | #include "memory.h" |
11 | | #include "wheel.h" |
12 | | #include "log.h" |
13 | | |
14 | 8 | DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL, "Timer Wheel"); |
15 | 8 | DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL_LIST, "Timer Wheel Slot List"); |
16 | 8 | |
17 | 8 | static int debug_timer_wheel = 0; |
18 | 8 | |
19 | 8 | static void wheel_timer_thread(struct event *t); |
20 | 8 | |
21 | 8 | static void wheel_timer_thread_helper(struct event *t) |
22 | 8 | { |
23 | 0 | struct listnode *node, *nextnode; |
24 | 0 | unsigned long long curr_slot; |
25 | 0 | unsigned int slots_to_skip = 1; |
26 | 0 | struct timer_wheel *wheel; |
27 | 0 | void *data; |
28 | 0 |
|
29 | 0 | wheel = EVENT_ARG(t); |
30 | 0 |
|
31 | 0 | wheel->curr_slot += wheel->slots_to_skip; |
32 | 0 |
|
33 | 0 | curr_slot = wheel->curr_slot % wheel->slots; |
34 | 0 |
|
35 | 0 | if (debug_timer_wheel) |
36 | 0 | zlog_debug("%s: Wheel Slot: %lld(%lld) count: %d", __func__, |
37 | 0 | wheel->curr_slot, curr_slot, |
38 | 0 | listcount(wheel->wheel_slot_lists[curr_slot])); |
39 | 0 |
|
40 | 0 | for (ALL_LIST_ELEMENTS(wheel->wheel_slot_lists[curr_slot], node, |
41 | 0 | nextnode, data)) |
42 | 0 | (*wheel->slot_run)(data); |
43 | 0 |
|
44 | 0 | while (list_isempty(wheel->wheel_slot_lists[(curr_slot + slots_to_skip) |
45 | 0 | % wheel->slots]) |
46 | 0 | && (curr_slot + slots_to_skip) % wheel->slots != curr_slot) |
47 | 0 | slots_to_skip++; |
48 | 0 |
|
49 | 0 | wheel->slots_to_skip = slots_to_skip; |
50 | 0 | event_add_timer_msec(wheel->master, wheel_timer_thread, wheel, |
51 | 0 | wheel->nexttime * slots_to_skip, &wheel->timer); |
52 | 0 | } |
53 | | |
54 | | static void wheel_timer_thread(struct event *t) |
55 | 0 | { |
56 | 0 | struct timer_wheel *wheel; |
57 | 0 |
|
58 | 0 | wheel = EVENT_ARG(t); |
59 | 0 |
|
60 | 0 | event_execute(wheel->master, wheel_timer_thread_helper, wheel, 0); |
61 | 0 | } |
62 | | |
63 | | struct timer_wheel *wheel_init(struct event_loop *master, int period, |
64 | | size_t slots, |
65 | | unsigned int (*slot_key)(const void *), |
66 | | void (*slot_run)(void *), const char *run_name) |
67 | 1 | { |
68 | 1 | struct timer_wheel *wheel; |
69 | 1 | size_t i; |
70 | | |
71 | 1 | wheel = XCALLOC(MTYPE_TIMER_WHEEL, sizeof(struct timer_wheel)); |
72 | | |
73 | 1 | wheel->name = XSTRDUP(MTYPE_TIMER_WHEEL, run_name); |
74 | 1 | wheel->slot_key = slot_key; |
75 | 1 | wheel->slot_run = slot_run; |
76 | | |
77 | 1 | wheel->period = period; |
78 | 1 | wheel->slots = slots; |
79 | 1 | wheel->curr_slot = 0; |
80 | 1 | wheel->master = master; |
81 | 1 | wheel->nexttime = period / slots; |
82 | | |
83 | 1 | wheel->wheel_slot_lists = XCALLOC(MTYPE_TIMER_WHEEL_LIST, |
84 | 1 | slots * sizeof(struct list *)); |
85 | 101 | for (i = 0; i < slots; i++) |
86 | 100 | wheel->wheel_slot_lists[i] = list_new(); |
87 | | |
88 | 1 | event_add_timer_msec(wheel->master, wheel_timer_thread, wheel, |
89 | 1 | wheel->nexttime, &wheel->timer); |
90 | | |
91 | 1 | return wheel; |
92 | 1 | } |
93 | | |
94 | | void wheel_delete(struct timer_wheel *wheel) |
95 | 0 | { |
96 | 0 | int i; |
97 | |
|
98 | 0 | for (i = 0; i < wheel->slots; i++) { |
99 | 0 | list_delete(&wheel->wheel_slot_lists[i]); |
100 | 0 | } |
101 | |
|
102 | 0 | EVENT_OFF(wheel->timer); |
103 | 0 | XFREE(MTYPE_TIMER_WHEEL_LIST, wheel->wheel_slot_lists); |
104 | 0 | XFREE(MTYPE_TIMER_WHEEL, wheel->name); |
105 | 0 | XFREE(MTYPE_TIMER_WHEEL, wheel); |
106 | 0 | } |
107 | | |
108 | | int wheel_add_item(struct timer_wheel *wheel, void *item) |
109 | 44.4k | { |
110 | 44.4k | long long slot; |
111 | | |
112 | 44.4k | slot = (*wheel->slot_key)(item); |
113 | | |
114 | 44.4k | if (debug_timer_wheel) |
115 | 0 | zlog_debug("%s: Inserting %p: %lld %lld", __func__, item, slot, |
116 | 44.4k | slot % wheel->slots); |
117 | 44.4k | listnode_add(wheel->wheel_slot_lists[slot % wheel->slots], item); |
118 | | |
119 | 44.4k | return 0; |
120 | 44.4k | } |
121 | | |
122 | | int wheel_remove_item(struct timer_wheel *wheel, void *item) |
123 | 43.9k | { |
124 | 43.9k | long long slot; |
125 | | |
126 | 43.9k | slot = (*wheel->slot_key)(item); |
127 | | |
128 | 43.9k | if (debug_timer_wheel) |
129 | 0 | zlog_debug("%s: Removing %p: %lld %lld", __func__, item, slot, |
130 | 43.9k | slot % wheel->slots); |
131 | 43.9k | listnode_delete(wheel->wheel_slot_lists[slot % wheel->slots], item); |
132 | | |
133 | 43.9k | return 0; |
134 | 43.9k | } |