]> git.proxmox.com Git - mirror_zfs.git/blame - module/splat/splat-taskq.c
Condition variable reference counts
[mirror_zfs.git] / module / splat / splat-taskq.c
CommitLineData
716154c5
BB
1/*****************************************************************************\
2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3 * Copyright (C) 2007 The Regents of the University of California.
4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5 * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
715f6251
BB
6 * UCRL-CODE-235197
7 *
716154c5
BB
8 * This file is part of the SPL, Solaris Porting Layer.
9 * For details, see <http://github.com/behlendorf/spl/>.
10 *
11 * The SPL is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
715f6251 15 *
716154c5 16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
715f6251
BB
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 * for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
716154c5
BB
22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23 *****************************************************************************
24 * Solaris Porting LAyer Tests (SPLAT) Task Queue Tests.
25\*****************************************************************************/
715f6251 26
7c50328b 27#include "splat-internal.h"
f1ca4da6 28
7c50328b
BB
29#define SPLAT_TASKQ_NAME "taskq"
30#define SPLAT_TASKQ_DESC "Kernel Task Queue Tests"
f1ca4da6 31
7c50328b
BB
32#define SPLAT_TASKQ_TEST1_ID 0x0201
33#define SPLAT_TASKQ_TEST1_NAME "single"
34#define SPLAT_TASKQ_TEST1_DESC "Single task queue, single task"
f1ca4da6 35
5562e5d1 36#define SPLAT_TASKQ_TEST2_ID 0x0202
7c50328b
BB
37#define SPLAT_TASKQ_TEST2_NAME "multiple"
38#define SPLAT_TASKQ_TEST2_DESC "Multiple task queues, multiple tasks"
f1ca4da6 39
5562e5d1 40#define SPLAT_TASKQ_TEST3_ID 0x0203
e9cb2b4f
BB
41#define SPLAT_TASKQ_TEST3_NAME "system"
42#define SPLAT_TASKQ_TEST3_DESC "System task queue, multiple tasks"
43
5562e5d1 44#define SPLAT_TASKQ_TEST4_ID 0x0204
7257ec41
BB
45#define SPLAT_TASKQ_TEST4_NAME "wait"
46#define SPLAT_TASKQ_TEST4_DESC "Multiple task waiting"
47
5562e5d1
BB
48#define SPLAT_TASKQ_TEST5_ID 0x0205
49#define SPLAT_TASKQ_TEST5_NAME "order"
50#define SPLAT_TASKQ_TEST5_DESC "Correct task ordering"
51
55f10ae5
NB
52#define SPLAT_TASKQ_TEST6_ID 0x0206
53#define SPLAT_TASKQ_TEST6_NAME "front"
54#define SPLAT_TASKQ_TEST6_DESC "Correct ordering with TQ_FRONT flag"
55
ac1e5b60
PS
56#define SPLAT_TASKQ_TEST7_ID 0x0207
57#define SPLAT_TASKQ_TEST7_NAME "recurse"
58#define SPLAT_TASKQ_TEST7_DESC "Single task queue, recursive dispatch"
59
cf5d23fa
NB
60#define SPLAT_TASKQ_TEST8_ID 0x0208
61#define SPLAT_TASKQ_TEST8_NAME "contention"
62#define SPLAT_TASKQ_TEST8_DESC "1 queue, 100 threads, 131072 tasks"
63
5562e5d1 64#define SPLAT_TASKQ_ORDER_MAX 8
ac1e5b60 65#define SPLAT_TASKQ_DEPTH_MAX 16
5562e5d1 66
cf5d23fa 67
7c50328b 68typedef struct splat_taskq_arg {
f1ca4da6
BB
69 int flag;
70 int id;
7257ec41 71 atomic_t count;
5562e5d1 72 int order[SPLAT_TASKQ_ORDER_MAX];
ac1e5b60
PS
73 unsigned int depth;
74 taskq_t *tq;
699d5ee8 75 taskq_ent_t *tqe;
5562e5d1 76 spinlock_t lock;
f1ca4da6
BB
77 struct file *file;
78 const char *name;
7c50328b 79} splat_taskq_arg_t;
f1ca4da6 80
5562e5d1
BB
81typedef struct splat_taskq_id {
82 int id;
83 splat_taskq_arg_t *arg;
84} splat_taskq_id_t;
85
86/*
87 * Create a taskq, queue a task, wait until task completes, ensure
88 * task ran properly, cleanup taskq.
f1ca4da6
BB
89 */
90static void
e9cb2b4f 91splat_taskq_test13_func(void *arg)
f1ca4da6 92{
7c50328b 93 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
f1ca4da6
BB
94
95 ASSERT(tq_arg);
7c50328b 96 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST1_NAME,
f1ca4da6 97 "Taskq '%s' function '%s' setting flag\n",
e9cb2b4f 98 tq_arg->name, sym2str(splat_taskq_test13_func));
f1ca4da6
BB
99 tq_arg->flag = 1;
100}
101
102static int
699d5ee8 103splat_taskq_test1_impl(struct file *file, void *arg, boolean_t prealloc)
f1ca4da6
BB
104{
105 taskq_t *tq;
106 taskqid_t id;
7c50328b 107 splat_taskq_arg_t tq_arg;
699d5ee8
PS
108 taskq_ent_t tqe;
109
110 taskq_init_ent(&tqe);
f1ca4da6 111
699d5ee8
PS
112 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
113 "Taskq '%s' creating (%s dispatch)\n",
114 SPLAT_TASKQ_TEST1_NAME,
115 prealloc ? "prealloc" : "dynamic");
bcd68186
BB
116 if ((tq = taskq_create(SPLAT_TASKQ_TEST1_NAME, 1, maxclsyspri,
117 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
7c50328b 118 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
f1ca4da6 119 "Taskq '%s' create failed\n",
7c50328b 120 SPLAT_TASKQ_TEST1_NAME);
f1ca4da6
BB
121 return -EINVAL;
122 }
123
124 tq_arg.flag = 0;
125 tq_arg.id = 0;
126 tq_arg.file = file;
7c50328b 127 tq_arg.name = SPLAT_TASKQ_TEST1_NAME;
f1ca4da6 128
7c50328b 129 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
f1ca4da6 130 "Taskq '%s' function '%s' dispatching\n",
e9cb2b4f 131 tq_arg.name, sym2str(splat_taskq_test13_func));
699d5ee8
PS
132 if (prealloc) {
133 taskq_dispatch_ent(tq, splat_taskq_test13_func,
134 &tq_arg, TQ_SLEEP, &tqe);
135 id = tqe.tqent_id;
136 } else {
137 id = taskq_dispatch(tq, splat_taskq_test13_func,
138 &tq_arg, TQ_SLEEP);
139 }
140
141 if (id == 0) {
7c50328b 142 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
699d5ee8
PS
143 "Taskq '%s' function '%s' dispatch failed\n",
144 tq_arg.name, sym2str(splat_taskq_test13_func));
4098c921 145 taskq_destroy(tq);
f1ca4da6
BB
146 return -EINVAL;
147 }
148
7c50328b 149 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' waiting\n",
f1ca4da6
BB
150 tq_arg.name);
151 taskq_wait(tq);
7c50328b 152 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' destroying\n",
f1ca4da6 153 tq_arg.name);
699d5ee8 154
4098c921 155 taskq_destroy(tq);
f1ca4da6
BB
156
157 return (tq_arg.flag) ? 0 : -EINVAL;
158}
159
699d5ee8
PS
160static int
161splat_taskq_test1(struct file *file, void *arg)
162{
163 int rc;
164
165 rc = splat_taskq_test1_impl(file, arg, B_FALSE);
166 if (rc)
167 return rc;
168
169 rc = splat_taskq_test1_impl(file, arg, B_TRUE);
170
171 return rc;
172}
173
5562e5d1
BB
174/*
175 * Create multiple taskq's, each with multiple tasks, wait until
176 * all tasks complete, ensure all tasks ran properly and in the
177 * correct order. Run order must be the same as the order submitted
178 * because we only have 1 thread per taskq. Finally cleanup the taskq.
f1ca4da6
BB
179 */
180static void
7c50328b 181splat_taskq_test2_func1(void *arg)
f1ca4da6 182{
7c50328b 183 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
f1ca4da6
BB
184
185 ASSERT(tq_arg);
7c50328b 186 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6
BB
187 "Taskq '%s/%d' function '%s' flag = %d = %d * 2\n",
188 tq_arg->name, tq_arg->id,
7c50328b 189 sym2str(splat_taskq_test2_func1),
f1ca4da6
BB
190 tq_arg->flag * 2, tq_arg->flag);
191 tq_arg->flag *= 2;
192}
193
194static void
7c50328b 195splat_taskq_test2_func2(void *arg)
f1ca4da6 196{
7c50328b 197 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
f1ca4da6
BB
198
199 ASSERT(tq_arg);
7c50328b 200 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6
BB
201 "Taskq '%s/%d' function '%s' flag = %d = %d + 1\n",
202 tq_arg->name, tq_arg->id,
7c50328b 203 sym2str(splat_taskq_test2_func2),
f1ca4da6
BB
204 tq_arg->flag + 1, tq_arg->flag);
205 tq_arg->flag += 1;
206}
207
208#define TEST2_TASKQS 8
5562e5d1 209#define TEST2_THREADS_PER_TASKQ 1
bcd68186 210
f1ca4da6 211static int
699d5ee8 212splat_taskq_test2_impl(struct file *file, void *arg, boolean_t prealloc) {
f1ca4da6
BB
213 taskq_t *tq[TEST2_TASKQS] = { NULL };
214 taskqid_t id;
7c50328b 215 splat_taskq_arg_t tq_args[TEST2_TASKQS];
699d5ee8
PS
216 taskq_ent_t *func1_tqes = NULL;
217 taskq_ent_t *func2_tqes = NULL;
f1ca4da6
BB
218 int i, rc = 0;
219
699d5ee8
PS
220 func1_tqes = kmalloc(sizeof(*func1_tqes) * TEST2_TASKQS, GFP_KERNEL);
221 if (func1_tqes == NULL) {
222 rc = -ENOMEM;
223 goto out;
224 }
225
226 func2_tqes = kmalloc(sizeof(*func2_tqes) * TEST2_TASKQS, GFP_KERNEL);
227 if (func2_tqes == NULL) {
228 rc = -ENOMEM;
229 goto out;
230 }
231
f1ca4da6 232 for (i = 0; i < TEST2_TASKQS; i++) {
699d5ee8
PS
233 taskq_init_ent(&func1_tqes[i]);
234 taskq_init_ent(&func2_tqes[i]);
f1ca4da6 235
699d5ee8
PS
236 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
237 "Taskq '%s/%d' creating (%s dispatch)\n",
238 SPLAT_TASKQ_TEST2_NAME, i,
239 prealloc ? "prealloc" : "dynamic");
7c50328b 240 if ((tq[i] = taskq_create(SPLAT_TASKQ_TEST2_NAME,
bcd68186
BB
241 TEST2_THREADS_PER_TASKQ,
242 maxclsyspri, 50, INT_MAX,
243 TASKQ_PREPOPULATE)) == NULL) {
7c50328b 244 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6 245 "Taskq '%s/%d' create failed\n",
7c50328b 246 SPLAT_TASKQ_TEST2_NAME, i);
f1ca4da6
BB
247 rc = -EINVAL;
248 break;
249 }
250
251 tq_args[i].flag = i;
252 tq_args[i].id = i;
253 tq_args[i].file = file;
7c50328b 254 tq_args[i].name = SPLAT_TASKQ_TEST2_NAME;
f1ca4da6 255
7c50328b 256 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6 257 "Taskq '%s/%d' function '%s' dispatching\n",
7c50328b
BB
258 tq_args[i].name, tq_args[i].id,
259 sym2str(splat_taskq_test2_func1));
699d5ee8
PS
260 if (prealloc) {
261 taskq_dispatch_ent(tq[i], splat_taskq_test2_func1,
262 &tq_args[i], TQ_SLEEP, &func1_tqes[i]);
263 id = func1_tqes[i].tqent_id;
264 } else {
265 id = taskq_dispatch(tq[i], splat_taskq_test2_func1,
266 &tq_args[i], TQ_SLEEP);
267 }
268
269 if (id == 0) {
7c50328b 270 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6
BB
271 "Taskq '%s/%d' function '%s' dispatch "
272 "failed\n", tq_args[i].name, tq_args[i].id,
7c50328b 273 sym2str(splat_taskq_test2_func1));
f1ca4da6
BB
274 rc = -EINVAL;
275 break;
276 }
277
7c50328b 278 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6 279 "Taskq '%s/%d' function '%s' dispatching\n",
7c50328b
BB
280 tq_args[i].name, tq_args[i].id,
281 sym2str(splat_taskq_test2_func2));
699d5ee8
PS
282 if (prealloc) {
283 taskq_dispatch_ent(tq[i], splat_taskq_test2_func2,
284 &tq_args[i], TQ_SLEEP, &func2_tqes[i]);
285 id = func2_tqes[i].tqent_id;
286 } else {
287 id = taskq_dispatch(tq[i], splat_taskq_test2_func2,
288 &tq_args[i], TQ_SLEEP);
289 }
290
291 if (id == 0) {
292 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq "
293 "'%s/%d' function '%s' dispatch failed\n",
294 tq_args[i].name, tq_args[i].id,
295 sym2str(splat_taskq_test2_func2));
f1ca4da6
BB
296 rc = -EINVAL;
297 break;
298 }
299 }
300
301 /* When rc is set we're effectively just doing cleanup here, so
302 * ignore new errors in that case. They just cause noise. */
303 for (i = 0; i < TEST2_TASKQS; i++) {
304 if (tq[i] != NULL) {
7c50328b 305 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6
BB
306 "Taskq '%s/%d' waiting\n",
307 tq_args[i].name, tq_args[i].id);
308 taskq_wait(tq[i]);
7c50328b 309 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6
BB
310 "Taskq '%s/%d; destroying\n",
311 tq_args[i].name, tq_args[i].id);
699d5ee8 312
4098c921 313 taskq_destroy(tq[i]);
f1ca4da6
BB
314
315 if (!rc && tq_args[i].flag != ((i * 2) + 1)) {
7c50328b 316 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6
BB
317 "Taskq '%s/%d' processed tasks "
318 "out of order; %d != %d\n",
319 tq_args[i].name, tq_args[i].id,
320 tq_args[i].flag, i * 2 + 1);
321 rc = -EINVAL;
322 } else {
7c50328b 323 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6
BB
324 "Taskq '%s/%d' processed tasks "
325 "in the correct order; %d == %d\n",
326 tq_args[i].name, tq_args[i].id,
327 tq_args[i].flag, i * 2 + 1);
328 }
329 }
330 }
699d5ee8
PS
331out:
332 if (func1_tqes)
333 kfree(func1_tqes);
334
335 if (func2_tqes)
336 kfree(func2_tqes);
337
338 return rc;
339}
340
341static int
342splat_taskq_test2(struct file *file, void *arg) {
343 int rc;
344
345 rc = splat_taskq_test2_impl(file, arg, B_FALSE);
346 if (rc)
347 return rc;
348
349 rc = splat_taskq_test2_impl(file, arg, B_TRUE);
f1ca4da6
BB
350
351 return rc;
352}
353
5562e5d1
BB
354/*
355 * Use the global system task queue with a single task, wait until task
356 * completes, ensure task ran properly.
e9cb2b4f
BB
357 */
358static int
699d5ee8 359splat_taskq_test3_impl(struct file *file, void *arg, boolean_t prealloc)
e9cb2b4f
BB
360{
361 taskqid_t id;
362 splat_taskq_arg_t tq_arg;
699d5ee8
PS
363 taskq_ent_t tqe;
364
365 taskq_init_ent(&tqe);
e9cb2b4f
BB
366
367 tq_arg.flag = 0;
368 tq_arg.id = 0;
369 tq_arg.file = file;
370 tq_arg.name = SPLAT_TASKQ_TEST3_NAME;
371
372 splat_vprint(file, SPLAT_TASKQ_TEST3_NAME,
699d5ee8
PS
373 "Taskq '%s' function '%s' %s dispatch\n",
374 tq_arg.name, sym2str(splat_taskq_test13_func),
375 prealloc ? "prealloc" : "dynamic");
376 if (prealloc) {
377 taskq_dispatch_ent(system_taskq, splat_taskq_test13_func,
378 &tq_arg, TQ_SLEEP, &tqe);
379 id = tqe.tqent_id;
380 } else {
381 id = taskq_dispatch(system_taskq, splat_taskq_test13_func,
382 &tq_arg, TQ_SLEEP);
383 }
384
385 if (id == 0) {
e9cb2b4f
BB
386 splat_vprint(file, SPLAT_TASKQ_TEST3_NAME,
387 "Taskq '%s' function '%s' dispatch failed\n",
388 tq_arg.name, sym2str(splat_taskq_test13_func));
389 return -EINVAL;
390 }
391
392 splat_vprint(file, SPLAT_TASKQ_TEST3_NAME, "Taskq '%s' waiting\n",
393 tq_arg.name);
394 taskq_wait(system_taskq);
395
396 return (tq_arg.flag) ? 0 : -EINVAL;
397}
398
699d5ee8
PS
399static int
400splat_taskq_test3(struct file *file, void *arg)
401{
402 int rc;
403
404 rc = splat_taskq_test3_impl(file, arg, B_FALSE);
405 if (rc)
406 return rc;
407
408 rc = splat_taskq_test3_impl(file, arg, B_TRUE);
409
410 return rc;
411}
412
5562e5d1
BB
413/*
414 * Create a taskq and dispatch a large number of tasks to the queue.
415 * Then use taskq_wait() to block until all the tasks complete, then
416 * cross check that all the tasks ran by checking tg_arg->count which
417 * is incremented in the task function. Finally cleanup the taskq.
26f7245c
RC
418 *
419 * First we try with a large 'maxalloc' value, then we try with a small one.
420 * We should not drop tasks when TQ_SLEEP is used in taskq_dispatch(), even
421 * if the number of pending tasks is above maxalloc.
5562e5d1 422 */
7257ec41
BB
423static void
424splat_taskq_test4_func(void *arg)
425{
426 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
427 ASSERT(tq_arg);
428
429 atomic_inc(&tq_arg->count);
430}
431
432static int
26f7245c 433splat_taskq_test4_common(struct file *file, void *arg, int minalloc,
699d5ee8 434 int maxalloc, int nr_tasks, boolean_t prealloc)
7257ec41
BB
435{
436 taskq_t *tq;
699d5ee8 437 taskqid_t id;
7257ec41 438 splat_taskq_arg_t tq_arg;
699d5ee8 439 taskq_ent_t *tqes;
7257ec41
BB
440 int i, j, rc = 0;
441
699d5ee8
PS
442 tqes = kmalloc(sizeof(*tqes) * nr_tasks, GFP_KERNEL);
443 if (tqes == NULL)
444 return -ENOMEM;
445
446 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
447 "Taskq '%s' creating (%s dispatch) (%d/%d/%d)\n",
448 SPLAT_TASKQ_TEST4_NAME,
449 prealloc ? "prealloc" : "dynamic",
450 minalloc, maxalloc, nr_tasks);
7257ec41 451 if ((tq = taskq_create(SPLAT_TASKQ_TEST4_NAME, 1, maxclsyspri,
26f7245c 452 minalloc, maxalloc, TASKQ_PREPOPULATE)) == NULL) {
7257ec41
BB
453 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
454 "Taskq '%s' create failed\n",
455 SPLAT_TASKQ_TEST4_NAME);
699d5ee8
PS
456 rc = -EINVAL;
457 goto out_free;
7257ec41
BB
458 }
459
460 tq_arg.file = file;
461 tq_arg.name = SPLAT_TASKQ_TEST4_NAME;
462
26f7245c 463 for (i = 1; i <= nr_tasks; i *= 2) {
7257ec41
BB
464 atomic_set(&tq_arg.count, 0);
465 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
466 "Taskq '%s' function '%s' dispatched %d times\n",
467 tq_arg.name, sym2str(splat_taskq_test4_func), i);
468
469 for (j = 0; j < i; j++) {
699d5ee8
PS
470 taskq_init_ent(&tqes[j]);
471
472 if (prealloc) {
473 taskq_dispatch_ent(tq, splat_taskq_test4_func,
474 &tq_arg, TQ_SLEEP, &tqes[j]);
475 id = tqes[j].tqent_id;
476 } else {
477 id = taskq_dispatch(tq, splat_taskq_test4_func,
478 &tq_arg, TQ_SLEEP);
479 }
480
481 if (id == 0) {
7257ec41
BB
482 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
483 "Taskq '%s' function '%s' dispatch "
484 "%d failed\n", tq_arg.name,
e05bec80 485 sym2str(splat_taskq_test4_func), j);
7257ec41
BB
486 rc = -EINVAL;
487 goto out;
488 }
489 }
490
491 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' "
492 "waiting for %d dispatches\n", tq_arg.name, i);
493 taskq_wait(tq);
494 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' "
495 "%d/%d dispatches finished\n", tq_arg.name,
496 atomic_read(&tq_arg.count), i);
497 if (atomic_read(&tq_arg.count) != i) {
498 rc = -ERANGE;
499 goto out;
500
501 }
502 }
503out:
504 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' destroying\n",
505 tq_arg.name);
506 taskq_destroy(tq);
507
699d5ee8
PS
508out_free:
509 kfree(tqes);
510
7257ec41
BB
511 return rc;
512}
513
699d5ee8
PS
514static int
515splat_taskq_test4_impl(struct file *file, void *arg, boolean_t prealloc)
516{
517 int rc;
518
519 rc = splat_taskq_test4_common(file, arg, 50, INT_MAX, 1024, prealloc);
520 if (rc)
521 return rc;
522
523 rc = splat_taskq_test4_common(file, arg, 1, 1, 32, prealloc);
524
525 return rc;
526}
527
528static int
529splat_taskq_test4(struct file *file, void *arg)
26f7245c
RC
530{
531 int rc;
532
699d5ee8 533 rc = splat_taskq_test4_impl(file, arg, B_FALSE);
26f7245c
RC
534 if (rc)
535 return rc;
536
699d5ee8 537 rc = splat_taskq_test4_impl(file, arg, B_TRUE);
26f7245c
RC
538
539 return rc;
540}
541
5562e5d1
BB
542/*
543 * Create a taskq and dispatch a specific sequence of tasks carefully
544 * crafted to validate the order in which tasks are processed. When
545 * there are multiple worker threads each thread will process the
546 * next pending task as soon as it completes its current task. This
547 * means that tasks do not strictly complete in order in which they
548 * were dispatched (increasing task id). This is fine but we need to
549 * verify that taskq_wait_id() blocks until the passed task id and all
550 * lower task ids complete. We do this by dispatching the following
551 * specific sequence of tasks each of which block for N time units.
552 * We then use taskq_wait_id() to unblock at specific task id and
553 * verify the only the expected task ids have completed and in the
554 * correct order. The two cases of interest are:
555 *
556 * 1) Task ids larger than the waited for task id can run and
557 * complete as long as there is an available worker thread.
558 * 2) All task ids lower than the waited one must complete before
559 * unblocking even if the waited task id itself has completed.
560 *
561 * The following table shows each task id and how they will be
562 * scheduled. Each rows represent one time unit and each column
563 * one of the three worker threads. The places taskq_wait_id()
564 * must unblock for a specific id are identified as well as the
565 * task ids which must have completed and their order.
566 *
567 * +-----+ <--- taskq_wait_id(tq, 8) unblocks
55f10ae5 568 * | | Required Completion Order: 1,2,4,5,3,8,6,7
5562e5d1
BB
569 * +-----+ |
570 * | | |
571 * | | +-----+
572 * | | | 8 |
573 * | | +-----+ <--- taskq_wait_id(tq, 3) unblocks
55f10ae5 574 * | | 7 | | Required Completion Order: 1,2,4,5,3
5562e5d1
BB
575 * | +-----+ |
576 * | 6 | | |
577 * +-----+ | |
578 * | | 5 | |
579 * | +-----+ |
580 * | 4 | | |
581 * +-----+ | |
582 * | 1 | 2 | 3 |
583 * +-----+-----+-----+
584 *
585 */
586static void
587splat_taskq_test5_func(void *arg)
588{
589 splat_taskq_id_t *tq_id = (splat_taskq_id_t *)arg;
590 splat_taskq_arg_t *tq_arg = tq_id->arg;
591 int factor;
592
593 /* Delays determined by above table */
594 switch (tq_id->id) {
595 default: factor = 0; break;
596 case 1: case 8: factor = 1; break;
597 case 2: case 4: case 5: factor = 2; break;
598 case 6: case 7: factor = 4; break;
599 case 3: factor = 5; break;
600 }
601
602 msleep(factor * 100);
603 splat_vprint(tq_arg->file, tq_arg->name,
604 "Taskqid %d complete for taskq '%s'\n",
605 tq_id->id, tq_arg->name);
606
607 spin_lock(&tq_arg->lock);
608 tq_arg->order[tq_arg->flag] = tq_id->id;
609 tq_arg->flag++;
610 spin_unlock(&tq_arg->lock);
611}
612
613static int
55f10ae5 614splat_taskq_test_order(splat_taskq_arg_t *tq_arg, int *order)
5562e5d1
BB
615{
616 int i, j;
617
618 for (i = 0; i < SPLAT_TASKQ_ORDER_MAX; i++) {
619 if (tq_arg->order[i] != order[i]) {
55f10ae5 620 splat_vprint(tq_arg->file, tq_arg->name,
5562e5d1
BB
621 "Taskq '%s' incorrect completion "
622 "order\n", tq_arg->name);
55f10ae5 623 splat_vprint(tq_arg->file, tq_arg->name,
5562e5d1
BB
624 "%s", "Expected { ");
625
626 for (j = 0; j < SPLAT_TASKQ_ORDER_MAX; j++)
627 splat_print(tq_arg->file, "%d ", order[j]);
628
629 splat_print(tq_arg->file, "%s", "}\n");
55f10ae5 630 splat_vprint(tq_arg->file, tq_arg->name,
5562e5d1
BB
631 "%s", "Got { ");
632
633 for (j = 0; j < SPLAT_TASKQ_ORDER_MAX; j++)
634 splat_print(tq_arg->file, "%d ",
635 tq_arg->order[j]);
636
637 splat_print(tq_arg->file, "%s", "}\n");
638 return -EILSEQ;
639 }
640 }
641
55f10ae5 642 splat_vprint(tq_arg->file, tq_arg->name,
5562e5d1
BB
643 "Taskq '%s' validated correct completion order\n",
644 tq_arg->name);
645
646 return 0;
647}
648
649static int
699d5ee8 650splat_taskq_test5_impl(struct file *file, void *arg, boolean_t prealloc)
5562e5d1
BB
651{
652 taskq_t *tq;
653 taskqid_t id;
654 splat_taskq_id_t tq_id[SPLAT_TASKQ_ORDER_MAX];
655 splat_taskq_arg_t tq_arg;
656 int order1[SPLAT_TASKQ_ORDER_MAX] = { 1,2,4,5,3,0,0,0 };
657 int order2[SPLAT_TASKQ_ORDER_MAX] = { 1,2,4,5,3,8,6,7 };
699d5ee8 658 taskq_ent_t tqes[SPLAT_TASKQ_ORDER_MAX];
5562e5d1
BB
659 int i, rc = 0;
660
699d5ee8
PS
661 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
662 "Taskq '%s' creating (%s dispatch)\n",
663 SPLAT_TASKQ_TEST5_NAME,
664 prealloc ? "prealloc" : "dynamic");
5562e5d1
BB
665 if ((tq = taskq_create(SPLAT_TASKQ_TEST5_NAME, 3, maxclsyspri,
666 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
667 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
668 "Taskq '%s' create failed\n",
669 SPLAT_TASKQ_TEST5_NAME);
670 return -EINVAL;
671 }
672
673 tq_arg.flag = 0;
674 memset(&tq_arg.order, 0, sizeof(int) * SPLAT_TASKQ_ORDER_MAX);
675 spin_lock_init(&tq_arg.lock);
676 tq_arg.file = file;
677 tq_arg.name = SPLAT_TASKQ_TEST5_NAME;
678
679 for (i = 0; i < SPLAT_TASKQ_ORDER_MAX; i++) {
699d5ee8
PS
680 taskq_init_ent(&tqes[i]);
681
5562e5d1
BB
682 tq_id[i].id = i + 1;
683 tq_id[i].arg = &tq_arg;
684
699d5ee8
PS
685 if (prealloc) {
686 taskq_dispatch_ent(tq, splat_taskq_test5_func,
687 &tq_id[i], TQ_SLEEP, &tqes[i]);
688 id = tqes[i].tqent_id;
689 } else {
690 id = taskq_dispatch(tq, splat_taskq_test5_func,
691 &tq_id[i], TQ_SLEEP);
692 }
693
694 if (id == 0) {
5562e5d1
BB
695 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
696 "Taskq '%s' function '%s' dispatch failed\n",
697 tq_arg.name, sym2str(splat_taskq_test5_func));
698 rc = -EINVAL;
699 goto out;
700 }
701
702 if (tq_id[i].id != id) {
703 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
704 "Taskq '%s' expected taskqid %d got %d\n",
705 tq_arg.name, (int)tq_id[i].id, (int)id);
706 rc = -EINVAL;
707 goto out;
708 }
709 }
710
711 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' "
712 "waiting for taskqid %d completion\n", tq_arg.name, 3);
713 taskq_wait_id(tq, 3);
55f10ae5 714 if ((rc = splat_taskq_test_order(&tq_arg, order1)))
5562e5d1
BB
715 goto out;
716
717 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' "
718 "waiting for taskqid %d completion\n", tq_arg.name, 8);
719 taskq_wait_id(tq, 8);
55f10ae5 720 rc = splat_taskq_test_order(&tq_arg, order2);
5562e5d1
BB
721
722out:
723 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
724 "Taskq '%s' destroying\n", tq_arg.name);
725 taskq_destroy(tq);
726
727 return rc;
728}
729
699d5ee8
PS
730static int
731splat_taskq_test5(struct file *file, void *arg)
732{
733 int rc;
734
735 rc = splat_taskq_test5_impl(file, arg, B_FALSE);
736 if (rc)
737 return rc;
738
739 rc = splat_taskq_test5_impl(file, arg, B_TRUE);
740
741 return rc;
742}
743
55f10ae5
NB
744/*
745 * Create a single task queue with three threads. Dispatch 8 tasks,
746 * setting TQ_FRONT on only the last three. Sleep after
747 * dispatching tasks 1-3 to ensure they will run and hold the threads
748 * busy while we dispatch the remaining tasks. Verify that tasks 6-8
749 * run before task 4-5.
750 *
751 * The following table shows each task id and how they will be
752 * scheduled. Each rows represent one time unit and each column
753 * one of the three worker threads.
754 *
755 * +-----+
756 * | |
757 * +-----+ |
758 * | | 5 +-----+
759 * | | | |
760 * | +-----| |
761 * | 4 | | |
762 * +-----+ | 8 |
763 * | | | |
764 * | | 7 +-----+
765 * | | | |
766 * | |-----+ |
767 * | 6 | | |
768 * +-----+ | |
769 * | | | |
770 * | 1 | 2 | 3 |
771 * +-----+-----+-----+
772 *
773 */
774static void
775splat_taskq_test6_func(void *arg)
776{
777 splat_taskq_id_t *tq_id = (splat_taskq_id_t *)arg;
778 splat_taskq_arg_t *tq_arg = tq_id->arg;
779 int factor;
780
781 /* Delays determined by above table */
782 switch (tq_id->id) {
783 default: factor = 0; break;
784 case 1: factor = 2; break;
785 case 2: case 4: case 5: factor = 4; break;
786 case 6: case 7: case 8: factor = 5; break;
787 case 3: factor = 6; break;
788 }
789
790 msleep(factor * 100);
791
792 splat_vprint(tq_arg->file, tq_arg->name,
793 "Taskqid %d complete for taskq '%s'\n",
794 tq_id->id, tq_arg->name);
795
796 spin_lock(&tq_arg->lock);
797 tq_arg->order[tq_arg->flag] = tq_id->id;
798 tq_arg->flag++;
799 spin_unlock(&tq_arg->lock);
800}
801
802static int
699d5ee8 803splat_taskq_test6_impl(struct file *file, void *arg, boolean_t prealloc)
55f10ae5
NB
804{
805 taskq_t *tq;
806 taskqid_t id;
807 splat_taskq_id_t tq_id[SPLAT_TASKQ_ORDER_MAX];
808 splat_taskq_arg_t tq_arg;
809 int order[SPLAT_TASKQ_ORDER_MAX] = { 1,2,3,6,7,8,4,5 };
699d5ee8 810 taskq_ent_t tqes[SPLAT_TASKQ_ORDER_MAX];
55f10ae5
NB
811 int i, rc = 0;
812 uint_t tflags;
813
699d5ee8
PS
814 splat_vprint(file, SPLAT_TASKQ_TEST6_NAME,
815 "Taskq '%s' creating (%s dispatch)\n",
816 SPLAT_TASKQ_TEST6_NAME,
817 prealloc ? "prealloc" : "dynamic");
55f10ae5
NB
818 if ((tq = taskq_create(SPLAT_TASKQ_TEST6_NAME, 3, maxclsyspri,
819 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
820 splat_vprint(file, SPLAT_TASKQ_TEST6_NAME,
821 "Taskq '%s' create failed\n",
822 SPLAT_TASKQ_TEST6_NAME);
823 return -EINVAL;
824 }
825
826 tq_arg.flag = 0;
827 memset(&tq_arg.order, 0, sizeof(int) * SPLAT_TASKQ_ORDER_MAX);
828 spin_lock_init(&tq_arg.lock);
829 tq_arg.file = file;
830 tq_arg.name = SPLAT_TASKQ_TEST6_NAME;
831
832 for (i = 0; i < SPLAT_TASKQ_ORDER_MAX; i++) {
699d5ee8
PS
833 taskq_init_ent(&tqes[i]);
834
55f10ae5
NB
835 tq_id[i].id = i + 1;
836 tq_id[i].arg = &tq_arg;
837 tflags = TQ_SLEEP;
838 if (i > 4)
839 tflags |= TQ_FRONT;
840
699d5ee8
PS
841 if (prealloc) {
842 taskq_dispatch_ent(tq, splat_taskq_test6_func,
843 &tq_id[i], tflags, &tqes[i]);
844 id = tqes[i].tqent_id;
845 } else {
846 id = taskq_dispatch(tq, splat_taskq_test6_func,
847 &tq_id[i], tflags);
848 }
849
850 if (id == 0) {
55f10ae5
NB
851 splat_vprint(file, SPLAT_TASKQ_TEST6_NAME,
852 "Taskq '%s' function '%s' dispatch failed\n",
853 tq_arg.name, sym2str(splat_taskq_test6_func));
854 rc = -EINVAL;
855 goto out;
856 }
857
858 if (tq_id[i].id != id) {
859 splat_vprint(file, SPLAT_TASKQ_TEST6_NAME,
860 "Taskq '%s' expected taskqid %d got %d\n",
861 tq_arg.name, (int)tq_id[i].id, (int)id);
862 rc = -EINVAL;
863 goto out;
864 }
865 /* Sleep to let tasks 1-3 start executing. */
866 if ( i == 2 )
867 msleep(100);
868 }
869
870 splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, "Taskq '%s' "
871 "waiting for taskqid %d completion\n", tq_arg.name,
872 SPLAT_TASKQ_ORDER_MAX);
873 taskq_wait_id(tq, SPLAT_TASKQ_ORDER_MAX);
874 rc = splat_taskq_test_order(&tq_arg, order);
875
876out:
877 splat_vprint(file, SPLAT_TASKQ_TEST6_NAME,
878 "Taskq '%s' destroying\n", tq_arg.name);
879 taskq_destroy(tq);
880
881 return rc;
882}
883
699d5ee8
PS
884static int
885splat_taskq_test6(struct file *file, void *arg)
886{
887 int rc;
888
889 rc = splat_taskq_test6_impl(file, arg, B_FALSE);
890 if (rc)
891 return rc;
892
893 rc = splat_taskq_test6_impl(file, arg, B_TRUE);
894
895 return rc;
896}
897
ac1e5b60
PS
898static void
899splat_taskq_test7_func(void *arg)
900{
901 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
902 taskqid_t id;
903
904 ASSERT(tq_arg);
905
906 if (tq_arg->depth >= SPLAT_TASKQ_DEPTH_MAX)
907 return;
908
909 tq_arg->depth++;
910
911 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST7_NAME,
912 "Taskq '%s' function '%s' dispatching (depth = %u)\n",
913 tq_arg->name, sym2str(splat_taskq_test7_func),
914 tq_arg->depth);
915
699d5ee8
PS
916 if (tq_arg->tqe) {
917 VERIFY(taskq_empty_ent(tq_arg->tqe));
918 taskq_dispatch_ent(tq_arg->tq, splat_taskq_test7_func,
919 tq_arg, TQ_SLEEP, tq_arg->tqe);
920 id = tq_arg->tqe->tqent_id;
921 } else {
922 id = taskq_dispatch(tq_arg->tq, splat_taskq_test7_func,
923 tq_arg, TQ_SLEEP);
924 }
925
926 if (id == 0) {
ac1e5b60
PS
927 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST7_NAME,
928 "Taskq '%s' function '%s' dispatch failed "
929 "(depth = %u)\n", tq_arg->name,
930 sym2str(splat_taskq_test7_func), tq_arg->depth);
931 tq_arg->flag = -EINVAL;
932 return;
933 }
934}
935
936static int
699d5ee8 937splat_taskq_test7_impl(struct file *file, void *arg, boolean_t prealloc)
ac1e5b60
PS
938{
939 taskq_t *tq;
699d5ee8 940 taskq_ent_t tqe;
ac1e5b60
PS
941 splat_taskq_arg_t tq_arg;
942
943 splat_vprint(file, SPLAT_TASKQ_TEST7_NAME,
699d5ee8
PS
944 "Taskq '%s' creating (%s dispatch)\n",
945 SPLAT_TASKQ_TEST7_NAME,
946 prealloc ? "prealloc" : "dynamic");
ac1e5b60
PS
947 if ((tq = taskq_create(SPLAT_TASKQ_TEST7_NAME, 1, maxclsyspri,
948 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
949 splat_vprint(file, SPLAT_TASKQ_TEST7_NAME,
950 "Taskq '%s' create failed\n",
951 SPLAT_TASKQ_TEST7_NAME);
952 return -EINVAL;
953 }
954
955 tq_arg.depth = 0;
956 tq_arg.flag = 0;
957 tq_arg.id = 0;
958 tq_arg.file = file;
959 tq_arg.name = SPLAT_TASKQ_TEST7_NAME;
960 tq_arg.tq = tq;
961
699d5ee8
PS
962 if (prealloc) {
963 taskq_init_ent(&tqe);
964 tq_arg.tqe = &tqe;
965 } else {
966 tq_arg.tqe = NULL;
967 }
968
ac1e5b60
PS
969 splat_taskq_test7_func(&tq_arg);
970
971 if (tq_arg.flag == 0) {
972 splat_vprint(file, SPLAT_TASKQ_TEST7_NAME,
973 "Taskq '%s' waiting\n", tq_arg.name);
974 taskq_wait_id(tq, SPLAT_TASKQ_DEPTH_MAX);
975 }
976
977 splat_vprint(file, SPLAT_TASKQ_TEST7_NAME,
978 "Taskq '%s' destroying\n", tq_arg.name);
979 taskq_destroy(tq);
980
981 return tq_arg.depth == SPLAT_TASKQ_DEPTH_MAX ? 0 : -EINVAL;
982}
983
699d5ee8
PS
984static int
985splat_taskq_test7(struct file *file, void *arg)
986{
987 int rc;
988
989 rc = splat_taskq_test7_impl(file, arg, B_FALSE);
990 if (rc)
991 return rc;
992
993 rc = splat_taskq_test7_impl(file, arg, B_TRUE);
994
995 return rc;
996}
997
cf5d23fa
NB
998/*
999 * Create a taskq with 100 threads and dispatch a huge number of trivial
1000 * tasks to generate contention on tq->tq_lock. This test should always
1001 * pass. The purpose is to provide a benchmark for measuring the
1002 * effectiveness of taskq optimizations.
1003 */
1004static void
1005splat_taskq_test8_func(void *arg)
1006{
1007 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
1008 ASSERT(tq_arg);
1009
1010 atomic_inc(&tq_arg->count);
1011}
1012
1013#define TEST8_NUM_TASKS 0x20000
1014#define TEST8_THREADS_PER_TASKQ 100
1015
1016static int
1017splat_taskq_test8_common(struct file *file, void *arg, int minalloc,
1018 int maxalloc)
1019{
1020 taskq_t *tq;
1021 taskqid_t id;
1022 splat_taskq_arg_t tq_arg;
1023 taskq_ent_t **tqes;
1024 int i, j, rc = 0;
1025
1026 tqes = vmalloc(sizeof(*tqes) * TEST8_NUM_TASKS);
1027 if (tqes == NULL)
1028 return -ENOMEM;
1029 memset(tqes, 0, sizeof(*tqes) * TEST8_NUM_TASKS);
1030
1031 splat_vprint(file, SPLAT_TASKQ_TEST8_NAME,
1032 "Taskq '%s' creating (%d/%d/%d)\n",
1033 SPLAT_TASKQ_TEST8_NAME,
1034 minalloc, maxalloc, TEST8_NUM_TASKS);
1035 if ((tq = taskq_create(SPLAT_TASKQ_TEST8_NAME, TEST8_THREADS_PER_TASKQ,
1036 maxclsyspri, minalloc, maxalloc,
1037 TASKQ_PREPOPULATE)) == NULL) {
1038 splat_vprint(file, SPLAT_TASKQ_TEST8_NAME,
1039 "Taskq '%s' create failed\n",
1040 SPLAT_TASKQ_TEST8_NAME);
1041 rc = -EINVAL;
1042 goto out_free;
1043 }
1044
1045 tq_arg.file = file;
1046 tq_arg.name = SPLAT_TASKQ_TEST8_NAME;
1047
1048 atomic_set(&tq_arg.count, 0);
1049 for (i = 0; i < TEST8_NUM_TASKS; i++) {
1050 tqes[i] = kmalloc(sizeof(taskq_ent_t), GFP_KERNEL);
1051 if (tqes[i] == NULL) {
1052 rc = -ENOMEM;
1053 goto out;
1054 }
1055 taskq_init_ent(tqes[i]);
1056
1057 taskq_dispatch_ent(tq, splat_taskq_test8_func,
1058 &tq_arg, TQ_SLEEP, tqes[i]);
1059
1060 id = tqes[i]->tqent_id;
1061
1062 if (id == 0) {
1063 splat_vprint(file, SPLAT_TASKQ_TEST8_NAME,
1064 "Taskq '%s' function '%s' dispatch "
1065 "%d failed\n", tq_arg.name,
1066 sym2str(splat_taskq_test8_func), i);
1067 rc = -EINVAL;
1068 goto out;
1069 }
1070 }
1071
1072 splat_vprint(file, SPLAT_TASKQ_TEST8_NAME, "Taskq '%s' "
1073 "waiting for %d dispatches\n", tq_arg.name,
1074 TEST8_NUM_TASKS);
1075 taskq_wait(tq);
1076 splat_vprint(file, SPLAT_TASKQ_TEST8_NAME, "Taskq '%s' "
1077 "%d/%d dispatches finished\n", tq_arg.name,
1078 atomic_read(&tq_arg.count), TEST8_NUM_TASKS);
1079
1080 if (atomic_read(&tq_arg.count) != TEST8_NUM_TASKS)
1081 rc = -ERANGE;
1082
1083out:
1084 splat_vprint(file, SPLAT_TASKQ_TEST8_NAME, "Taskq '%s' destroying\n",
1085 tq_arg.name);
1086 taskq_destroy(tq);
1087out_free:
1088 for (j = 0; j < TEST8_NUM_TASKS && tqes[j] != NULL; j++)
1089 kfree(tqes[j]);
1090 vfree(tqes);
1091
1092 return rc;
1093}
1094
1095static int
1096splat_taskq_test8(struct file *file, void *arg)
1097{
1098 int rc;
1099
1100 rc = splat_taskq_test8_common(file, arg, 1, 100);
1101
1102 return rc;
1103}
1104
7c50328b
BB
1105splat_subsystem_t *
1106splat_taskq_init(void)
f1ca4da6 1107{
7c50328b 1108 splat_subsystem_t *sub;
f1ca4da6
BB
1109
1110 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
1111 if (sub == NULL)
1112 return NULL;
1113
1114 memset(sub, 0, sizeof(*sub));
7c50328b
BB
1115 strncpy(sub->desc.name, SPLAT_TASKQ_NAME, SPLAT_NAME_SIZE);
1116 strncpy(sub->desc.desc, SPLAT_TASKQ_DESC, SPLAT_DESC_SIZE);
f1ca4da6
BB
1117 INIT_LIST_HEAD(&sub->subsystem_list);
1118 INIT_LIST_HEAD(&sub->test_list);
1119 spin_lock_init(&sub->test_lock);
7c50328b 1120 sub->desc.id = SPLAT_SUBSYSTEM_TASKQ;
f1ca4da6 1121
7c50328b
BB
1122 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST1_NAME, SPLAT_TASKQ_TEST1_DESC,
1123 SPLAT_TASKQ_TEST1_ID, splat_taskq_test1);
1124 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST2_NAME, SPLAT_TASKQ_TEST2_DESC,
1125 SPLAT_TASKQ_TEST2_ID, splat_taskq_test2);
e9cb2b4f
BB
1126 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST3_NAME, SPLAT_TASKQ_TEST3_DESC,
1127 SPLAT_TASKQ_TEST3_ID, splat_taskq_test3);
7257ec41
BB
1128 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST4_NAME, SPLAT_TASKQ_TEST4_DESC,
1129 SPLAT_TASKQ_TEST4_ID, splat_taskq_test4);
5562e5d1
BB
1130 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST5_NAME, SPLAT_TASKQ_TEST5_DESC,
1131 SPLAT_TASKQ_TEST5_ID, splat_taskq_test5);
55f10ae5
NB
1132 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST6_NAME, SPLAT_TASKQ_TEST6_DESC,
1133 SPLAT_TASKQ_TEST6_ID, splat_taskq_test6);
ac1e5b60
PS
1134 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST7_NAME, SPLAT_TASKQ_TEST7_DESC,
1135 SPLAT_TASKQ_TEST7_ID, splat_taskq_test7);
cf5d23fa
NB
1136 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST8_NAME, SPLAT_TASKQ_TEST8_DESC,
1137 SPLAT_TASKQ_TEST8_ID, splat_taskq_test8);
f1ca4da6
BB
1138
1139 return sub;
1140}
1141
1142void
7c50328b 1143splat_taskq_fini(splat_subsystem_t *sub)
f1ca4da6
BB
1144{
1145 ASSERT(sub);
cf5d23fa 1146 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST8_ID);
ac1e5b60 1147 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST7_ID);
ed948fa7 1148 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST6_ID);
5562e5d1 1149 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST5_ID);
7257ec41 1150 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST4_ID);
e9cb2b4f 1151 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST3_ID);
7c50328b
BB
1152 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST2_ID);
1153 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST1_ID);
f1ca4da6
BB
1154
1155 kfree(sub);
1156}
1157
1158int
7c50328b
BB
1159splat_taskq_id(void) {
1160 return SPLAT_SUBSYSTEM_TASKQ;
f1ca4da6 1161}