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>.
8 * This file is part of the SPL, Solaris Porting Layer.
9 * For details, see <http://github.com/behlendorf/spl/>.
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.
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
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 \*****************************************************************************/
27 #include "splat-internal.h"
29 #define SPLAT_TASKQ_NAME "taskq"
30 #define SPLAT_TASKQ_DESC "Kernel Task Queue Tests"
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"
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"
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"
44 #define SPLAT_TASKQ_TEST4_ID 0x0204
45 #define SPLAT_TASKQ_TEST4_NAME "wait"
46 #define SPLAT_TASKQ_TEST4_DESC "Multiple task waiting"
48 #define SPLAT_TASKQ_TEST5_ID 0x0205
49 #define SPLAT_TASKQ_TEST5_NAME "order"
50 #define SPLAT_TASKQ_TEST5_DESC "Correct task ordering"
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"
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"
60 #define SPLAT_TASKQ_ORDER_MAX 8
61 #define SPLAT_TASKQ_DEPTH_MAX 16
63 typedef struct splat_taskq_arg
{
67 int order
[SPLAT_TASKQ_ORDER_MAX
];
75 typedef struct splat_taskq_id
{
77 splat_taskq_arg_t
*arg
;
81 * Create a taskq, queue a task, wait until task completes, ensure
82 * task ran properly, cleanup taskq.
85 splat_taskq_test13_func(void *arg
)
87 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
90 splat_vprint(tq_arg
->file
, SPLAT_TASKQ_TEST1_NAME
,
91 "Taskq '%s' function '%s' setting flag\n",
92 tq_arg
->name
, sym2str(splat_taskq_test13_func
));
97 splat_taskq_test1(struct file
*file
, void *arg
)
101 splat_taskq_arg_t tq_arg
;
103 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
, "Taskq '%s' creating\n",
104 SPLAT_TASKQ_TEST1_NAME
);
105 if ((tq
= taskq_create(SPLAT_TASKQ_TEST1_NAME
, 1, maxclsyspri
,
106 50, INT_MAX
, TASKQ_PREPOPULATE
)) == NULL
) {
107 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
,
108 "Taskq '%s' create failed\n",
109 SPLAT_TASKQ_TEST1_NAME
);
116 tq_arg
.name
= SPLAT_TASKQ_TEST1_NAME
;
118 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
,
119 "Taskq '%s' function '%s' dispatching\n",
120 tq_arg
.name
, sym2str(splat_taskq_test13_func
));
121 if ((id
= taskq_dispatch(tq
, splat_taskq_test13_func
,
122 &tq_arg
, TQ_SLEEP
)) == 0) {
123 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
,
124 "Taskq '%s' function '%s' dispatch failed\n",
125 tq_arg
.name
, sym2str(splat_taskq_test13_func
));
130 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
, "Taskq '%s' waiting\n",
133 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
, "Taskq '%s' destroying\n",
137 return (tq_arg
.flag
) ? 0 : -EINVAL
;
141 * Create multiple taskq's, each with multiple tasks, wait until
142 * all tasks complete, ensure all tasks ran properly and in the
143 * correct order. Run order must be the same as the order submitted
144 * because we only have 1 thread per taskq. Finally cleanup the taskq.
147 splat_taskq_test2_func1(void *arg
)
149 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
152 splat_vprint(tq_arg
->file
, SPLAT_TASKQ_TEST2_NAME
,
153 "Taskq '%s/%d' function '%s' flag = %d = %d * 2\n",
154 tq_arg
->name
, tq_arg
->id
,
155 sym2str(splat_taskq_test2_func1
),
156 tq_arg
->flag
* 2, tq_arg
->flag
);
161 splat_taskq_test2_func2(void *arg
)
163 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
166 splat_vprint(tq_arg
->file
, SPLAT_TASKQ_TEST2_NAME
,
167 "Taskq '%s/%d' function '%s' flag = %d = %d + 1\n",
168 tq_arg
->name
, tq_arg
->id
,
169 sym2str(splat_taskq_test2_func2
),
170 tq_arg
->flag
+ 1, tq_arg
->flag
);
174 #define TEST2_TASKQS 8
175 #define TEST2_THREADS_PER_TASKQ 1
178 splat_taskq_test2(struct file
*file
, void *arg
) {
179 taskq_t
*tq
[TEST2_TASKQS
] = { NULL
};
181 splat_taskq_arg_t tq_args
[TEST2_TASKQS
];
184 for (i
= 0; i
< TEST2_TASKQS
; i
++) {
186 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
, "Taskq '%s/%d' "
187 "creating\n", SPLAT_TASKQ_TEST2_NAME
, i
);
188 if ((tq
[i
] = taskq_create(SPLAT_TASKQ_TEST2_NAME
,
189 TEST2_THREADS_PER_TASKQ
,
190 maxclsyspri
, 50, INT_MAX
,
191 TASKQ_PREPOPULATE
)) == NULL
) {
192 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
193 "Taskq '%s/%d' create failed\n",
194 SPLAT_TASKQ_TEST2_NAME
, i
);
201 tq_args
[i
].file
= file
;
202 tq_args
[i
].name
= SPLAT_TASKQ_TEST2_NAME
;
204 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
205 "Taskq '%s/%d' function '%s' dispatching\n",
206 tq_args
[i
].name
, tq_args
[i
].id
,
207 sym2str(splat_taskq_test2_func1
));
208 if ((id
= taskq_dispatch(
209 tq
[i
], splat_taskq_test2_func1
,
210 &tq_args
[i
], TQ_SLEEP
)) == 0) {
211 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
212 "Taskq '%s/%d' function '%s' dispatch "
213 "failed\n", tq_args
[i
].name
, tq_args
[i
].id
,
214 sym2str(splat_taskq_test2_func1
));
219 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
220 "Taskq '%s/%d' function '%s' dispatching\n",
221 tq_args
[i
].name
, tq_args
[i
].id
,
222 sym2str(splat_taskq_test2_func2
));
223 if ((id
= taskq_dispatch(
224 tq
[i
], splat_taskq_test2_func2
,
225 &tq_args
[i
], TQ_SLEEP
)) == 0) {
226 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
227 "Taskq '%s/%d' function '%s' dispatch failed\n",
228 tq_args
[i
].name
, tq_args
[i
].id
,
229 sym2str(splat_taskq_test2_func2
));
235 /* When rc is set we're effectively just doing cleanup here, so
236 * ignore new errors in that case. They just cause noise. */
237 for (i
= 0; i
< TEST2_TASKQS
; i
++) {
239 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
240 "Taskq '%s/%d' waiting\n",
241 tq_args
[i
].name
, tq_args
[i
].id
);
243 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
244 "Taskq '%s/%d; destroying\n",
245 tq_args
[i
].name
, tq_args
[i
].id
);
246 taskq_destroy(tq
[i
]);
248 if (!rc
&& tq_args
[i
].flag
!= ((i
* 2) + 1)) {
249 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
250 "Taskq '%s/%d' processed tasks "
251 "out of order; %d != %d\n",
252 tq_args
[i
].name
, tq_args
[i
].id
,
253 tq_args
[i
].flag
, i
* 2 + 1);
256 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
257 "Taskq '%s/%d' processed tasks "
258 "in the correct order; %d == %d\n",
259 tq_args
[i
].name
, tq_args
[i
].id
,
260 tq_args
[i
].flag
, i
* 2 + 1);
269 * Use the global system task queue with a single task, wait until task
270 * completes, ensure task ran properly.
273 splat_taskq_test3(struct file
*file
, void *arg
)
276 splat_taskq_arg_t tq_arg
;
281 tq_arg
.name
= SPLAT_TASKQ_TEST3_NAME
;
283 splat_vprint(file
, SPLAT_TASKQ_TEST3_NAME
,
284 "Taskq '%s' function '%s' dispatching\n",
285 tq_arg
.name
, sym2str(splat_taskq_test13_func
));
286 if ((id
= taskq_dispatch(system_taskq
, splat_taskq_test13_func
,
287 &tq_arg
, TQ_SLEEP
)) == 0) {
288 splat_vprint(file
, SPLAT_TASKQ_TEST3_NAME
,
289 "Taskq '%s' function '%s' dispatch failed\n",
290 tq_arg
.name
, sym2str(splat_taskq_test13_func
));
294 splat_vprint(file
, SPLAT_TASKQ_TEST3_NAME
, "Taskq '%s' waiting\n",
296 taskq_wait(system_taskq
);
298 return (tq_arg
.flag
) ? 0 : -EINVAL
;
302 * Create a taskq and dispatch a large number of tasks to the queue.
303 * Then use taskq_wait() to block until all the tasks complete, then
304 * cross check that all the tasks ran by checking tg_arg->count which
305 * is incremented in the task function. Finally cleanup the taskq.
307 * First we try with a large 'maxalloc' value, then we try with a small one.
308 * We should not drop tasks when TQ_SLEEP is used in taskq_dispatch(), even
309 * if the number of pending tasks is above maxalloc.
312 splat_taskq_test4_func(void *arg
)
314 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
317 atomic_inc(&tq_arg
->count
);
321 splat_taskq_test4_common(struct file
*file
, void *arg
, int minalloc
,
322 int maxalloc
, int nr_tasks
)
325 splat_taskq_arg_t tq_arg
;
328 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
, "Taskq '%s' creating "
329 "(%d/%d/%d)\n", SPLAT_TASKQ_TEST4_NAME
, minalloc
, maxalloc
,
331 if ((tq
= taskq_create(SPLAT_TASKQ_TEST4_NAME
, 1, maxclsyspri
,
332 minalloc
, maxalloc
, TASKQ_PREPOPULATE
)) == NULL
) {
333 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
,
334 "Taskq '%s' create failed\n",
335 SPLAT_TASKQ_TEST4_NAME
);
340 tq_arg
.name
= SPLAT_TASKQ_TEST4_NAME
;
342 for (i
= 1; i
<= nr_tasks
; i
*= 2) {
343 atomic_set(&tq_arg
.count
, 0);
344 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
,
345 "Taskq '%s' function '%s' dispatched %d times\n",
346 tq_arg
.name
, sym2str(splat_taskq_test4_func
), i
);
348 for (j
= 0; j
< i
; j
++) {
349 if ((taskq_dispatch(tq
, splat_taskq_test4_func
,
350 &tq_arg
, TQ_SLEEP
)) == 0) {
351 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
,
352 "Taskq '%s' function '%s' dispatch "
353 "%d failed\n", tq_arg
.name
,
354 sym2str(splat_taskq_test4_func
), j
);
360 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
, "Taskq '%s' "
361 "waiting for %d dispatches\n", tq_arg
.name
, i
);
363 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
, "Taskq '%s' "
364 "%d/%d dispatches finished\n", tq_arg
.name
,
365 atomic_read(&tq_arg
.count
), i
);
366 if (atomic_read(&tq_arg
.count
) != i
) {
373 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
, "Taskq '%s' destroying\n",
380 static int splat_taskq_test4(struct file
*file
, void *arg
)
384 rc
= splat_taskq_test4_common(file
, arg
, 50, INT_MAX
, 1024);
388 rc
= splat_taskq_test4_common(file
, arg
, 1, 1, 32);
394 * Create a taskq and dispatch a specific sequence of tasks carefully
395 * crafted to validate the order in which tasks are processed. When
396 * there are multiple worker threads each thread will process the
397 * next pending task as soon as it completes its current task. This
398 * means that tasks do not strictly complete in order in which they
399 * were dispatched (increasing task id). This is fine but we need to
400 * verify that taskq_wait_id() blocks until the passed task id and all
401 * lower task ids complete. We do this by dispatching the following
402 * specific sequence of tasks each of which block for N time units.
403 * We then use taskq_wait_id() to unblock at specific task id and
404 * verify the only the expected task ids have completed and in the
405 * correct order. The two cases of interest are:
407 * 1) Task ids larger than the waited for task id can run and
408 * complete as long as there is an available worker thread.
409 * 2) All task ids lower than the waited one must complete before
410 * unblocking even if the waited task id itself has completed.
412 * The following table shows each task id and how they will be
413 * scheduled. Each rows represent one time unit and each column
414 * one of the three worker threads. The places taskq_wait_id()
415 * must unblock for a specific id are identified as well as the
416 * task ids which must have completed and their order.
418 * +-----+ <--- taskq_wait_id(tq, 8) unblocks
419 * | | Required Completion Order: 1,2,4,5,3,8,6,7
424 * | | +-----+ <--- taskq_wait_id(tq, 3) unblocks
425 * | | 7 | | Required Completion Order: 1,2,4,5,3
434 * +-----+-----+-----+
438 splat_taskq_test5_func(void *arg
)
440 splat_taskq_id_t
*tq_id
= (splat_taskq_id_t
*)arg
;
441 splat_taskq_arg_t
*tq_arg
= tq_id
->arg
;
444 /* Delays determined by above table */
446 default: factor
= 0; break;
447 case 1: case 8: factor
= 1; break;
448 case 2: case 4: case 5: factor
= 2; break;
449 case 6: case 7: factor
= 4; break;
450 case 3: factor
= 5; break;
453 msleep(factor
* 100);
454 splat_vprint(tq_arg
->file
, tq_arg
->name
,
455 "Taskqid %d complete for taskq '%s'\n",
456 tq_id
->id
, tq_arg
->name
);
458 spin_lock(&tq_arg
->lock
);
459 tq_arg
->order
[tq_arg
->flag
] = tq_id
->id
;
461 spin_unlock(&tq_arg
->lock
);
465 splat_taskq_test_order(splat_taskq_arg_t
*tq_arg
, int *order
)
469 for (i
= 0; i
< SPLAT_TASKQ_ORDER_MAX
; i
++) {
470 if (tq_arg
->order
[i
] != order
[i
]) {
471 splat_vprint(tq_arg
->file
, tq_arg
->name
,
472 "Taskq '%s' incorrect completion "
473 "order\n", tq_arg
->name
);
474 splat_vprint(tq_arg
->file
, tq_arg
->name
,
475 "%s", "Expected { ");
477 for (j
= 0; j
< SPLAT_TASKQ_ORDER_MAX
; j
++)
478 splat_print(tq_arg
->file
, "%d ", order
[j
]);
480 splat_print(tq_arg
->file
, "%s", "}\n");
481 splat_vprint(tq_arg
->file
, tq_arg
->name
,
484 for (j
= 0; j
< SPLAT_TASKQ_ORDER_MAX
; j
++)
485 splat_print(tq_arg
->file
, "%d ",
488 splat_print(tq_arg
->file
, "%s", "}\n");
493 splat_vprint(tq_arg
->file
, tq_arg
->name
,
494 "Taskq '%s' validated correct completion order\n",
501 splat_taskq_test5(struct file
*file
, void *arg
)
505 splat_taskq_id_t tq_id
[SPLAT_TASKQ_ORDER_MAX
];
506 splat_taskq_arg_t tq_arg
;
507 int order1
[SPLAT_TASKQ_ORDER_MAX
] = { 1,2,4,5,3,0,0,0 };
508 int order2
[SPLAT_TASKQ_ORDER_MAX
] = { 1,2,4,5,3,8,6,7 };
511 splat_vprint(file
, SPLAT_TASKQ_TEST5_NAME
, "Taskq '%s' creating\n",
512 SPLAT_TASKQ_TEST5_NAME
);
513 if ((tq
= taskq_create(SPLAT_TASKQ_TEST5_NAME
, 3, maxclsyspri
,
514 50, INT_MAX
, TASKQ_PREPOPULATE
)) == NULL
) {
515 splat_vprint(file
, SPLAT_TASKQ_TEST5_NAME
,
516 "Taskq '%s' create failed\n",
517 SPLAT_TASKQ_TEST5_NAME
);
522 memset(&tq_arg
.order
, 0, sizeof(int) * SPLAT_TASKQ_ORDER_MAX
);
523 spin_lock_init(&tq_arg
.lock
);
525 tq_arg
.name
= SPLAT_TASKQ_TEST5_NAME
;
527 for (i
= 0; i
< SPLAT_TASKQ_ORDER_MAX
; i
++) {
529 tq_id
[i
].arg
= &tq_arg
;
531 if ((id
= taskq_dispatch(tq
, splat_taskq_test5_func
,
532 &tq_id
[i
], TQ_SLEEP
)) == 0) {
533 splat_vprint(file
, SPLAT_TASKQ_TEST5_NAME
,
534 "Taskq '%s' function '%s' dispatch failed\n",
535 tq_arg
.name
, sym2str(splat_taskq_test5_func
));
540 if (tq_id
[i
].id
!= id
) {
541 splat_vprint(file
, SPLAT_TASKQ_TEST5_NAME
,
542 "Taskq '%s' expected taskqid %d got %d\n",
543 tq_arg
.name
, (int)tq_id
[i
].id
, (int)id
);
549 splat_vprint(file
, SPLAT_TASKQ_TEST5_NAME
, "Taskq '%s' "
550 "waiting for taskqid %d completion\n", tq_arg
.name
, 3);
551 taskq_wait_id(tq
, 3);
552 if ((rc
= splat_taskq_test_order(&tq_arg
, order1
)))
555 splat_vprint(file
, SPLAT_TASKQ_TEST5_NAME
, "Taskq '%s' "
556 "waiting for taskqid %d completion\n", tq_arg
.name
, 8);
557 taskq_wait_id(tq
, 8);
558 rc
= splat_taskq_test_order(&tq_arg
, order2
);
561 splat_vprint(file
, SPLAT_TASKQ_TEST5_NAME
,
562 "Taskq '%s' destroying\n", tq_arg
.name
);
569 * Create a single task queue with three threads. Dispatch 8 tasks,
570 * setting TQ_FRONT on only the last three. Sleep after
571 * dispatching tasks 1-3 to ensure they will run and hold the threads
572 * busy while we dispatch the remaining tasks. Verify that tasks 6-8
573 * run before task 4-5.
575 * The following table shows each task id and how they will be
576 * scheduled. Each rows represent one time unit and each column
577 * one of the three worker threads.
595 * +-----+-----+-----+
599 splat_taskq_test6_func(void *arg
)
601 splat_taskq_id_t
*tq_id
= (splat_taskq_id_t
*)arg
;
602 splat_taskq_arg_t
*tq_arg
= tq_id
->arg
;
605 /* Delays determined by above table */
607 default: factor
= 0; break;
608 case 1: factor
= 2; break;
609 case 2: case 4: case 5: factor
= 4; break;
610 case 6: case 7: case 8: factor
= 5; break;
611 case 3: factor
= 6; break;
614 msleep(factor
* 100);
616 splat_vprint(tq_arg
->file
, tq_arg
->name
,
617 "Taskqid %d complete for taskq '%s'\n",
618 tq_id
->id
, tq_arg
->name
);
620 spin_lock(&tq_arg
->lock
);
621 tq_arg
->order
[tq_arg
->flag
] = tq_id
->id
;
623 spin_unlock(&tq_arg
->lock
);
627 splat_taskq_test6(struct file
*file
, void *arg
)
631 splat_taskq_id_t tq_id
[SPLAT_TASKQ_ORDER_MAX
];
632 splat_taskq_arg_t tq_arg
;
633 int order
[SPLAT_TASKQ_ORDER_MAX
] = { 1,2,3,6,7,8,4,5 };
637 splat_vprint(file
, SPLAT_TASKQ_TEST6_NAME
, "Taskq '%s' creating\n",
638 SPLAT_TASKQ_TEST6_NAME
);
639 if ((tq
= taskq_create(SPLAT_TASKQ_TEST6_NAME
, 3, maxclsyspri
,
640 50, INT_MAX
, TASKQ_PREPOPULATE
)) == NULL
) {
641 splat_vprint(file
, SPLAT_TASKQ_TEST6_NAME
,
642 "Taskq '%s' create failed\n",
643 SPLAT_TASKQ_TEST6_NAME
);
648 memset(&tq_arg
.order
, 0, sizeof(int) * SPLAT_TASKQ_ORDER_MAX
);
649 spin_lock_init(&tq_arg
.lock
);
651 tq_arg
.name
= SPLAT_TASKQ_TEST6_NAME
;
653 for (i
= 0; i
< SPLAT_TASKQ_ORDER_MAX
; i
++) {
655 tq_id
[i
].arg
= &tq_arg
;
660 if ((id
= taskq_dispatch(tq
, splat_taskq_test6_func
,
661 &tq_id
[i
], tflags
)) == 0) {
662 splat_vprint(file
, SPLAT_TASKQ_TEST6_NAME
,
663 "Taskq '%s' function '%s' dispatch failed\n",
664 tq_arg
.name
, sym2str(splat_taskq_test6_func
));
669 if (tq_id
[i
].id
!= id
) {
670 splat_vprint(file
, SPLAT_TASKQ_TEST6_NAME
,
671 "Taskq '%s' expected taskqid %d got %d\n",
672 tq_arg
.name
, (int)tq_id
[i
].id
, (int)id
);
676 /* Sleep to let tasks 1-3 start executing. */
681 splat_vprint(file
, SPLAT_TASKQ_TEST6_NAME
, "Taskq '%s' "
682 "waiting for taskqid %d completion\n", tq_arg
.name
,
683 SPLAT_TASKQ_ORDER_MAX
);
684 taskq_wait_id(tq
, SPLAT_TASKQ_ORDER_MAX
);
685 rc
= splat_taskq_test_order(&tq_arg
, order
);
688 splat_vprint(file
, SPLAT_TASKQ_TEST6_NAME
,
689 "Taskq '%s' destroying\n", tq_arg
.name
);
696 splat_taskq_test7_func(void *arg
)
698 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
703 if (tq_arg
->depth
>= SPLAT_TASKQ_DEPTH_MAX
)
708 splat_vprint(tq_arg
->file
, SPLAT_TASKQ_TEST7_NAME
,
709 "Taskq '%s' function '%s' dispatching (depth = %u)\n",
710 tq_arg
->name
, sym2str(splat_taskq_test7_func
),
713 if ((id
= taskq_dispatch(tq_arg
->tq
, splat_taskq_test7_func
,
714 tq_arg
, TQ_SLEEP
)) == 0) {
715 splat_vprint(tq_arg
->file
, SPLAT_TASKQ_TEST7_NAME
,
716 "Taskq '%s' function '%s' dispatch failed "
717 "(depth = %u)\n", tq_arg
->name
,
718 sym2str(splat_taskq_test7_func
), tq_arg
->depth
);
719 tq_arg
->flag
= -EINVAL
;
725 splat_taskq_test7(struct file
*file
, void *arg
)
728 splat_taskq_arg_t tq_arg
;
730 splat_vprint(file
, SPLAT_TASKQ_TEST7_NAME
,
731 "Taskq '%s' creating\n", SPLAT_TASKQ_TEST7_NAME
);
732 if ((tq
= taskq_create(SPLAT_TASKQ_TEST7_NAME
, 1, maxclsyspri
,
733 50, INT_MAX
, TASKQ_PREPOPULATE
)) == NULL
) {
734 splat_vprint(file
, SPLAT_TASKQ_TEST7_NAME
,
735 "Taskq '%s' create failed\n",
736 SPLAT_TASKQ_TEST7_NAME
);
744 tq_arg
.name
= SPLAT_TASKQ_TEST7_NAME
;
747 splat_taskq_test7_func(&tq_arg
);
749 if (tq_arg
.flag
== 0) {
750 splat_vprint(file
, SPLAT_TASKQ_TEST7_NAME
,
751 "Taskq '%s' waiting\n", tq_arg
.name
);
752 taskq_wait_id(tq
, SPLAT_TASKQ_DEPTH_MAX
);
755 splat_vprint(file
, SPLAT_TASKQ_TEST7_NAME
,
756 "Taskq '%s' destroying\n", tq_arg
.name
);
759 return tq_arg
.depth
== SPLAT_TASKQ_DEPTH_MAX
? 0 : -EINVAL
;
763 splat_taskq_init(void)
765 splat_subsystem_t
*sub
;
767 sub
= kmalloc(sizeof(*sub
), GFP_KERNEL
);
771 memset(sub
, 0, sizeof(*sub
));
772 strncpy(sub
->desc
.name
, SPLAT_TASKQ_NAME
, SPLAT_NAME_SIZE
);
773 strncpy(sub
->desc
.desc
, SPLAT_TASKQ_DESC
, SPLAT_DESC_SIZE
);
774 INIT_LIST_HEAD(&sub
->subsystem_list
);
775 INIT_LIST_HEAD(&sub
->test_list
);
776 spin_lock_init(&sub
->test_lock
);
777 sub
->desc
.id
= SPLAT_SUBSYSTEM_TASKQ
;
779 SPLAT_TEST_INIT(sub
, SPLAT_TASKQ_TEST1_NAME
, SPLAT_TASKQ_TEST1_DESC
,
780 SPLAT_TASKQ_TEST1_ID
, splat_taskq_test1
);
781 SPLAT_TEST_INIT(sub
, SPLAT_TASKQ_TEST2_NAME
, SPLAT_TASKQ_TEST2_DESC
,
782 SPLAT_TASKQ_TEST2_ID
, splat_taskq_test2
);
783 SPLAT_TEST_INIT(sub
, SPLAT_TASKQ_TEST3_NAME
, SPLAT_TASKQ_TEST3_DESC
,
784 SPLAT_TASKQ_TEST3_ID
, splat_taskq_test3
);
785 SPLAT_TEST_INIT(sub
, SPLAT_TASKQ_TEST4_NAME
, SPLAT_TASKQ_TEST4_DESC
,
786 SPLAT_TASKQ_TEST4_ID
, splat_taskq_test4
);
787 SPLAT_TEST_INIT(sub
, SPLAT_TASKQ_TEST5_NAME
, SPLAT_TASKQ_TEST5_DESC
,
788 SPLAT_TASKQ_TEST5_ID
, splat_taskq_test5
);
789 SPLAT_TEST_INIT(sub
, SPLAT_TASKQ_TEST6_NAME
, SPLAT_TASKQ_TEST6_DESC
,
790 SPLAT_TASKQ_TEST6_ID
, splat_taskq_test6
);
791 SPLAT_TEST_INIT(sub
, SPLAT_TASKQ_TEST7_NAME
, SPLAT_TASKQ_TEST7_DESC
,
792 SPLAT_TASKQ_TEST7_ID
, splat_taskq_test7
);
798 splat_taskq_fini(splat_subsystem_t
*sub
)
801 SPLAT_TEST_FINI(sub
, SPLAT_TASKQ_TEST7_ID
);
802 SPLAT_TEST_FINI(sub
, SPLAT_TASKQ_TEST6_ID
);
803 SPLAT_TEST_FINI(sub
, SPLAT_TASKQ_TEST5_ID
);
804 SPLAT_TEST_FINI(sub
, SPLAT_TASKQ_TEST4_ID
);
805 SPLAT_TEST_FINI(sub
, SPLAT_TASKQ_TEST3_ID
);
806 SPLAT_TEST_FINI(sub
, SPLAT_TASKQ_TEST2_ID
);
807 SPLAT_TEST_FINI(sub
, SPLAT_TASKQ_TEST1_ID
);
813 splat_taskq_id(void) {
814 return SPLAT_SUBSYSTEM_TASKQ
;