1 // SPDX-License-Identifier: GPL-2.0
4 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
5 * Use is subject to license terms.
7 * Copyright (c) 2011, 2013, Intel Corporation.
11 * This file is part of Lustre, http://www.lustre.org/
13 * Author: Isaac Huang <isaac@clusterfs.com>
16 #define DEBUG_SUBSYSTEM S_LNET
22 * Timers are implemented as a sorted queue of expiry times. The queue
23 * is slotted, with each slot holding timers which expire in a
24 * 2**STTIMER_MINPOLL (8) second period. The timers in each slot are
25 * sorted by increasing expiry time. The number of slots is 2**7 (128),
26 * to cover a time period of 1024 seconds into the future before wrapping.
28 #define STTIMER_MINPOLL 3 /* log2 min poll interval (8 s) */
29 #define STTIMER_SLOTTIME (1 << STTIMER_MINPOLL)
30 #define STTIMER_SLOTTIMEMASK (~(STTIMER_SLOTTIME - 1))
31 #define STTIMER_NSLOTS (1 << 7)
32 #define STTIMER_SLOT(t) (&stt_data.stt_hash[(((t) >> STTIMER_MINPOLL) & \
33 (STTIMER_NSLOTS - 1))])
35 static struct st_timer_data {
37 /* start time of the slot processed previously */
38 time64_t stt_prev_slot;
39 struct list_head stt_hash[STTIMER_NSLOTS];
41 wait_queue_head_t stt_waitq;
46 stt_add_timer(struct stt_timer *timer)
48 struct list_head *pos;
50 spin_lock(&stt_data.stt_lock);
52 LASSERT(stt_data.stt_nthreads > 0);
53 LASSERT(!stt_data.stt_shuttingdown);
54 LASSERT(timer->stt_func != NULL);
55 LASSERT(list_empty(&timer->stt_list));
56 LASSERT(timer->stt_expires > ktime_get_real_seconds());
58 /* a simple insertion sort */
59 list_for_each_prev(pos, STTIMER_SLOT(timer->stt_expires)) {
60 struct stt_timer *old = list_entry(pos, struct stt_timer,
63 if (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(struct stt_timer *timer)
85 spin_lock(&stt_data.stt_lock);
87 LASSERT(stt_data.stt_nthreads > 0);
88 LASSERT(!stt_data.stt_shuttingdown);
90 if (!list_empty(&timer->stt_list)) {
92 list_del_init(&timer->stt_list);
95 spin_unlock(&stt_data.stt_lock);
99 /* called with stt_data.stt_lock held */
101 stt_expire_list(struct list_head *slot, time64_t now)
104 struct stt_timer *timer;
106 while (!list_empty(slot)) {
107 timer = list_first_entry(slot, struct stt_timer, stt_list);
109 if (timer->stt_expires > now)
112 list_del_init(&timer->stt_list);
113 spin_unlock(&stt_data.stt_lock);
116 (*timer->stt_func) (timer->stt_data);
118 spin_lock(&stt_data.stt_lock);
125 stt_check_timers(time64_t *last)
131 now = ktime_get_real_seconds();
132 this_slot = now & STTIMER_SLOTTIMEMASK;
134 spin_lock(&stt_data.stt_lock);
136 while (this_slot >= *last) {
137 expired += stt_expire_list(STTIMER_SLOT(this_slot), now);
138 this_slot = this_slot - STTIMER_SLOTTIME;
141 *last = now & STTIMER_SLOTTIMEMASK;
142 spin_unlock(&stt_data.stt_lock);
148 stt_timer_main (void *arg)
152 while (!stt_data.stt_shuttingdown) {
153 stt_check_timers(&stt_data.stt_prev_slot);
155 rc = wait_event_timeout(stt_data.stt_waitq,
156 stt_data.stt_shuttingdown,
157 cfs_time_seconds(STTIMER_SLOTTIME));
160 spin_lock(&stt_data.stt_lock);
161 stt_data.stt_nthreads--;
162 spin_unlock(&stt_data.stt_lock);
167 stt_start_timer_thread (void)
169 struct task_struct *task;
171 LASSERT(!stt_data.stt_shuttingdown);
173 task = kthread_run(stt_timer_main, NULL, "st_timer");
175 return PTR_ERR(task);
177 spin_lock(&stt_data.stt_lock);
178 stt_data.stt_nthreads++;
179 spin_unlock(&stt_data.stt_lock);
190 stt_data.stt_shuttingdown = 0;
191 stt_data.stt_prev_slot = ktime_get_real_seconds() & STTIMER_SLOTTIMEMASK;
193 spin_lock_init(&stt_data.stt_lock);
194 for (i = 0; i < STTIMER_NSLOTS; i++)
195 INIT_LIST_HEAD(&stt_data.stt_hash[i]);
197 stt_data.stt_nthreads = 0;
198 init_waitqueue_head(&stt_data.stt_waitq);
199 rc = stt_start_timer_thread();
201 CERROR ("Can't spawn timer thread: %d\n", rc);
211 spin_lock(&stt_data.stt_lock);
213 for (i = 0; i < STTIMER_NSLOTS; i++)
214 LASSERT(list_empty(&stt_data.stt_hash[i]));
216 stt_data.stt_shuttingdown = 1;
218 wake_up(&stt_data.stt_waitq);
219 lst_wait_until(stt_data.stt_nthreads == 0, stt_data.stt_lock,
220 "waiting for %d threads to terminate\n",
221 stt_data.stt_nthreads);
223 spin_unlock(&stt_data.stt_lock);