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.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2013, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
32 * lnet/selftest/timer.c
34 * Author: Isaac Huang <isaac@clusterfs.com>
37 #define DEBUG_SUBSYSTEM S_LNET
43 * Timers are implemented as a sorted queue of expiry times. The queue
44 * is slotted, with each slot holding timers which expire in a
45 * 2**STTIMER_MINPOLL (8) second period. The timers in each slot are
46 * sorted by increasing expiry time. The number of slots is 2**7 (128),
47 * to cover a time period of 1024 seconds into the future before wrapping.
49 #define STTIMER_MINPOLL 3 /* log2 min poll interval (8 s) */
50 #define STTIMER_SLOTTIME (1 << STTIMER_MINPOLL)
51 #define STTIMER_SLOTTIMEMASK (~(STTIMER_SLOTTIME - 1))
52 #define STTIMER_NSLOTS (1 << 7)
53 #define STTIMER_SLOT(t) (&stt_data.stt_hash[(((t) >> STTIMER_MINPOLL) & \
54 (STTIMER_NSLOTS - 1))])
56 static struct st_timer_data {
58 /* start time of the slot processed previously */
59 time64_t stt_prev_slot;
60 struct list_head stt_hash[STTIMER_NSLOTS];
62 wait_queue_head_t stt_waitq;
67 stt_add_timer(struct stt_timer *timer)
69 struct list_head *pos;
71 spin_lock(&stt_data.stt_lock);
73 LASSERT(stt_data.stt_nthreads > 0);
74 LASSERT(!stt_data.stt_shuttingdown);
75 LASSERT(timer->stt_func != NULL);
76 LASSERT(list_empty(&timer->stt_list));
77 LASSERT(timer->stt_expires > ktime_get_real_seconds());
79 /* a simple insertion sort */
80 list_for_each_prev(pos, STTIMER_SLOT(timer->stt_expires)) {
81 struct stt_timer *old = list_entry(pos, struct stt_timer,
84 if (timer->stt_expires >= old->stt_expires)
87 list_add(&timer->stt_list, pos);
89 spin_unlock(&stt_data.stt_lock);
93 * The function returns whether it has deactivated a pending timer or not.
94 * (ie. del_timer() of an inactive timer returns 0, del_timer() of an
95 * active timer returns 1.)
98 * When 0 is returned, it is possible that timer->stt_func _is_ running on
102 stt_del_timer(struct stt_timer *timer)
106 spin_lock(&stt_data.stt_lock);
108 LASSERT(stt_data.stt_nthreads > 0);
109 LASSERT(!stt_data.stt_shuttingdown);
111 if (!list_empty(&timer->stt_list)) {
113 list_del_init(&timer->stt_list);
116 spin_unlock(&stt_data.stt_lock);
120 /* called with stt_data.stt_lock held */
122 stt_expire_list(struct list_head *slot, time64_t now)
125 struct stt_timer *timer;
127 while (!list_empty(slot)) {
128 timer = list_entry(slot->next, struct stt_timer, stt_list);
130 if (timer->stt_expires > now)
133 list_del_init(&timer->stt_list);
134 spin_unlock(&stt_data.stt_lock);
137 (*timer->stt_func) (timer->stt_data);
139 spin_lock(&stt_data.stt_lock);
146 stt_check_timers(time64_t *last)
152 now = ktime_get_real_seconds();
153 this_slot = now & STTIMER_SLOTTIMEMASK;
155 spin_lock(&stt_data.stt_lock);
157 while (this_slot >= *last) {
158 expired += stt_expire_list(STTIMER_SLOT(this_slot), now);
159 this_slot = this_slot - STTIMER_SLOTTIME;
162 *last = now & STTIMER_SLOTTIMEMASK;
163 spin_unlock(&stt_data.stt_lock);
169 stt_timer_main (void *arg)
173 while (!stt_data.stt_shuttingdown) {
174 stt_check_timers(&stt_data.stt_prev_slot);
176 rc = wait_event_timeout(stt_data.stt_waitq,
177 stt_data.stt_shuttingdown,
178 cfs_time_seconds(STTIMER_SLOTTIME));
181 spin_lock(&stt_data.stt_lock);
182 stt_data.stt_nthreads--;
183 spin_unlock(&stt_data.stt_lock);
188 stt_start_timer_thread (void)
190 struct task_struct *task;
192 LASSERT(!stt_data.stt_shuttingdown);
194 task = kthread_run(stt_timer_main, NULL, "st_timer");
196 return PTR_ERR(task);
198 spin_lock(&stt_data.stt_lock);
199 stt_data.stt_nthreads++;
200 spin_unlock(&stt_data.stt_lock);
211 stt_data.stt_shuttingdown = 0;
212 stt_data.stt_prev_slot = ktime_get_real_seconds() & STTIMER_SLOTTIMEMASK;
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]);
218 stt_data.stt_nthreads = 0;
219 init_waitqueue_head(&stt_data.stt_waitq);
220 rc = stt_start_timer_thread();
222 CERROR ("Can't spawn timer thread: %d\n", rc);
232 spin_lock(&stt_data.stt_lock);
234 for (i = 0; i < STTIMER_NSLOTS; i++)
235 LASSERT(list_empty(&stt_data.stt_hash[i]));
237 stt_data.stt_shuttingdown = 1;
239 wake_up(&stt_data.stt_waitq);
240 lst_wait_until(stt_data.stt_nthreads == 0, stt_data.stt_lock,
241 "waiting for %d threads to terminate\n",
242 stt_data.stt_nthreads);
244 spin_unlock(&stt_data.stt_lock);