2 * This file is part of the SPL: Solaris Porting Layer.
4 * Copyright (c) 2008 Lawrence Livermore National Security, LLC.
5 * Produced at Lawrence Livermore National Laboratory
7 * Brian Behlendorf <behlendorf1@llnl.gov>,
8 * Herb Wartens <wartens2@llnl.gov>,
9 * Jim Garlick <garlick@llnl.gov>
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.
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
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.
27 #include "splat-internal.h"
29 #define SPLAT_SUBSYSTEM_TASKQ 0x0200
30 #define SPLAT_TASKQ_NAME "taskq"
31 #define SPLAT_TASKQ_DESC "Kernel Task Queue Tests"
33 #define SPLAT_TASKQ_TEST1_ID 0x0201
34 #define SPLAT_TASKQ_TEST1_NAME "single"
35 #define SPLAT_TASKQ_TEST1_DESC "Single task queue, single task"
37 #define SPLAT_TASKQ_TEST2_ID 0x0202
38 #define SPLAT_TASKQ_TEST2_NAME "multiple"
39 #define SPLAT_TASKQ_TEST2_DESC "Multiple task queues, multiple tasks"
41 #define SPLAT_TASKQ_TEST3_ID 0x0203
42 #define SPLAT_TASKQ_TEST3_NAME "system"
43 #define SPLAT_TASKQ_TEST3_DESC "System task queue, multiple tasks"
45 typedef struct splat_taskq_arg
{
52 /* Validation Test 1 - Create a taskq, queue a task, wait until
53 * task completes, ensure task ran properly, cleanup taskq,
56 splat_taskq_test13_func(void *arg
)
58 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
61 splat_vprint(tq_arg
->file
, SPLAT_TASKQ_TEST1_NAME
,
62 "Taskq '%s' function '%s' setting flag\n",
63 tq_arg
->name
, sym2str(splat_taskq_test13_func
));
68 splat_taskq_test1(struct file
*file
, void *arg
)
72 splat_taskq_arg_t tq_arg
;
74 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
, "Taskq '%s' creating\n",
75 SPLAT_TASKQ_TEST1_NAME
);
76 if ((tq
= taskq_create(SPLAT_TASKQ_TEST1_NAME
, 1, maxclsyspri
,
77 50, INT_MAX
, TASKQ_PREPOPULATE
)) == NULL
) {
78 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
,
79 "Taskq '%s' create failed\n",
80 SPLAT_TASKQ_TEST1_NAME
);
87 tq_arg
.name
= SPLAT_TASKQ_TEST1_NAME
;
89 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
,
90 "Taskq '%s' function '%s' dispatching\n",
91 tq_arg
.name
, sym2str(splat_taskq_test13_func
));
92 if ((id
= taskq_dispatch(tq
, splat_taskq_test13_func
,
93 &tq_arg
, TQ_SLEEP
)) == 0) {
94 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
,
95 "Taskq '%s' function '%s' dispatch failed\n",
96 tq_arg
.name
, sym2str(splat_taskq_test13_func
));
101 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
, "Taskq '%s' waiting\n",
104 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
, "Taskq '%s' destroying\n",
108 return (tq_arg
.flag
) ? 0 : -EINVAL
;
111 /* Validation Test 2 - Create multiple taskq's, each with multiple tasks,
112 * wait until all tasks complete, ensure all tasks ran properly and in the
113 * the correct order, cleanup taskq's
116 splat_taskq_test2_func1(void *arg
)
118 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
121 splat_vprint(tq_arg
->file
, SPLAT_TASKQ_TEST2_NAME
,
122 "Taskq '%s/%d' function '%s' flag = %d = %d * 2\n",
123 tq_arg
->name
, tq_arg
->id
,
124 sym2str(splat_taskq_test2_func1
),
125 tq_arg
->flag
* 2, tq_arg
->flag
);
130 splat_taskq_test2_func2(void *arg
)
132 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
135 splat_vprint(tq_arg
->file
, SPLAT_TASKQ_TEST2_NAME
,
136 "Taskq '%s/%d' function '%s' flag = %d = %d + 1\n",
137 tq_arg
->name
, tq_arg
->id
,
138 sym2str(splat_taskq_test2_func2
),
139 tq_arg
->flag
+ 1, tq_arg
->flag
);
143 #define TEST2_TASKQS 8
144 #define TEST2_THREADS_PER_TASKQ 4
147 splat_taskq_test2(struct file
*file
, void *arg
) {
148 taskq_t
*tq
[TEST2_TASKQS
] = { NULL
};
150 splat_taskq_arg_t tq_args
[TEST2_TASKQS
];
153 for (i
= 0; i
< TEST2_TASKQS
; i
++) {
155 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
, "Taskq '%s/%d' "
156 "creating\n", SPLAT_TASKQ_TEST2_NAME
, i
);
157 if ((tq
[i
] = taskq_create(SPLAT_TASKQ_TEST2_NAME
,
158 TEST2_THREADS_PER_TASKQ
,
159 maxclsyspri
, 50, INT_MAX
,
160 TASKQ_PREPOPULATE
)) == NULL
) {
161 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
162 "Taskq '%s/%d' create failed\n",
163 SPLAT_TASKQ_TEST2_NAME
, i
);
170 tq_args
[i
].file
= file
;
171 tq_args
[i
].name
= SPLAT_TASKQ_TEST2_NAME
;
173 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
174 "Taskq '%s/%d' function '%s' dispatching\n",
175 tq_args
[i
].name
, tq_args
[i
].id
,
176 sym2str(splat_taskq_test2_func1
));
177 if ((id
= taskq_dispatch(
178 tq
[i
], splat_taskq_test2_func1
,
179 &tq_args
[i
], TQ_SLEEP
)) == 0) {
180 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
181 "Taskq '%s/%d' function '%s' dispatch "
182 "failed\n", tq_args
[i
].name
, tq_args
[i
].id
,
183 sym2str(splat_taskq_test2_func1
));
188 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
189 "Taskq '%s/%d' function '%s' dispatching\n",
190 tq_args
[i
].name
, tq_args
[i
].id
,
191 sym2str(splat_taskq_test2_func2
));
192 if ((id
= taskq_dispatch(
193 tq
[i
], splat_taskq_test2_func2
,
194 &tq_args
[i
], TQ_SLEEP
)) == 0) {
195 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
196 "Taskq '%s/%d' function '%s' dispatch failed\n",
197 tq_args
[i
].name
, tq_args
[i
].id
,
198 sym2str(splat_taskq_test2_func2
));
204 /* When rc is set we're effectively just doing cleanup here, so
205 * ignore new errors in that case. They just cause noise. */
206 for (i
= 0; i
< TEST2_TASKQS
; i
++) {
208 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
209 "Taskq '%s/%d' waiting\n",
210 tq_args
[i
].name
, tq_args
[i
].id
);
212 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
213 "Taskq '%s/%d; destroying\n",
214 tq_args
[i
].name
, tq_args
[i
].id
);
215 taskq_destroy(tq
[i
]);
217 if (!rc
&& tq_args
[i
].flag
!= ((i
* 2) + 1)) {
218 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
219 "Taskq '%s/%d' processed tasks "
220 "out of order; %d != %d\n",
221 tq_args
[i
].name
, tq_args
[i
].id
,
222 tq_args
[i
].flag
, i
* 2 + 1);
225 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
226 "Taskq '%s/%d' processed tasks "
227 "in the correct order; %d == %d\n",
228 tq_args
[i
].name
, tq_args
[i
].id
,
229 tq_args
[i
].flag
, i
* 2 + 1);
237 /* Validation Test 3 - Use the global system task queue with a single
238 * task, * wait until task completes, ensure task ran properly.
241 splat_taskq_test3(struct file
*file
, void *arg
)
244 splat_taskq_arg_t tq_arg
;
249 tq_arg
.name
= SPLAT_TASKQ_TEST3_NAME
;
251 splat_vprint(file
, SPLAT_TASKQ_TEST3_NAME
,
252 "Taskq '%s' function '%s' dispatching\n",
253 tq_arg
.name
, sym2str(splat_taskq_test13_func
));
254 if ((id
= taskq_dispatch(system_taskq
, splat_taskq_test13_func
,
255 &tq_arg
, TQ_SLEEP
)) == 0) {
256 splat_vprint(file
, SPLAT_TASKQ_TEST3_NAME
,
257 "Taskq '%s' function '%s' dispatch failed\n",
258 tq_arg
.name
, sym2str(splat_taskq_test13_func
));
262 splat_vprint(file
, SPLAT_TASKQ_TEST3_NAME
, "Taskq '%s' waiting\n",
264 taskq_wait(system_taskq
);
266 return (tq_arg
.flag
) ? 0 : -EINVAL
;
270 splat_taskq_init(void)
272 splat_subsystem_t
*sub
;
274 sub
= kmalloc(sizeof(*sub
), GFP_KERNEL
);
278 memset(sub
, 0, sizeof(*sub
));
279 strncpy(sub
->desc
.name
, SPLAT_TASKQ_NAME
, SPLAT_NAME_SIZE
);
280 strncpy(sub
->desc
.desc
, SPLAT_TASKQ_DESC
, SPLAT_DESC_SIZE
);
281 INIT_LIST_HEAD(&sub
->subsystem_list
);
282 INIT_LIST_HEAD(&sub
->test_list
);
283 spin_lock_init(&sub
->test_lock
);
284 sub
->desc
.id
= SPLAT_SUBSYSTEM_TASKQ
;
286 SPLAT_TEST_INIT(sub
, SPLAT_TASKQ_TEST1_NAME
, SPLAT_TASKQ_TEST1_DESC
,
287 SPLAT_TASKQ_TEST1_ID
, splat_taskq_test1
);
288 SPLAT_TEST_INIT(sub
, SPLAT_TASKQ_TEST2_NAME
, SPLAT_TASKQ_TEST2_DESC
,
289 SPLAT_TASKQ_TEST2_ID
, splat_taskq_test2
);
290 SPLAT_TEST_INIT(sub
, SPLAT_TASKQ_TEST3_NAME
, SPLAT_TASKQ_TEST3_DESC
,
291 SPLAT_TASKQ_TEST3_ID
, splat_taskq_test3
);
297 splat_taskq_fini(splat_subsystem_t
*sub
)
300 SPLAT_TEST_FINI(sub
, SPLAT_TASKQ_TEST3_ID
);
301 SPLAT_TEST_FINI(sub
, SPLAT_TASKQ_TEST2_ID
);
302 SPLAT_TEST_FINI(sub
, SPLAT_TASKQ_TEST1_ID
);
308 splat_taskq_id(void) {
309 return SPLAT_SUBSYSTEM_TASKQ
;