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