4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
30 * Copyright (c) 2011, 2012, Intel Corporation.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 * lnet/selftest/timer.c
38 * Author: Isaac Huang <isaac@clusterfs.com>
41 #define DEBUG_SUBSYSTEM S_LNET
47 * Timers are implemented as a sorted queue of expiry times. The queue
48 * is slotted, with each slot holding timers which expire in a
49 * 2**STTIMER_MINPOLL (8) second period. The timers in each slot are
50 * sorted by increasing expiry time. The number of slots is 2**7 (128),
51 * to cover a time period of 1024 seconds into the future before wrapping.
53 #define STTIMER_MINPOLL 3 /* log2 min poll interval (8 s) */
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))])
60 struct st_timer_data {
62 /* start time of the slot processed previously */
63 cfs_time_t stt_prev_slot;
64 struct list_head stt_hash[STTIMER_NSLOTS];
67 wait_queue_head_t stt_waitq;
73 stt_add_timer(stt_timer_t *timer)
75 struct list_head *pos;
77 spin_lock(&stt_data.stt_lock);
80 LASSERT(stt_data.stt_nthreads > 0);
82 LASSERT(!stt_data.stt_shuttingdown);
83 LASSERT(timer->stt_func != NULL);
84 LASSERT(list_empty(&timer->stt_list));
85 LASSERT(cfs_time_after(timer->stt_expires, cfs_time_current_sec()));
87 /* a simple insertion sort */
88 list_for_each_prev(pos, STTIMER_SLOT(timer->stt_expires)) {
89 stt_timer_t *old = list_entry(pos, stt_timer_t, stt_list);
91 if (cfs_time_aftereq(timer->stt_expires, old->stt_expires))
94 list_add(&timer->stt_list, pos);
96 spin_unlock(&stt_data.stt_lock);
100 * The function returns whether it has deactivated a pending timer or not.
101 * (ie. del_timer() of an inactive timer returns 0, del_timer() of an
102 * active timer returns 1.)
105 * When 0 is returned, it is possible that timer->stt_func _is_ running on
109 stt_del_timer(stt_timer_t *timer)
113 spin_lock(&stt_data.stt_lock);
116 LASSERT(stt_data.stt_nthreads > 0);
118 LASSERT(!stt_data.stt_shuttingdown);
120 if (!list_empty(&timer->stt_list)) {
122 list_del_init(&timer->stt_list);
125 spin_unlock(&stt_data.stt_lock);
129 /* called with stt_data.stt_lock held */
131 stt_expire_list(struct list_head *slot, cfs_time_t now)
136 while (!list_empty(slot)) {
137 timer = list_entry(slot->next, stt_timer_t, stt_list);
139 if (cfs_time_after(timer->stt_expires, now))
142 list_del_init(&timer->stt_list);
143 spin_unlock(&stt_data.stt_lock);
146 (*timer->stt_func) (timer->stt_data);
148 spin_lock(&stt_data.stt_lock);
155 stt_check_timers (cfs_time_t *last)
159 cfs_time_t this_slot;
161 now = cfs_time_current_sec();
162 this_slot = now & STTIMER_SLOTTIMEMASK;
164 spin_lock(&stt_data.stt_lock);
166 while (cfs_time_aftereq(this_slot, *last)) {
167 expired += stt_expire_list(STTIMER_SLOT(this_slot), now);
168 this_slot = cfs_time_sub(this_slot, STTIMER_SLOTTIME);
171 *last = now & STTIMER_SLOTTIMEMASK;
172 spin_unlock(&stt_data.stt_lock);
179 stt_timer_main (void *arg)
185 while (!stt_data.stt_shuttingdown) {
186 stt_check_timers(&stt_data.stt_prev_slot);
188 rc = wait_event_timeout(stt_data.stt_waitq,
189 stt_data.stt_shuttingdown,
190 cfs_time_seconds(STTIMER_SLOTTIME));
193 spin_lock(&stt_data.stt_lock);
194 stt_data.stt_nthreads--;
195 spin_unlock(&stt_data.stt_lock);
200 stt_start_timer_thread (void)
202 struct task_struct *task;
204 LASSERT(!stt_data.stt_shuttingdown);
206 task = kthread_run(stt_timer_main, NULL, "st_timer");
208 return PTR_ERR(task);
210 spin_lock(&stt_data.stt_lock);
211 stt_data.stt_nthreads++;
212 spin_unlock(&stt_data.stt_lock);
216 #else /* !__KERNEL__ */
219 stt_check_events (void)
221 return stt_check_timers(&stt_data.stt_prev_slot);
225 stt_poll_interval (void)
227 return STTIMER_SLOTTIME;
238 stt_data.stt_shuttingdown = 0;
239 stt_data.stt_prev_slot = cfs_time_current_sec() & STTIMER_SLOTTIMEMASK;
241 spin_lock_init(&stt_data.stt_lock);
242 for (i = 0; i < STTIMER_NSLOTS; i++)
243 INIT_LIST_HEAD(&stt_data.stt_hash[i]);
246 stt_data.stt_nthreads = 0;
247 init_waitqueue_head(&stt_data.stt_waitq);
248 rc = stt_start_timer_thread();
250 CERROR ("Can't spawn timer thread: %d\n", rc);
261 spin_lock(&stt_data.stt_lock);
263 for (i = 0; i < STTIMER_NSLOTS; i++)
264 LASSERT(list_empty(&stt_data.stt_hash[i]));
266 stt_data.stt_shuttingdown = 1;
269 wake_up(&stt_data.stt_waitq);
270 lst_wait_until(stt_data.stt_nthreads == 0, stt_data.stt_lock,
271 "waiting for %d threads to terminate\n",
272 stt_data.stt_nthreads);
275 spin_unlock(&stt_data.stt_lock);