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 struct list_head wi_runq; /* concurrent workitems */
47 struct list_head 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 spinlock_t wi_lock; /* serialize */
56 swi_sched_cansleep (struct list_head *q)
60 spin_lock(&swi_data.wi_lock);
62 rc = !swi_data.wi_shuttingdown && list_empty(q);
64 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 (!in_interrupt()); /* because we use plain spinlock */
76 LASSERT (!swi_data.wi_shuttingdown);
78 spin_lock(&swi_data.wi_lock);
81 LASSERT (wi->wi_running);
84 if (wi->wi_scheduled) { /* cancel pending schedules */
85 LASSERT (!list_empty(&wi->wi_list));
86 list_del_init(&wi->wi_list);
89 LASSERT (list_empty(&wi->wi_list));
90 wi->wi_scheduled = 1; /* LBUG future schedule attempts */
92 spin_unlock(&swi_data.wi_lock);
97 swi_schedule_workitem (swi_workitem_t *wi)
99 LASSERT (!in_interrupt()); /* because we use plain spinlock */
100 LASSERT (!swi_data.wi_shuttingdown);
102 spin_lock(&swi_data.wi_lock);
104 if (!wi->wi_scheduled) {
105 LASSERT (list_empty(&wi->wi_list));
107 wi->wi_scheduled = 1;
108 list_add_tail(&wi->wi_list, &swi_data.wi_runq);
109 cfs_waitq_signal(&swi_data.wi_waitq);
112 LASSERT (!list_empty(&wi->wi_list));
113 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 (!in_interrupt()); /* because we use plain spinlock */
128 LASSERT (!swi_data.wi_shuttingdown);
130 spin_lock(&swi_data.wi_lock);
132 if (!wi->wi_scheduled) {
133 LASSERT (list_empty(&wi->wi_list));
135 wi->wi_scheduled = 1;
136 list_add_tail(&wi->wi_list, &swi_data.wi_serial_runq);
137 cfs_waitq_signal(&swi_data.wi_serial_waitq);
140 LASSERT (!list_empty(&wi->wi_list));
141 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 spin_lock(&swi_data.wi_lock);
159 while (!swi_data.wi_shuttingdown) {
164 while (!list_empty(&swi_data.wi_runq) &&
165 nloops < SWI_RESCHED) {
166 wi = list_entry(swi_data.wi_runq.next,
167 swi_workitem_t, wi_list);
168 list_del_init(&wi->wi_list);
170 LASSERT (wi->wi_scheduled);
173 if (wi->wi_running) {
174 list_add_tail(&wi->wi_list, &swi_data.wi_runq);
179 wi->wi_scheduled = 0;
180 spin_unlock(&swi_data.wi_lock);
182 rc = (*wi->wi_action) (wi);
184 spin_lock(&swi_data.wi_lock);
185 if (rc == 0) /* wi still active */
189 spin_unlock(&swi_data.wi_lock);
191 if (nloops < SWI_RESCHED)
192 cfs_wait_event_interruptible_exclusive(
194 !swi_sched_cansleep(&swi_data.wi_runq), rc);
198 spin_lock(&swi_data.wi_lock);
201 swi_data.wi_nthreads--;
202 spin_unlock(&swi_data.wi_lock);
207 swi_serial_scheduler_main (void *arg)
211 cfs_daemonize("swi_serial_sd");
214 spin_lock(&swi_data.wi_lock);
216 while (!swi_data.wi_shuttingdown) {
221 while (!list_empty(&swi_data.wi_serial_runq) &&
222 nloops < SWI_RESCHED) {
223 wi = list_entry(swi_data.wi_serial_runq.next,
224 swi_workitem_t, wi_list);
225 list_del_init(&wi->wi_list);
227 LASSERT (!wi->wi_running);
228 LASSERT (wi->wi_scheduled);
232 wi->wi_scheduled = 0;
233 spin_unlock(&swi_data.wi_lock);
235 rc = (*wi->wi_action) (wi);
237 spin_lock(&swi_data.wi_lock);
238 if (rc == 0) /* wi still active */
242 spin_unlock(&swi_data.wi_lock);
244 if (nloops < SWI_RESCHED)
245 cfs_wait_event_interruptible_exclusive(
246 swi_data.wi_serial_waitq,
247 !swi_sched_cansleep(&swi_data.wi_serial_runq), rc);
251 spin_lock(&swi_data.wi_lock);
254 swi_data.wi_nthreads--;
255 spin_unlock(&swi_data.wi_lock);
260 swi_start_thread (int (*func) (void*), void *arg)
264 LASSERT (!swi_data.wi_shuttingdown);
266 pid = cfs_kernel_thread(func, arg, 0);
270 spin_lock(&swi_data.wi_lock);
271 swi_data.wi_nthreads++;
272 spin_unlock(&swi_data.wi_lock);
276 #else /* __KERNEL__ */
279 swi_check_events (void)
285 spin_lock(&swi_data.wi_lock);
288 if (!list_empty(&swi_data.wi_serial_runq))
289 q = &swi_data.wi_serial_runq;
290 else if (!list_empty(&swi_data.wi_runq))
291 q = &swi_data.wi_runq;
295 wi = list_entry(q->next, swi_workitem_t, wi_list);
296 list_del_init(&wi->wi_list);
298 LASSERT (wi->wi_scheduled);
299 wi->wi_scheduled = 0;
300 spin_unlock(&swi_data.wi_lock);
303 (*wi->wi_action) (wi);
305 spin_lock(&swi_data.wi_lock);
308 spin_unlock(&swi_data.wi_lock);
320 swi_data.wi_nthreads = 0;
321 swi_data.wi_shuttingdown = 0;
322 spin_lock_init(&swi_data.wi_lock);
323 cfs_waitq_init(&swi_data.wi_waitq);
324 cfs_waitq_init(&swi_data.wi_serial_waitq);
325 CFS_INIT_LIST_HEAD(&swi_data.wi_runq);
326 CFS_INIT_LIST_HEAD(&swi_data.wi_serial_runq);
329 rc = swi_start_thread(swi_serial_scheduler_main, NULL);
331 LASSERT (swi_data.wi_nthreads == 0);
332 CERROR ("Can't spawn serial workitem scheduler: %d\n", rc);
336 for (i = 0; i < num_online_cpus(); i++) {
337 rc = swi_start_thread(swi_scheduler_main,
338 (void *) (long_ptr_t) i);
340 CERROR ("Can't spawn workitem scheduler: %d\n", rc);
356 spin_lock(&swi_data.wi_lock);
358 LASSERT (list_empty(&swi_data.wi_runq));
359 LASSERT (list_empty(&swi_data.wi_serial_runq));
361 swi_data.wi_shuttingdown = 1;
364 cfs_waitq_broadcast(&swi_data.wi_waitq);
365 cfs_waitq_broadcast(&swi_data.wi_serial_waitq);
366 lst_wait_until(swi_data.wi_nthreads == 0, swi_data.wi_lock,
367 "waiting for %d threads to terminate\n",
368 swi_data.wi_nthreads);
371 spin_unlock(&swi_data.wi_lock);