1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37#define DEBUG_SUBSYSTEM S_LNET
38
39#include "selftest.h"
40
41
42
43
44
45
46
47
48#define STTIMER_MINPOLL 3
49#define STTIMER_SLOTTIME BIT(STTIMER_MINPOLL)
50#define STTIMER_SLOTTIMEMASK (~(STTIMER_SLOTTIME - 1))
51#define STTIMER_NSLOTS BIT(7)
52#define STTIMER_SLOT(t) (&stt_data.stt_hash[(((t) >> STTIMER_MINPOLL) & \
53 (STTIMER_NSLOTS - 1))])
54
55static struct st_timer_data {
56 spinlock_t stt_lock;
57 unsigned long stt_prev_slot;
58
59
60 struct list_head stt_hash[STTIMER_NSLOTS];
61 int stt_shuttingdown;
62 wait_queue_head_t stt_waitq;
63 int stt_nthreads;
64} stt_data;
65
66void
67stt_add_timer(struct stt_timer *timer)
68{
69 struct list_head *pos;
70
71 spin_lock(&stt_data.stt_lock);
72
73 LASSERT(stt_data.stt_nthreads > 0);
74 LASSERT(!stt_data.stt_shuttingdown);
75 LASSERT(timer->stt_func);
76 LASSERT(list_empty(&timer->stt_list));
77 LASSERT(timer->stt_expires > ktime_get_real_seconds());
78
79
80 list_for_each_prev(pos, STTIMER_SLOT(timer->stt_expires)) {
81 struct stt_timer *old = list_entry(pos, struct stt_timer,
82 stt_list);
83
84 if (timer->stt_expires >= old->stt_expires)
85 break;
86 }
87 list_add(&timer->stt_list, pos);
88
89 spin_unlock(&stt_data.stt_lock);
90}
91
92
93
94
95
96
97
98
99
100
101int
102stt_del_timer(struct stt_timer *timer)
103{
104 int ret = 0;
105
106 spin_lock(&stt_data.stt_lock);
107
108 LASSERT(stt_data.stt_nthreads > 0);
109 LASSERT(!stt_data.stt_shuttingdown);
110
111 if (!list_empty(&timer->stt_list)) {
112 ret = 1;
113 list_del_init(&timer->stt_list);
114 }
115
116 spin_unlock(&stt_data.stt_lock);
117 return ret;
118}
119
120
121static int
122stt_expire_list(struct list_head *slot, time64_t now)
123{
124 int expired = 0;
125 struct stt_timer *timer;
126
127 while (!list_empty(slot)) {
128 timer = list_entry(slot->next, struct stt_timer, stt_list);
129
130 if (timer->stt_expires > now)
131 break;
132
133 list_del_init(&timer->stt_list);
134 spin_unlock(&stt_data.stt_lock);
135
136 expired++;
137 (*timer->stt_func) (timer->stt_data);
138
139 spin_lock(&stt_data.stt_lock);
140 }
141
142 return expired;
143}
144
145static int
146stt_check_timers(unsigned long *last)
147{
148 int expired = 0;
149 time64_t now;
150 unsigned long this_slot;
151
152 now = ktime_get_real_seconds();
153 this_slot = now & STTIMER_SLOTTIMEMASK;
154
155 spin_lock(&stt_data.stt_lock);
156
157 while (cfs_time_aftereq(this_slot, *last)) {
158 expired += stt_expire_list(STTIMER_SLOT(this_slot), now);
159 this_slot = cfs_time_sub(this_slot, STTIMER_SLOTTIME);
160 }
161
162 *last = now & STTIMER_SLOTTIMEMASK;
163 spin_unlock(&stt_data.stt_lock);
164 return expired;
165}
166
167static int
168stt_timer_main(void *arg)
169{
170 int rc = 0;
171
172 cfs_block_allsigs();
173
174 while (!stt_data.stt_shuttingdown) {
175 stt_check_timers(&stt_data.stt_prev_slot);
176
177 rc = wait_event_timeout(stt_data.stt_waitq,
178 stt_data.stt_shuttingdown,
179 cfs_time_seconds(STTIMER_SLOTTIME));
180 }
181
182 spin_lock(&stt_data.stt_lock);
183 stt_data.stt_nthreads--;
184 spin_unlock(&stt_data.stt_lock);
185 return rc;
186}
187
188static int
189stt_start_timer_thread(void)
190{
191 struct task_struct *task;
192
193 LASSERT(!stt_data.stt_shuttingdown);
194
195 task = kthread_run(stt_timer_main, NULL, "st_timer");
196 if (IS_ERR(task))
197 return PTR_ERR(task);
198
199 spin_lock(&stt_data.stt_lock);
200 stt_data.stt_nthreads++;
201 spin_unlock(&stt_data.stt_lock);
202 return 0;
203}
204
205int
206stt_startup(void)
207{
208 int rc = 0;
209 int i;
210
211 stt_data.stt_shuttingdown = 0;
212 stt_data.stt_prev_slot = ktime_get_real_seconds() & STTIMER_SLOTTIMEMASK;
213
214 spin_lock_init(&stt_data.stt_lock);
215 for (i = 0; i < STTIMER_NSLOTS; i++)
216 INIT_LIST_HEAD(&stt_data.stt_hash[i]);
217
218 stt_data.stt_nthreads = 0;
219 init_waitqueue_head(&stt_data.stt_waitq);
220 rc = stt_start_timer_thread();
221 if (rc)
222 CERROR("Can't spawn timer thread: %d\n", rc);
223
224 return rc;
225}
226
227void
228stt_shutdown(void)
229{
230 int i;
231
232 spin_lock(&stt_data.stt_lock);
233
234 for (i = 0; i < STTIMER_NSLOTS; i++)
235 LASSERT(list_empty(&stt_data.stt_hash[i]));
236
237 stt_data.stt_shuttingdown = 1;
238
239 wake_up(&stt_data.stt_waitq);
240 lst_wait_until(!stt_data.stt_nthreads, stt_data.stt_lock,
241 "waiting for %d threads to terminate\n",
242 stt_data.stt_nthreads);
243
244 spin_unlock(&stt_data.stt_lock);
245}
246