1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2001, 2002 Cluster File Systems, Inc.
5 * Author: Isaac Huang <isaac@clusterfs.com>
9 #define DEBUG_SUBSYSTEM S_LNET
11 #include <libcfs/kp30.h>
12 #include <libcfs/libcfs.h>
13 #include <lnet/lib-lnet.h>
19 * Timers are implemented as a sorted queue of expiry times. The queue
20 * is slotted, with each slot holding timers which expire in a
21 * 2**STTIMER_MINPOLL (8) second period. The timers in each slot are
22 * sorted by increasing expiry time. The number of slots is 2**7 (128),
23 * to cover a time period of 1024 seconds into the future before wrapping.
25 #define STTIMER_MINPOLL 3 /* log2 min poll interval (8 s) */
26 #define STTIMER_SLOTTIME (1 << STTIMER_MINPOLL)
27 #define STTIMER_SLOTTIMEMASK (~(STTIMER_SLOTTIME - 1))
28 #define STTIMER_NSLOTS (1 << 7)
29 #define STTIMER_SLOT(t) (&stt_data.stt_hash[(((t) >> STTIMER_MINPOLL) & \
30 (STTIMER_NSLOTS - 1))])
32 struct st_timer_data {
34 /* start time of the slot processed previously */
35 cfs_time_t stt_prev_slot;
36 struct list_head stt_hash[STTIMER_NSLOTS];
39 cfs_waitq_t stt_waitq;
45 stt_add_timer (stt_timer_t *timer)
47 struct list_head *pos;
49 spin_lock(&stt_data.stt_lock);
52 LASSERT (stt_data.stt_nthreads > 0);
54 LASSERT (!stt_data.stt_shuttingdown);
55 LASSERT (timer->stt_func != NULL);
56 LASSERT (list_empty(&timer->stt_list));
57 LASSERT (cfs_time_after(timer->stt_expires, cfs_time_current_sec()));
59 /* a simple insertion sort */
60 list_for_each_prev (pos, STTIMER_SLOT(timer->stt_expires)) {
61 stt_timer_t *old = list_entry(pos, stt_timer_t, stt_list);
63 if (cfs_time_aftereq(timer->stt_expires, old->stt_expires))
66 list_add(&timer->stt_list, pos);
68 spin_unlock(&stt_data.stt_lock);
72 * The function returns whether it has deactivated a pending timer or not.
73 * (ie. del_timer() of an inactive timer returns 0, del_timer() of an
74 * active timer returns 1.)
77 * When 0 is returned, it is possible that timer->stt_func _is_ running on
81 stt_del_timer (stt_timer_t *timer)
85 spin_lock(&stt_data.stt_lock);
88 LASSERT (stt_data.stt_nthreads > 0);
90 LASSERT (!stt_data.stt_shuttingdown);
92 if (!list_empty(&timer->stt_list)) {
94 list_del_init(&timer->stt_list);
97 spin_unlock(&stt_data.stt_lock);
101 /* called with stt_data.stt_lock held */
103 stt_expire_list (struct list_head *slot, cfs_time_t now)
108 while (!list_empty(slot)) {
109 timer = list_entry(slot->next, stt_timer_t, stt_list);
111 if (cfs_time_after(timer->stt_expires, now))
114 list_del_init(&timer->stt_list);
115 spin_unlock(&stt_data.stt_lock);
118 (*timer->stt_func) (timer->stt_data);
120 spin_lock(&stt_data.stt_lock);
127 stt_check_timers (cfs_time_t *last)
131 cfs_time_t this_slot;
133 now = cfs_time_current_sec();
134 this_slot = now & STTIMER_SLOTTIMEMASK;
136 spin_lock(&stt_data.stt_lock);
138 while (cfs_time_aftereq(this_slot, *last)) {
139 expired += stt_expire_list(STTIMER_SLOT(this_slot), now);
140 this_slot = cfs_time_sub(this_slot, STTIMER_SLOTTIME);
143 *last = now & STTIMER_SLOTTIMEMASK;
144 spin_unlock(&stt_data.stt_lock);
151 stt_timer_main (void *arg)
155 cfs_daemonize("st_timer");
158 while (!stt_data.stt_shuttingdown) {
159 stt_check_timers(&stt_data.stt_prev_slot);
161 wait_event_timeout(stt_data.stt_waitq,
162 stt_data.stt_shuttingdown,
163 cfs_time_seconds(STTIMER_SLOTTIME));
166 spin_lock(&stt_data.stt_lock);
167 stt_data.stt_nthreads--;
168 spin_unlock(&stt_data.stt_lock);
173 stt_start_timer_thread (void)
177 LASSERT (!stt_data.stt_shuttingdown);
179 pid = cfs_kernel_thread(stt_timer_main, NULL, 0);
183 spin_lock(&stt_data.stt_lock);
184 stt_data.stt_nthreads++;
185 spin_unlock(&stt_data.stt_lock);
189 #else /* !__KERNEL__ */
192 stt_check_events (void)
194 return stt_check_timers(&stt_data.stt_prev_slot);
198 stt_poll_interval (void)
200 return STTIMER_SLOTTIME;
211 stt_data.stt_shuttingdown = 0;
212 stt_data.stt_prev_slot = cfs_time_current_sec() & STTIMER_SLOTTIMEMASK;
214 spin_lock_init(&stt_data.stt_lock);
215 for (i = 0; i < STTIMER_NSLOTS; i++)
216 CFS_INIT_LIST_HEAD(&stt_data.stt_hash[i]);
219 stt_data.stt_nthreads = 0;
220 cfs_waitq_init(&stt_data.stt_waitq);
221 rc = stt_start_timer_thread();
223 CERROR ("Can't spawn timer thread: %d\n", rc);
234 spin_lock(&stt_data.stt_lock);
236 for (i = 0; i < STTIMER_NSLOTS; i++)
237 LASSERT (list_empty(&stt_data.stt_hash[i]));
239 stt_data.stt_shuttingdown = 1;
242 cfs_waitq_signal(&stt_data.stt_waitq);
243 lst_wait_until(stt_data.stt_nthreads == 0, stt_data.stt_lock,
244 "waiting for %d threads to terminate\n",
245 stt_data.stt_nthreads);
248 spin_unlock(&stt_data.stt_lock);