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 2008 Sun Microsystems, Inc. All rights reserved
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 * lnet/selftest/workitem.c
38 * Author: Isaac Huang <isaac@clusterfs.com>
40 #define DEBUG_SUBSYSTEM S_LNET
45 struct smoketest_workitem {
46 cfs_list_t wi_runq; /* concurrent workitems */
47 cfs_list_t wi_serial_runq; /* serialised workitems */
48 cfs_waitq_t wi_waitq; /* where schedulers sleep */
49 cfs_waitq_t wi_serial_waitq; /* where serial scheduler sleep */
50 cfs_spinlock_t wi_lock; /* serialize */
56 swi_sched_cansleep (cfs_list_t *q)
60 cfs_spin_lock(&swi_data.wi_lock);
62 rc = !swi_data.wi_shuttingdown && cfs_list_empty(q);
64 cfs_spin_unlock(&swi_data.wi_lock);
69 * 0. it only works when called from wi->wi_action.
70 * 1. when it returns no one shall try to schedule the workitem.
73 swi_kill_workitem (swi_workitem_t *wi)
75 LASSERT (!cfs_in_interrupt()); /* because we use plain spinlock */
76 LASSERT (!swi_data.wi_shuttingdown);
78 cfs_spin_lock(&swi_data.wi_lock);
81 LASSERT (wi->wi_running);
84 if (wi->wi_scheduled) { /* cancel pending schedules */
85 LASSERT (!cfs_list_empty(&wi->wi_list));
86 cfs_list_del_init(&wi->wi_list);
89 LASSERT (cfs_list_empty(&wi->wi_list));
90 wi->wi_scheduled = 1; /* LBUG future schedule attempts */
92 cfs_spin_unlock(&swi_data.wi_lock);
97 swi_schedule_workitem (swi_workitem_t *wi)
99 LASSERT (!cfs_in_interrupt()); /* because we use plain spinlock */
100 LASSERT (!swi_data.wi_shuttingdown);
102 cfs_spin_lock(&swi_data.wi_lock);
104 if (!wi->wi_scheduled) {
105 LASSERT (cfs_list_empty(&wi->wi_list));
107 wi->wi_scheduled = 1;
108 cfs_list_add_tail(&wi->wi_list, &swi_data.wi_runq);
109 cfs_waitq_signal(&swi_data.wi_waitq);
112 LASSERT (!cfs_list_empty(&wi->wi_list));
113 cfs_spin_unlock(&swi_data.wi_lock);
118 * Workitem scheduled by this function is strictly serialised not only with
119 * itself, but also with others scheduled this way.
121 * Now there's only one static serialised queue, but in the future more might
122 * be added, and even dynamic creation of serialised queues might be supported.
125 swi_schedule_serial_workitem (swi_workitem_t *wi)
127 LASSERT (!cfs_in_interrupt()); /* because we use plain spinlock */
128 LASSERT (!swi_data.wi_shuttingdown);
130 cfs_spin_lock(&swi_data.wi_lock);
132 if (!wi->wi_scheduled) {
133 LASSERT (cfs_list_empty(&wi->wi_list));
135 wi->wi_scheduled = 1;
136 cfs_list_add_tail(&wi->wi_list, &swi_data.wi_serial_runq);
137 cfs_waitq_signal(&swi_data.wi_serial_waitq);
140 LASSERT (!cfs_list_empty(&wi->wi_list));
141 cfs_spin_unlock(&swi_data.wi_lock);
148 swi_scheduler_main (void *arg)
150 int id = (int)(long_ptr_t) arg;
153 snprintf(name, sizeof(name), "swi_sd%03d", id);
157 cfs_spin_lock(&swi_data.wi_lock);
159 while (!swi_data.wi_shuttingdown) {
164 while (!cfs_list_empty(&swi_data.wi_runq) &&
165 nloops < SWI_RESCHED) {
166 wi = cfs_list_entry(swi_data.wi_runq.next,
167 swi_workitem_t, wi_list);
168 cfs_list_del_init(&wi->wi_list);
170 LASSERT (wi->wi_scheduled);
173 if (wi->wi_running) {
174 cfs_list_add_tail(&wi->wi_list,
180 wi->wi_scheduled = 0;
181 cfs_spin_unlock(&swi_data.wi_lock);
183 rc = (*wi->wi_action) (wi);
185 cfs_spin_lock(&swi_data.wi_lock);
186 if (rc == 0) /* wi still active */
190 cfs_spin_unlock(&swi_data.wi_lock);
192 if (nloops < SWI_RESCHED)
193 cfs_wait_event_interruptible_exclusive(
195 !swi_sched_cansleep(&swi_data.wi_runq), rc);
199 cfs_spin_lock(&swi_data.wi_lock);
202 swi_data.wi_nthreads--;
203 cfs_spin_unlock(&swi_data.wi_lock);
208 swi_serial_scheduler_main (void *arg)
212 cfs_daemonize("swi_serial_sd");
215 cfs_spin_lock(&swi_data.wi_lock);
217 while (!swi_data.wi_shuttingdown) {
222 while (!cfs_list_empty(&swi_data.wi_serial_runq) &&
223 nloops < SWI_RESCHED) {
224 wi = cfs_list_entry(swi_data.wi_serial_runq.next,
225 swi_workitem_t, wi_list);
226 cfs_list_del_init(&wi->wi_list);
228 LASSERTF (!wi->wi_running && wi->wi_scheduled,
229 "wi %p running %d scheduled %d\n",
230 wi, wi->wi_running, wi->wi_scheduled);
234 wi->wi_scheduled = 0;
235 cfs_spin_unlock(&swi_data.wi_lock);
237 rc = (*wi->wi_action) (wi);
239 cfs_spin_lock(&swi_data.wi_lock);
240 if (rc == 0) /* wi still active */
244 cfs_spin_unlock(&swi_data.wi_lock);
246 if (nloops < SWI_RESCHED)
247 cfs_wait_event_interruptible_exclusive(
248 swi_data.wi_serial_waitq,
249 !swi_sched_cansleep(&swi_data.wi_serial_runq),
254 cfs_spin_lock(&swi_data.wi_lock);
257 swi_data.wi_nthreads--;
258 cfs_spin_unlock(&swi_data.wi_lock);
263 swi_start_thread (int (*func) (void*), void *arg)
267 LASSERT (!swi_data.wi_shuttingdown);
269 pid = cfs_kernel_thread(func, arg, 0);
273 cfs_spin_lock(&swi_data.wi_lock);
274 swi_data.wi_nthreads++;
275 cfs_spin_unlock(&swi_data.wi_lock);
279 #else /* __KERNEL__ */
282 swi_check_events (void)
288 cfs_spin_lock(&swi_data.wi_lock);
291 if (!cfs_list_empty(&swi_data.wi_serial_runq))
292 q = &swi_data.wi_serial_runq;
293 else if (!cfs_list_empty(&swi_data.wi_runq))
294 q = &swi_data.wi_runq;
298 wi = cfs_list_entry(q->next, swi_workitem_t, wi_list);
299 cfs_list_del_init(&wi->wi_list);
301 LASSERT (wi->wi_scheduled);
302 wi->wi_scheduled = 0;
303 cfs_spin_unlock(&swi_data.wi_lock);
306 (*wi->wi_action) (wi);
308 cfs_spin_lock(&swi_data.wi_lock);
311 cfs_spin_unlock(&swi_data.wi_lock);
323 swi_data.wi_nthreads = 0;
324 swi_data.wi_shuttingdown = 0;
325 cfs_spin_lock_init(&swi_data.wi_lock);
326 cfs_waitq_init(&swi_data.wi_waitq);
327 cfs_waitq_init(&swi_data.wi_serial_waitq);
328 CFS_INIT_LIST_HEAD(&swi_data.wi_runq);
329 CFS_INIT_LIST_HEAD(&swi_data.wi_serial_runq);
332 rc = swi_start_thread(swi_serial_scheduler_main, NULL);
334 LASSERT (swi_data.wi_nthreads == 0);
335 CERROR ("Can't spawn serial workitem scheduler: %d\n", rc);
339 for (i = 0; i < cfs_num_online_cpus(); i++) {
340 rc = swi_start_thread(swi_scheduler_main,
341 (void *) (long_ptr_t) i);
343 CERROR ("Can't spawn workitem scheduler: %d\n", rc);
359 cfs_spin_lock(&swi_data.wi_lock);
361 LASSERT (cfs_list_empty(&swi_data.wi_runq));
362 LASSERT (cfs_list_empty(&swi_data.wi_serial_runq));
364 swi_data.wi_shuttingdown = 1;
367 cfs_waitq_broadcast(&swi_data.wi_waitq);
368 cfs_waitq_broadcast(&swi_data.wi_serial_waitq);
369 lst_wait_until(swi_data.wi_nthreads == 0, swi_data.wi_lock,
370 "waiting for %d threads to terminate\n",
371 swi_data.wi_nthreads);
374 cfs_spin_unlock(&swi_data.wi_lock);