]>
Commit | Line | Data |
---|---|---|
715f6251 | 1 | /* |
2 | * This file is part of the SPL: Solaris Porting Layer. | |
3 | * | |
4 | * Copyright (c) 2008 Lawrence Livermore National Security, LLC. | |
5 | * Produced at Lawrence Livermore National Laboratory | |
6 | * Written by: | |
7 | * Brian Behlendorf <behlendorf1@llnl.gov>, | |
8 | * Herb Wartens <wartens2@llnl.gov>, | |
9 | * Jim Garlick <garlick@llnl.gov> | |
10 | * UCRL-CODE-235197 | |
11 | * | |
12 | * This is free software; you can redistribute it and/or modify it | |
13 | * under the terms of the GNU General Public License as published by | |
14 | * the Free Software Foundation; either version 2 of the License, or | |
15 | * (at your option) any later version. | |
16 | * | |
17 | * This is distributed in the hope that it will be useful, but WITHOUT | |
18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
19 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
20 | * for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU General Public License along | |
23 | * with this program; if not, write to the Free Software Foundation, Inc., | |
24 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
25 | */ | |
26 | ||
7c50328b | 27 | #include "splat-internal.h" |
f1ca4da6 | 28 | |
7c50328b | 29 | #define SPLAT_TASKQ_NAME "taskq" |
30 | #define SPLAT_TASKQ_DESC "Kernel Task Queue Tests" | |
f1ca4da6 | 31 | |
7c50328b | 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 | 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 | ||
52 | #define SPLAT_TASKQ_ORDER_MAX 8 | |
53 | ||
7c50328b | 54 | typedef struct splat_taskq_arg { |
f1ca4da6 | 55 | int flag; |
56 | int id; | |
7257ec41 | 57 | atomic_t count; |
5562e5d1 BB |
58 | int order[SPLAT_TASKQ_ORDER_MAX]; |
59 | spinlock_t lock; | |
f1ca4da6 | 60 | struct file *file; |
61 | const char *name; | |
7c50328b | 62 | } splat_taskq_arg_t; |
f1ca4da6 | 63 | |
5562e5d1 BB |
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. | |
f1ca4da6 | 72 | */ |
73 | static void | |
e9cb2b4f | 74 | splat_taskq_test13_func(void *arg) |
f1ca4da6 | 75 | { |
7c50328b | 76 | splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg; |
f1ca4da6 | 77 | |
78 | ASSERT(tq_arg); | |
7c50328b | 79 | splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST1_NAME, |
f1ca4da6 | 80 | "Taskq '%s' function '%s' setting flag\n", |
e9cb2b4f | 81 | tq_arg->name, sym2str(splat_taskq_test13_func)); |
f1ca4da6 | 82 | tq_arg->flag = 1; |
83 | } | |
84 | ||
85 | static int | |
7c50328b | 86 | splat_taskq_test1(struct file *file, void *arg) |
f1ca4da6 | 87 | { |
88 | taskq_t *tq; | |
89 | taskqid_t id; | |
7c50328b | 90 | splat_taskq_arg_t tq_arg; |
f1ca4da6 | 91 | |
7c50328b | 92 | splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' creating\n", |
93 | SPLAT_TASKQ_TEST1_NAME); | |
bcd68186 | 94 | if ((tq = taskq_create(SPLAT_TASKQ_TEST1_NAME, 1, maxclsyspri, |
95 | 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) { | |
7c50328b | 96 | splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, |
f1ca4da6 | 97 | "Taskq '%s' create failed\n", |
7c50328b | 98 | SPLAT_TASKQ_TEST1_NAME); |
f1ca4da6 | 99 | return -EINVAL; |
100 | } | |
101 | ||
102 | tq_arg.flag = 0; | |
103 | tq_arg.id = 0; | |
104 | tq_arg.file = file; | |
7c50328b | 105 | tq_arg.name = SPLAT_TASKQ_TEST1_NAME; |
f1ca4da6 | 106 | |
7c50328b | 107 | splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, |
f1ca4da6 | 108 | "Taskq '%s' function '%s' dispatching\n", |
e9cb2b4f BB |
109 | tq_arg.name, sym2str(splat_taskq_test13_func)); |
110 | if ((id = taskq_dispatch(tq, splat_taskq_test13_func, | |
bcd68186 | 111 | &tq_arg, TQ_SLEEP)) == 0) { |
7c50328b | 112 | splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, |
f1ca4da6 | 113 | "Taskq '%s' function '%s' dispatch failed\n", |
e9cb2b4f | 114 | tq_arg.name, sym2str(splat_taskq_test13_func)); |
4098c921 | 115 | taskq_destroy(tq); |
f1ca4da6 | 116 | return -EINVAL; |
117 | } | |
118 | ||
7c50328b | 119 | splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' waiting\n", |
f1ca4da6 | 120 | tq_arg.name); |
121 | taskq_wait(tq); | |
7c50328b | 122 | splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' destroying\n", |
f1ca4da6 | 123 | tq_arg.name); |
4098c921 | 124 | taskq_destroy(tq); |
f1ca4da6 | 125 | |
126 | return (tq_arg.flag) ? 0 : -EINVAL; | |
127 | } | |
128 | ||
5562e5d1 BB |
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. | |
f1ca4da6 | 134 | */ |
135 | static void | |
7c50328b | 136 | splat_taskq_test2_func1(void *arg) |
f1ca4da6 | 137 | { |
7c50328b | 138 | splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg; |
f1ca4da6 | 139 | |
140 | ASSERT(tq_arg); | |
7c50328b | 141 | splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST2_NAME, |
f1ca4da6 | 142 | "Taskq '%s/%d' function '%s' flag = %d = %d * 2\n", |
143 | tq_arg->name, tq_arg->id, | |
7c50328b | 144 | sym2str(splat_taskq_test2_func1), |
f1ca4da6 | 145 | tq_arg->flag * 2, tq_arg->flag); |
146 | tq_arg->flag *= 2; | |
147 | } | |
148 | ||
149 | static void | |
7c50328b | 150 | splat_taskq_test2_func2(void *arg) |
f1ca4da6 | 151 | { |
7c50328b | 152 | splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg; |
f1ca4da6 | 153 | |
154 | ASSERT(tq_arg); | |
7c50328b | 155 | splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST2_NAME, |
f1ca4da6 | 156 | "Taskq '%s/%d' function '%s' flag = %d = %d + 1\n", |
157 | tq_arg->name, tq_arg->id, | |
7c50328b | 158 | sym2str(splat_taskq_test2_func2), |
f1ca4da6 | 159 | tq_arg->flag + 1, tq_arg->flag); |
160 | tq_arg->flag += 1; | |
161 | } | |
162 | ||
163 | #define TEST2_TASKQS 8 | |
5562e5d1 | 164 | #define TEST2_THREADS_PER_TASKQ 1 |
bcd68186 | 165 | |
f1ca4da6 | 166 | static int |
7c50328b | 167 | splat_taskq_test2(struct file *file, void *arg) { |
f1ca4da6 | 168 | taskq_t *tq[TEST2_TASKQS] = { NULL }; |
169 | taskqid_t id; | |
7c50328b | 170 | splat_taskq_arg_t tq_args[TEST2_TASKQS]; |
f1ca4da6 | 171 | int i, rc = 0; |
172 | ||
173 | for (i = 0; i < TEST2_TASKQS; i++) { | |
174 | ||
7c50328b | 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, | |
bcd68186 | 178 | TEST2_THREADS_PER_TASKQ, |
179 | maxclsyspri, 50, INT_MAX, | |
180 | TASKQ_PREPOPULATE)) == NULL) { | |
7c50328b | 181 | splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, |
f1ca4da6 | 182 | "Taskq '%s/%d' create failed\n", |
7c50328b | 183 | SPLAT_TASKQ_TEST2_NAME, i); |
f1ca4da6 | 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; | |
7c50328b | 191 | tq_args[i].name = SPLAT_TASKQ_TEST2_NAME; |
f1ca4da6 | 192 | |
7c50328b | 193 | splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, |
f1ca4da6 | 194 | "Taskq '%s/%d' function '%s' dispatching\n", |
7c50328b | 195 | tq_args[i].name, tq_args[i].id, |
196 | sym2str(splat_taskq_test2_func1)); | |
f1ca4da6 | 197 | if ((id = taskq_dispatch( |
bcd68186 | 198 | tq[i], splat_taskq_test2_func1, |
199 | &tq_args[i], TQ_SLEEP)) == 0) { | |
7c50328b | 200 | splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, |
f1ca4da6 | 201 | "Taskq '%s/%d' function '%s' dispatch " |
202 | "failed\n", tq_args[i].name, tq_args[i].id, | |
7c50328b | 203 | sym2str(splat_taskq_test2_func1)); |
f1ca4da6 | 204 | rc = -EINVAL; |
205 | break; | |
206 | } | |
207 | ||
7c50328b | 208 | splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, |
f1ca4da6 | 209 | "Taskq '%s/%d' function '%s' dispatching\n", |
7c50328b | 210 | tq_args[i].name, tq_args[i].id, |
211 | sym2str(splat_taskq_test2_func2)); | |
f1ca4da6 | 212 | if ((id = taskq_dispatch( |
bcd68186 | 213 | tq[i], splat_taskq_test2_func2, |
214 | &tq_args[i], TQ_SLEEP)) == 0) { | |
7c50328b | 215 | splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, |
f1ca4da6 | 216 | "Taskq '%s/%d' function '%s' dispatch failed\n", |
217 | tq_args[i].name, tq_args[i].id, | |
7c50328b | 218 | sym2str(splat_taskq_test2_func2)); |
f1ca4da6 | 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) { | |
7c50328b | 228 | splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, |
f1ca4da6 | 229 | "Taskq '%s/%d' waiting\n", |
230 | tq_args[i].name, tq_args[i].id); | |
231 | taskq_wait(tq[i]); | |
7c50328b | 232 | splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, |
f1ca4da6 | 233 | "Taskq '%s/%d; destroying\n", |
234 | tq_args[i].name, tq_args[i].id); | |
4098c921 | 235 | taskq_destroy(tq[i]); |
f1ca4da6 | 236 | |
237 | if (!rc && tq_args[i].flag != ((i * 2) + 1)) { | |
7c50328b | 238 | splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, |
f1ca4da6 | 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 { | |
7c50328b | 245 | splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, |
f1ca4da6 | 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 | ||
5562e5d1 BB |
257 | /* |
258 | * Use the global system task queue with a single task, wait until task | |
259 | * completes, ensure task ran properly. | |
e9cb2b4f BB |
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 | ||
5562e5d1 BB |
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 | */ | |
7257ec41 BB |
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 | ||
5562e5d1 BB |
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 | ||
7c50328b | 538 | splat_subsystem_t * |
539 | splat_taskq_init(void) | |
f1ca4da6 | 540 | { |
7c50328b | 541 | splat_subsystem_t *sub; |
f1ca4da6 | 542 | |
543 | sub = kmalloc(sizeof(*sub), GFP_KERNEL); | |
544 | if (sub == NULL) | |
545 | return NULL; | |
546 | ||
547 | memset(sub, 0, sizeof(*sub)); | |
7c50328b | 548 | strncpy(sub->desc.name, SPLAT_TASKQ_NAME, SPLAT_NAME_SIZE); |
549 | strncpy(sub->desc.desc, SPLAT_TASKQ_DESC, SPLAT_DESC_SIZE); | |
f1ca4da6 | 550 | INIT_LIST_HEAD(&sub->subsystem_list); |
551 | INIT_LIST_HEAD(&sub->test_list); | |
552 | spin_lock_init(&sub->test_lock); | |
7c50328b | 553 | sub->desc.id = SPLAT_SUBSYSTEM_TASKQ; |
f1ca4da6 | 554 | |
7c50328b | 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); | |
e9cb2b4f BB |
559 | SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST3_NAME, SPLAT_TASKQ_TEST3_DESC, |
560 | SPLAT_TASKQ_TEST3_ID, splat_taskq_test3); | |
7257ec41 BB |
561 | SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST4_NAME, SPLAT_TASKQ_TEST4_DESC, |
562 | SPLAT_TASKQ_TEST4_ID, splat_taskq_test4); | |
5562e5d1 BB |
563 | SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST5_NAME, SPLAT_TASKQ_TEST5_DESC, |
564 | SPLAT_TASKQ_TEST5_ID, splat_taskq_test5); | |
f1ca4da6 | 565 | |
566 | return sub; | |
567 | } | |
568 | ||
569 | void | |
7c50328b | 570 | splat_taskq_fini(splat_subsystem_t *sub) |
f1ca4da6 | 571 | { |
572 | ASSERT(sub); | |
5562e5d1 | 573 | SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST5_ID); |
7257ec41 | 574 | SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST4_ID); |
e9cb2b4f | 575 | SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST3_ID); |
7c50328b | 576 | SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST2_ID); |
577 | SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST1_ID); | |
f1ca4da6 | 578 | |
579 | kfree(sub); | |
580 | } | |
581 | ||
582 | int | |
7c50328b | 583 | splat_taskq_id(void) { |
584 | return SPLAT_SUBSYSTEM_TASKQ; | |
f1ca4da6 | 585 | } |