x86/mce: Fix mce_rdmsrl() warning message
[linux-2.6-block.git] / drivers / staging / lustre / lnet / selftest / timer.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
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).
15  *
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
19  *
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
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2012, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lnet/selftest/timer.c
37  *
38  * Author: Isaac Huang <isaac@clusterfs.com>
39  */
40
41 #define DEBUG_SUBSYSTEM S_LNET
42
43 #include "selftest.h"
44
45 /*
46  * Timers are implemented as a sorted queue of expiry times. The queue
47  * is slotted, with each slot holding timers which expire in a
48  * 2**STTIMER_MINPOLL (8) second period. The timers in each slot are
49  * sorted by increasing expiry time. The number of slots is 2**7 (128),
50  * to cover a time period of 1024 seconds into the future before wrapping.
51  */
52 #define STTIMER_MINPOLL        3        /* log2 min poll interval (8 s) */
53 #define STTIMER_SLOTTIME       (1 << STTIMER_MINPOLL)
54 #define STTIMER_SLOTTIMEMASK   (~(STTIMER_SLOTTIME - 1))
55 #define STTIMER_NSLOTS         (1 << 7)
56 #define STTIMER_SLOT(t)        (&stt_data.stt_hash[(((t) >> STTIMER_MINPOLL) & \
57                                                     (STTIMER_NSLOTS - 1))])
58
59 static struct st_timer_data {
60         spinlock_t        stt_lock;
61         unsigned long     stt_prev_slot; /* start time of the slot processed
62                                           * previously */
63         struct list_head  stt_hash[STTIMER_NSLOTS];
64         int               stt_shuttingdown;
65         wait_queue_head_t stt_waitq;
66         int               stt_nthreads;
67 } stt_data;
68
69 void
70 stt_add_timer(struct stt_timer *timer)
71 {
72         struct list_head *pos;
73
74         spin_lock(&stt_data.stt_lock);
75
76         LASSERT(stt_data.stt_nthreads > 0);
77         LASSERT(!stt_data.stt_shuttingdown);
78         LASSERT(timer->stt_func);
79         LASSERT(list_empty(&timer->stt_list));
80         LASSERT(timer->stt_expires > ktime_get_real_seconds());
81
82         /* a simple insertion sort */
83         list_for_each_prev(pos, STTIMER_SLOT(timer->stt_expires)) {
84                 struct stt_timer *old = list_entry(pos, struct stt_timer,
85                                                    stt_list);
86
87                 if (timer->stt_expires >= old->stt_expires)
88                         break;
89         }
90         list_add(&timer->stt_list, pos);
91
92         spin_unlock(&stt_data.stt_lock);
93 }
94
95 /*
96  * The function returns whether it has deactivated a pending timer or not.
97  * (ie. del_timer() of an inactive timer returns 0, del_timer() of an
98  * active timer returns 1.)
99  *
100  * CAVEAT EMPTOR:
101  * When 0 is returned, it is possible that timer->stt_func _is_ running on
102  * another CPU.
103  */
104 int
105 stt_del_timer(struct stt_timer *timer)
106 {
107         int ret = 0;
108
109         spin_lock(&stt_data.stt_lock);
110
111         LASSERT(stt_data.stt_nthreads > 0);
112         LASSERT(!stt_data.stt_shuttingdown);
113
114         if (!list_empty(&timer->stt_list)) {
115                 ret = 1;
116                 list_del_init(&timer->stt_list);
117         }
118
119         spin_unlock(&stt_data.stt_lock);
120         return ret;
121 }
122
123 /* called with stt_data.stt_lock held */
124 static int
125 stt_expire_list(struct list_head *slot, time64_t now)
126 {
127         int expired = 0;
128         struct stt_timer *timer;
129
130         while (!list_empty(slot)) {
131                 timer = list_entry(slot->next, struct stt_timer, stt_list);
132
133                 if (timer->stt_expires > now)
134                         break;
135
136                 list_del_init(&timer->stt_list);
137                 spin_unlock(&stt_data.stt_lock);
138
139                 expired++;
140                 (*timer->stt_func) (timer->stt_data);
141
142                 spin_lock(&stt_data.stt_lock);
143         }
144
145         return expired;
146 }
147
148 static int
149 stt_check_timers(unsigned long *last)
150 {
151         int expired = 0;
152         time64_t now;
153         unsigned long this_slot;
154
155         now = ktime_get_real_seconds();
156         this_slot = now & STTIMER_SLOTTIMEMASK;
157
158         spin_lock(&stt_data.stt_lock);
159
160         while (cfs_time_aftereq(this_slot, *last)) {
161                 expired += stt_expire_list(STTIMER_SLOT(this_slot), now);
162                 this_slot = cfs_time_sub(this_slot, STTIMER_SLOTTIME);
163         }
164
165         *last = now & STTIMER_SLOTTIMEMASK;
166         spin_unlock(&stt_data.stt_lock);
167         return expired;
168 }
169
170 static int
171 stt_timer_main(void *arg)
172 {
173         int rc = 0;
174
175         cfs_block_allsigs();
176
177         while (!stt_data.stt_shuttingdown) {
178                 stt_check_timers(&stt_data.stt_prev_slot);
179
180                 rc = wait_event_timeout(stt_data.stt_waitq,
181                                         stt_data.stt_shuttingdown,
182                                         cfs_time_seconds(STTIMER_SLOTTIME));
183         }
184
185         spin_lock(&stt_data.stt_lock);
186         stt_data.stt_nthreads--;
187         spin_unlock(&stt_data.stt_lock);
188         return rc;
189 }
190
191 static int
192 stt_start_timer_thread(void)
193 {
194         struct task_struct *task;
195
196         LASSERT(!stt_data.stt_shuttingdown);
197
198         task = kthread_run(stt_timer_main, NULL, "st_timer");
199         if (IS_ERR(task))
200                 return PTR_ERR(task);
201
202         spin_lock(&stt_data.stt_lock);
203         stt_data.stt_nthreads++;
204         spin_unlock(&stt_data.stt_lock);
205         return 0;
206 }
207
208 int
209 stt_startup(void)
210 {
211         int rc = 0;
212         int i;
213
214         stt_data.stt_shuttingdown = 0;
215         stt_data.stt_prev_slot = ktime_get_real_seconds() & STTIMER_SLOTTIMEMASK;
216
217         spin_lock_init(&stt_data.stt_lock);
218         for (i = 0; i < STTIMER_NSLOTS; i++)
219                 INIT_LIST_HEAD(&stt_data.stt_hash[i]);
220
221         stt_data.stt_nthreads = 0;
222         init_waitqueue_head(&stt_data.stt_waitq);
223         rc = stt_start_timer_thread();
224         if (rc)
225                 CERROR("Can't spawn timer thread: %d\n", rc);
226
227         return rc;
228 }
229
230 void
231 stt_shutdown(void)
232 {
233         int i;
234
235         spin_lock(&stt_data.stt_lock);
236
237         for (i = 0; i < STTIMER_NSLOTS; i++)
238                 LASSERT(list_empty(&stt_data.stt_hash[i]));
239
240         stt_data.stt_shuttingdown = 1;
241
242         wake_up(&stt_data.stt_waitq);
243         lst_wait_until(!stt_data.stt_nthreads, stt_data.stt_lock,
244                        "waiting for %d threads to terminate\n",
245                        stt_data.stt_nthreads);
246
247         spin_unlock(&stt_data.stt_lock);
248 }