1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
30 * Use is subject to license terms.
32 * Copyright (c) 2011, Whamcloud, Inc.
35 * This file is part of Lustre, http://www.lustre.org/
36 * Lustre is a trademark of Sun Microsystems, Inc.
38 * lnet/selftest/timer.c
40 * Author: Isaac Huang <isaac@clusterfs.com>
43 #define DEBUG_SUBSYSTEM S_LNET
49 * Timers are implemented as a sorted queue of expiry times. The queue
50 * is slotted, with each slot holding timers which expire in a
51 * 2**STTIMER_MINPOLL (8) second period. The timers in each slot are
52 * sorted by increasing expiry time. The number of slots is 2**7 (128),
53 * to cover a time period of 1024 seconds into the future before wrapping.
55 #define STTIMER_MINPOLL 3 /* log2 min poll interval (8 s) */
56 #define STTIMER_SLOTTIME (1 << STTIMER_MINPOLL)
57 #define STTIMER_SLOTTIMEMASK (~(STTIMER_SLOTTIME - 1))
58 #define STTIMER_NSLOTS (1 << 7)
59 #define STTIMER_SLOT(t) (&stt_data.stt_hash[(((t) >> STTIMER_MINPOLL) & \
60 (STTIMER_NSLOTS - 1))])
62 struct st_timer_data {
63 cfs_spinlock_t stt_lock;
64 /* start time of the slot processed previously */
65 cfs_time_t stt_prev_slot;
66 cfs_list_t stt_hash[STTIMER_NSLOTS];
69 cfs_waitq_t stt_waitq;
75 stt_add_timer (stt_timer_t *timer)
79 cfs_spin_lock(&stt_data.stt_lock);
82 LASSERT (stt_data.stt_nthreads > 0);
84 LASSERT (!stt_data.stt_shuttingdown);
85 LASSERT (timer->stt_func != NULL);
86 LASSERT (cfs_list_empty(&timer->stt_list));
87 LASSERT (cfs_time_after(timer->stt_expires, cfs_time_current_sec()));
89 /* a simple insertion sort */
90 cfs_list_for_each_prev (pos, STTIMER_SLOT(timer->stt_expires)) {
91 stt_timer_t *old = cfs_list_entry(pos, stt_timer_t, stt_list);
93 if (cfs_time_aftereq(timer->stt_expires, old->stt_expires))
96 cfs_list_add(&timer->stt_list, pos);
98 cfs_spin_unlock(&stt_data.stt_lock);
102 * The function returns whether it has deactivated a pending timer or not.
103 * (ie. del_timer() of an inactive timer returns 0, del_timer() of an
104 * active timer returns 1.)
107 * When 0 is returned, it is possible that timer->stt_func _is_ running on
111 stt_del_timer (stt_timer_t *timer)
115 cfs_spin_lock(&stt_data.stt_lock);
118 LASSERT (stt_data.stt_nthreads > 0);
120 LASSERT (!stt_data.stt_shuttingdown);
122 if (!cfs_list_empty(&timer->stt_list)) {
124 cfs_list_del_init(&timer->stt_list);
127 cfs_spin_unlock(&stt_data.stt_lock);
131 /* called with stt_data.stt_lock held */
133 stt_expire_list (cfs_list_t *slot, cfs_time_t now)
138 while (!cfs_list_empty(slot)) {
139 timer = cfs_list_entry(slot->next, stt_timer_t, stt_list);
141 if (cfs_time_after(timer->stt_expires, now))
144 cfs_list_del_init(&timer->stt_list);
145 cfs_spin_unlock(&stt_data.stt_lock);
148 (*timer->stt_func) (timer->stt_data);
150 cfs_spin_lock(&stt_data.stt_lock);
157 stt_check_timers (cfs_time_t *last)
161 cfs_time_t this_slot;
163 now = cfs_time_current_sec();
164 this_slot = now & STTIMER_SLOTTIMEMASK;
166 cfs_spin_lock(&stt_data.stt_lock);
168 while (cfs_time_aftereq(this_slot, *last)) {
169 expired += stt_expire_list(STTIMER_SLOT(this_slot), now);
170 this_slot = cfs_time_sub(this_slot, STTIMER_SLOTTIME);
173 *last = now & STTIMER_SLOTTIMEMASK;
174 cfs_spin_unlock(&stt_data.stt_lock);
181 stt_timer_main (void *arg)
188 cfs_daemonize("st_timer");
191 while (!stt_data.stt_shuttingdown) {
192 stt_check_timers(&stt_data.stt_prev_slot);
194 cfs_waitq_wait_event_timeout(stt_data.stt_waitq,
195 stt_data.stt_shuttingdown,
196 cfs_time_seconds(STTIMER_SLOTTIME),
200 cfs_spin_lock(&stt_data.stt_lock);
201 stt_data.stt_nthreads--;
202 cfs_spin_unlock(&stt_data.stt_lock);
207 stt_start_timer_thread (void)
211 LASSERT (!stt_data.stt_shuttingdown);
213 pid = cfs_create_thread(stt_timer_main, NULL, 0);
217 cfs_spin_lock(&stt_data.stt_lock);
218 stt_data.stt_nthreads++;
219 cfs_spin_unlock(&stt_data.stt_lock);
223 #else /* !__KERNEL__ */
226 stt_check_events (void)
228 return stt_check_timers(&stt_data.stt_prev_slot);
232 stt_poll_interval (void)
234 return STTIMER_SLOTTIME;
245 stt_data.stt_shuttingdown = 0;
246 stt_data.stt_prev_slot = cfs_time_current_sec() & STTIMER_SLOTTIMEMASK;
248 cfs_spin_lock_init(&stt_data.stt_lock);
249 for (i = 0; i < STTIMER_NSLOTS; i++)
250 CFS_INIT_LIST_HEAD(&stt_data.stt_hash[i]);
253 stt_data.stt_nthreads = 0;
254 cfs_waitq_init(&stt_data.stt_waitq);
255 rc = stt_start_timer_thread();
257 CERROR ("Can't spawn timer thread: %d\n", rc);
268 cfs_spin_lock(&stt_data.stt_lock);
270 for (i = 0; i < STTIMER_NSLOTS; i++)
271 LASSERT (cfs_list_empty(&stt_data.stt_hash[i]));
273 stt_data.stt_shuttingdown = 1;
276 cfs_waitq_signal(&stt_data.stt_waitq);
277 lst_wait_until(stt_data.stt_nthreads == 0, stt_data.stt_lock,
278 "waiting for %d threads to terminate\n",
279 stt_data.stt_nthreads);
282 cfs_spin_unlock(&stt_data.stt_lock);