]> git.proxmox.com Git - mirror_spl-debian.git/blob - module/splat/splat-taskq.c
Public Release Prep
[mirror_spl-debian.git] / module / splat / splat-taskq.c
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>.
6 * UCRL-CODE-235197
7 *
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.
15 *
16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
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
22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23 *****************************************************************************
24 * Solaris Porting LAyer Tests (SPLAT) Task Queue Tests.
25 \*****************************************************************************/
26
27 #include "splat-internal.h"
28
29 #define SPLAT_TASKQ_NAME "taskq"
30 #define SPLAT_TASKQ_DESC "Kernel Task Queue Tests"
31
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"
35
36 #define SPLAT_TASKQ_TEST2_ID 0x0202
37 #define SPLAT_TASKQ_TEST2_NAME "multiple"
38 #define SPLAT_TASKQ_TEST2_DESC "Multiple task queues, multiple tasks"
39
40 #define SPLAT_TASKQ_TEST3_ID 0x0203
41 #define SPLAT_TASKQ_TEST3_NAME "system"
42 #define SPLAT_TASKQ_TEST3_DESC "System task queue, multiple tasks"
43
44 #define SPLAT_TASKQ_TEST4_ID 0x0204
45 #define SPLAT_TASKQ_TEST4_NAME "wait"
46 #define SPLAT_TASKQ_TEST4_DESC "Multiple task waiting"
47
48 #define SPLAT_TASKQ_TEST5_ID 0x0205
49 #define SPLAT_TASKQ_TEST5_NAME "order"
50 #define SPLAT_TASKQ_TEST5_DESC "Correct task ordering"
51
52 #define SPLAT_TASKQ_ORDER_MAX 8
53
54 typedef struct splat_taskq_arg {
55 int flag;
56 int id;
57 atomic_t count;
58 int order[SPLAT_TASKQ_ORDER_MAX];
59 spinlock_t lock;
60 struct file *file;
61 const char *name;
62 } splat_taskq_arg_t;
63
64 typedef struct splat_taskq_id {
65 int id;
66 splat_taskq_arg_t *arg;
67 } splat_taskq_id_t;
68
69 /*
70 * Create a taskq, queue a task, wait until task completes, ensure
71 * task ran properly, cleanup taskq.
72 */
73 static void
74 splat_taskq_test13_func(void *arg)
75 {
76 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
77
78 ASSERT(tq_arg);
79 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST1_NAME,
80 "Taskq '%s' function '%s' setting flag\n",
81 tq_arg->name, sym2str(splat_taskq_test13_func));
82 tq_arg->flag = 1;
83 }
84
85 static int
86 splat_taskq_test1(struct file *file, void *arg)
87 {
88 taskq_t *tq;
89 taskqid_t id;
90 splat_taskq_arg_t tq_arg;
91
92 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' creating\n",
93 SPLAT_TASKQ_TEST1_NAME);
94 if ((tq = taskq_create(SPLAT_TASKQ_TEST1_NAME, 1, maxclsyspri,
95 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
96 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
97 "Taskq '%s' create failed\n",
98 SPLAT_TASKQ_TEST1_NAME);
99 return -EINVAL;
100 }
101
102 tq_arg.flag = 0;
103 tq_arg.id = 0;
104 tq_arg.file = file;
105 tq_arg.name = SPLAT_TASKQ_TEST1_NAME;
106
107 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
108 "Taskq '%s' function '%s' dispatching\n",
109 tq_arg.name, sym2str(splat_taskq_test13_func));
110 if ((id = taskq_dispatch(tq, splat_taskq_test13_func,
111 &tq_arg, TQ_SLEEP)) == 0) {
112 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
113 "Taskq '%s' function '%s' dispatch failed\n",
114 tq_arg.name, sym2str(splat_taskq_test13_func));
115 taskq_destroy(tq);
116 return -EINVAL;
117 }
118
119 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' waiting\n",
120 tq_arg.name);
121 taskq_wait(tq);
122 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' destroying\n",
123 tq_arg.name);
124 taskq_destroy(tq);
125
126 return (tq_arg.flag) ? 0 : -EINVAL;
127 }
128
129 /*
130 * Create multiple taskq's, each with multiple tasks, wait until
131 * all tasks complete, ensure all tasks ran properly and in the
132 * correct order. Run order must be the same as the order submitted
133 * because we only have 1 thread per taskq. Finally cleanup the taskq.
134 */
135 static void
136 splat_taskq_test2_func1(void *arg)
137 {
138 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
139
140 ASSERT(tq_arg);
141 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST2_NAME,
142 "Taskq '%s/%d' function '%s' flag = %d = %d * 2\n",
143 tq_arg->name, tq_arg->id,
144 sym2str(splat_taskq_test2_func1),
145 tq_arg->flag * 2, tq_arg->flag);
146 tq_arg->flag *= 2;
147 }
148
149 static void
150 splat_taskq_test2_func2(void *arg)
151 {
152 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
153
154 ASSERT(tq_arg);
155 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST2_NAME,
156 "Taskq '%s/%d' function '%s' flag = %d = %d + 1\n",
157 tq_arg->name, tq_arg->id,
158 sym2str(splat_taskq_test2_func2),
159 tq_arg->flag + 1, tq_arg->flag);
160 tq_arg->flag += 1;
161 }
162
163 #define TEST2_TASKQS 8
164 #define TEST2_THREADS_PER_TASKQ 1
165
166 static int
167 splat_taskq_test2(struct file *file, void *arg) {
168 taskq_t *tq[TEST2_TASKQS] = { NULL };
169 taskqid_t id;
170 splat_taskq_arg_t tq_args[TEST2_TASKQS];
171 int i, rc = 0;
172
173 for (i = 0; i < TEST2_TASKQS; i++) {
174
175 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq '%s/%d' "
176 "creating\n", SPLAT_TASKQ_TEST2_NAME, i);
177 if ((tq[i] = taskq_create(SPLAT_TASKQ_TEST2_NAME,
178 TEST2_THREADS_PER_TASKQ,
179 maxclsyspri, 50, INT_MAX,
180 TASKQ_PREPOPULATE)) == NULL) {
181 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
182 "Taskq '%s/%d' create failed\n",
183 SPLAT_TASKQ_TEST2_NAME, i);
184 rc = -EINVAL;
185 break;
186 }
187
188 tq_args[i].flag = i;
189 tq_args[i].id = i;
190 tq_args[i].file = file;
191 tq_args[i].name = SPLAT_TASKQ_TEST2_NAME;
192
193 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
194 "Taskq '%s/%d' function '%s' dispatching\n",
195 tq_args[i].name, tq_args[i].id,
196 sym2str(splat_taskq_test2_func1));
197 if ((id = taskq_dispatch(
198 tq[i], splat_taskq_test2_func1,
199 &tq_args[i], TQ_SLEEP)) == 0) {
200 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
201 "Taskq '%s/%d' function '%s' dispatch "
202 "failed\n", tq_args[i].name, tq_args[i].id,
203 sym2str(splat_taskq_test2_func1));
204 rc = -EINVAL;
205 break;
206 }
207
208 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
209 "Taskq '%s/%d' function '%s' dispatching\n",
210 tq_args[i].name, tq_args[i].id,
211 sym2str(splat_taskq_test2_func2));
212 if ((id = taskq_dispatch(
213 tq[i], splat_taskq_test2_func2,
214 &tq_args[i], TQ_SLEEP)) == 0) {
215 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
216 "Taskq '%s/%d' function '%s' dispatch failed\n",
217 tq_args[i].name, tq_args[i].id,
218 sym2str(splat_taskq_test2_func2));
219 rc = -EINVAL;
220 break;
221 }
222 }
223
224 /* When rc is set we're effectively just doing cleanup here, so
225 * ignore new errors in that case. They just cause noise. */
226 for (i = 0; i < TEST2_TASKQS; i++) {
227 if (tq[i] != NULL) {
228 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
229 "Taskq '%s/%d' waiting\n",
230 tq_args[i].name, tq_args[i].id);
231 taskq_wait(tq[i]);
232 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
233 "Taskq '%s/%d; destroying\n",
234 tq_args[i].name, tq_args[i].id);
235 taskq_destroy(tq[i]);
236
237 if (!rc && tq_args[i].flag != ((i * 2) + 1)) {
238 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
239 "Taskq '%s/%d' processed tasks "
240 "out of order; %d != %d\n",
241 tq_args[i].name, tq_args[i].id,
242 tq_args[i].flag, i * 2 + 1);
243 rc = -EINVAL;
244 } else {
245 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
246 "Taskq '%s/%d' processed tasks "
247 "in the correct order; %d == %d\n",
248 tq_args[i].name, tq_args[i].id,
249 tq_args[i].flag, i * 2 + 1);
250 }
251 }
252 }
253
254 return rc;
255 }
256
257 /*
258 * Use the global system task queue with a single task, wait until task
259 * completes, ensure task ran properly.
260 */
261 static int
262 splat_taskq_test3(struct file *file, void *arg)
263 {
264 taskqid_t id;
265 splat_taskq_arg_t tq_arg;
266
267 tq_arg.flag = 0;
268 tq_arg.id = 0;
269 tq_arg.file = file;
270 tq_arg.name = SPLAT_TASKQ_TEST3_NAME;
271
272 splat_vprint(file, SPLAT_TASKQ_TEST3_NAME,
273 "Taskq '%s' function '%s' dispatching\n",
274 tq_arg.name, sym2str(splat_taskq_test13_func));
275 if ((id = taskq_dispatch(system_taskq, splat_taskq_test13_func,
276 &tq_arg, TQ_SLEEP)) == 0) {
277 splat_vprint(file, SPLAT_TASKQ_TEST3_NAME,
278 "Taskq '%s' function '%s' dispatch failed\n",
279 tq_arg.name, sym2str(splat_taskq_test13_func));
280 return -EINVAL;
281 }
282
283 splat_vprint(file, SPLAT_TASKQ_TEST3_NAME, "Taskq '%s' waiting\n",
284 tq_arg.name);
285 taskq_wait(system_taskq);
286
287 return (tq_arg.flag) ? 0 : -EINVAL;
288 }
289
290 /*
291 * Create a taskq and dispatch a large number of tasks to the queue.
292 * Then use taskq_wait() to block until all the tasks complete, then
293 * cross check that all the tasks ran by checking tg_arg->count which
294 * is incremented in the task function. Finally cleanup the taskq.
295 */
296 static void
297 splat_taskq_test4_func(void *arg)
298 {
299 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
300 ASSERT(tq_arg);
301
302 atomic_inc(&tq_arg->count);
303 }
304
305 static int
306 splat_taskq_test4(struct file *file, void *arg)
307 {
308 taskq_t *tq;
309 splat_taskq_arg_t tq_arg;
310 int i, j, rc = 0;
311
312 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' creating\n",
313 SPLAT_TASKQ_TEST4_NAME);
314 if ((tq = taskq_create(SPLAT_TASKQ_TEST4_NAME, 1, maxclsyspri,
315 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
316 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
317 "Taskq '%s' create failed\n",
318 SPLAT_TASKQ_TEST4_NAME);
319 return -EINVAL;
320 }
321
322 tq_arg.file = file;
323 tq_arg.name = SPLAT_TASKQ_TEST4_NAME;
324
325 for (i = 1; i <= 1024; i *= 2) {
326 atomic_set(&tq_arg.count, 0);
327 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
328 "Taskq '%s' function '%s' dispatched %d times\n",
329 tq_arg.name, sym2str(splat_taskq_test4_func), i);
330
331 for (j = 0; j < i; j++) {
332 if ((taskq_dispatch(tq, splat_taskq_test4_func,
333 &tq_arg, TQ_SLEEP)) == 0) {
334 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
335 "Taskq '%s' function '%s' dispatch "
336 "%d failed\n", tq_arg.name,
337 sym2str(splat_taskq_test13_func), j);
338 rc = -EINVAL;
339 goto out;
340 }
341 }
342
343 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' "
344 "waiting for %d dispatches\n", tq_arg.name, i);
345 taskq_wait(tq);
346 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' "
347 "%d/%d dispatches finished\n", tq_arg.name,
348 atomic_read(&tq_arg.count), i);
349 if (atomic_read(&tq_arg.count) != i) {
350 rc = -ERANGE;
351 goto out;
352
353 }
354 }
355 out:
356 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' destroying\n",
357 tq_arg.name);
358 taskq_destroy(tq);
359
360 return rc;
361 }
362
363 /*
364 * Create a taskq and dispatch a specific sequence of tasks carefully
365 * crafted to validate the order in which tasks are processed. When
366 * there are multiple worker threads each thread will process the
367 * next pending task as soon as it completes its current task. This
368 * means that tasks do not strictly complete in order in which they
369 * were dispatched (increasing task id). This is fine but we need to
370 * verify that taskq_wait_id() blocks until the passed task id and all
371 * lower task ids complete. We do this by dispatching the following
372 * specific sequence of tasks each of which block for N time units.
373 * We then use taskq_wait_id() to unblock at specific task id and
374 * verify the only the expected task ids have completed and in the
375 * correct order. The two cases of interest are:
376 *
377 * 1) Task ids larger than the waited for task id can run and
378 * complete as long as there is an available worker thread.
379 * 2) All task ids lower than the waited one must complete before
380 * unblocking even if the waited task id itself has completed.
381 *
382 * The following table shows each task id and how they will be
383 * scheduled. Each rows represent one time unit and each column
384 * one of the three worker threads. The places taskq_wait_id()
385 * must unblock for a specific id are identified as well as the
386 * task ids which must have completed and their order.
387 *
388 * +-----+ <--- taskq_wait_id(tq, 8) unblocks
389 * | | Required Completion Order: 1,2,4,5,3
390 * +-----+ |
391 * | | |
392 * | | +-----+
393 * | | | 8 |
394 * | | +-----+ <--- taskq_wait_id(tq, 3) unblocks
395 * | | 7 | | Required Completion Order: 1,2,4,5,3,8,6,7
396 * | +-----+ |
397 * | 6 | | |
398 * +-----+ | |
399 * | | 5 | |
400 * | +-----+ |
401 * | 4 | | |
402 * +-----+ | |
403 * | 1 | 2 | 3 |
404 * +-----+-----+-----+
405 *
406 */
407 static void
408 splat_taskq_test5_func(void *arg)
409 {
410 splat_taskq_id_t *tq_id = (splat_taskq_id_t *)arg;
411 splat_taskq_arg_t *tq_arg = tq_id->arg;
412 int factor;
413
414 /* Delays determined by above table */
415 switch (tq_id->id) {
416 default: factor = 0; break;
417 case 1: case 8: factor = 1; break;
418 case 2: case 4: case 5: factor = 2; break;
419 case 6: case 7: factor = 4; break;
420 case 3: factor = 5; break;
421 }
422
423 msleep(factor * 100);
424 splat_vprint(tq_arg->file, tq_arg->name,
425 "Taskqid %d complete for taskq '%s'\n",
426 tq_id->id, tq_arg->name);
427
428 spin_lock(&tq_arg->lock);
429 tq_arg->order[tq_arg->flag] = tq_id->id;
430 tq_arg->flag++;
431 spin_unlock(&tq_arg->lock);
432 }
433
434 static int
435 splat_taskq_test5_order(splat_taskq_arg_t *tq_arg, int *order)
436 {
437 int i, j;
438
439 for (i = 0; i < SPLAT_TASKQ_ORDER_MAX; i++) {
440 if (tq_arg->order[i] != order[i]) {
441 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST5_NAME,
442 "Taskq '%s' incorrect completion "
443 "order\n", tq_arg->name);
444 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST5_NAME,
445 "%s", "Expected { ");
446
447 for (j = 0; j < SPLAT_TASKQ_ORDER_MAX; j++)
448 splat_print(tq_arg->file, "%d ", order[j]);
449
450 splat_print(tq_arg->file, "%s", "}\n");
451 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST5_NAME,
452 "%s", "Got { ");
453
454 for (j = 0; j < SPLAT_TASKQ_ORDER_MAX; j++)
455 splat_print(tq_arg->file, "%d ",
456 tq_arg->order[j]);
457
458 splat_print(tq_arg->file, "%s", "}\n");
459 return -EILSEQ;
460 }
461 }
462
463 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST5_NAME,
464 "Taskq '%s' validated correct completion order\n",
465 tq_arg->name);
466
467 return 0;
468 }
469
470 static int
471 splat_taskq_test5(struct file *file, void *arg)
472 {
473 taskq_t *tq;
474 taskqid_t id;
475 splat_taskq_id_t tq_id[SPLAT_TASKQ_ORDER_MAX];
476 splat_taskq_arg_t tq_arg;
477 int order1[SPLAT_TASKQ_ORDER_MAX] = { 1,2,4,5,3,0,0,0 };
478 int order2[SPLAT_TASKQ_ORDER_MAX] = { 1,2,4,5,3,8,6,7 };
479 int i, rc = 0;
480
481 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' creating\n",
482 SPLAT_TASKQ_TEST5_NAME);
483 if ((tq = taskq_create(SPLAT_TASKQ_TEST5_NAME, 3, maxclsyspri,
484 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
485 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
486 "Taskq '%s' create failed\n",
487 SPLAT_TASKQ_TEST5_NAME);
488 return -EINVAL;
489 }
490
491 tq_arg.flag = 0;
492 memset(&tq_arg.order, 0, sizeof(int) * SPLAT_TASKQ_ORDER_MAX);
493 spin_lock_init(&tq_arg.lock);
494 tq_arg.file = file;
495 tq_arg.name = SPLAT_TASKQ_TEST5_NAME;
496
497 for (i = 0; i < SPLAT_TASKQ_ORDER_MAX; i++) {
498 tq_id[i].id = i + 1;
499 tq_id[i].arg = &tq_arg;
500
501 if ((id = taskq_dispatch(tq, splat_taskq_test5_func,
502 &tq_id[i], TQ_SLEEP)) == 0) {
503 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
504 "Taskq '%s' function '%s' dispatch failed\n",
505 tq_arg.name, sym2str(splat_taskq_test5_func));
506 rc = -EINVAL;
507 goto out;
508 }
509
510 if (tq_id[i].id != id) {
511 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
512 "Taskq '%s' expected taskqid %d got %d\n",
513 tq_arg.name, (int)tq_id[i].id, (int)id);
514 rc = -EINVAL;
515 goto out;
516 }
517 }
518
519 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' "
520 "waiting for taskqid %d completion\n", tq_arg.name, 3);
521 taskq_wait_id(tq, 3);
522 if ((rc = splat_taskq_test5_order(&tq_arg, order1)))
523 goto out;
524
525 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' "
526 "waiting for taskqid %d completion\n", tq_arg.name, 8);
527 taskq_wait_id(tq, 8);
528 rc = splat_taskq_test5_order(&tq_arg, order2);
529
530 out:
531 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
532 "Taskq '%s' destroying\n", tq_arg.name);
533 taskq_destroy(tq);
534
535 return rc;
536 }
537
538 splat_subsystem_t *
539 splat_taskq_init(void)
540 {
541 splat_subsystem_t *sub;
542
543 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
544 if (sub == NULL)
545 return NULL;
546
547 memset(sub, 0, sizeof(*sub));
548 strncpy(sub->desc.name, SPLAT_TASKQ_NAME, SPLAT_NAME_SIZE);
549 strncpy(sub->desc.desc, SPLAT_TASKQ_DESC, SPLAT_DESC_SIZE);
550 INIT_LIST_HEAD(&sub->subsystem_list);
551 INIT_LIST_HEAD(&sub->test_list);
552 spin_lock_init(&sub->test_lock);
553 sub->desc.id = SPLAT_SUBSYSTEM_TASKQ;
554
555 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST1_NAME, SPLAT_TASKQ_TEST1_DESC,
556 SPLAT_TASKQ_TEST1_ID, splat_taskq_test1);
557 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST2_NAME, SPLAT_TASKQ_TEST2_DESC,
558 SPLAT_TASKQ_TEST2_ID, splat_taskq_test2);
559 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST3_NAME, SPLAT_TASKQ_TEST3_DESC,
560 SPLAT_TASKQ_TEST3_ID, splat_taskq_test3);
561 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST4_NAME, SPLAT_TASKQ_TEST4_DESC,
562 SPLAT_TASKQ_TEST4_ID, splat_taskq_test4);
563 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST5_NAME, SPLAT_TASKQ_TEST5_DESC,
564 SPLAT_TASKQ_TEST5_ID, splat_taskq_test5);
565
566 return sub;
567 }
568
569 void
570 splat_taskq_fini(splat_subsystem_t *sub)
571 {
572 ASSERT(sub);
573 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST5_ID);
574 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST4_ID);
575 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST3_ID);
576 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST2_ID);
577 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST1_ID);
578
579 kfree(sub);
580 }
581
582 int
583 splat_taskq_id(void) {
584 return SPLAT_SUBSYSTEM_TASKQ;
585 }