]> git.proxmox.com Git - mirror_spl-debian.git/blame - module/splat/splat-condvar.c
Refresh links to web site
[mirror_spl-debian.git] / module / splat / splat-condvar.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 6 * UCRL-CODE-235197
7 *
716154c5 8 * This file is part of the SPL, Solaris Porting Layer.
3d6af2dd 9 * For details, see <http://zfsonlinux.org/>.
716154c5
BB
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 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) Condition Variable Tests.
25\*****************************************************************************/
715f6251 26
b84412a6 27#include <linux/kthread.h>
df870a69 28#include <sys/condvar.h>
7c50328b 29#include "splat-internal.h"
f1ca4da6 30
7c50328b 31#define SPLAT_CONDVAR_NAME "condvar"
32#define SPLAT_CONDVAR_DESC "Kernel Condition Variable Tests"
f1ca4da6 33
7c50328b 34#define SPLAT_CONDVAR_TEST1_ID 0x0501
35#define SPLAT_CONDVAR_TEST1_NAME "signal1"
36#define SPLAT_CONDVAR_TEST1_DESC "Wake a single thread, cv_wait()/cv_signal()"
f1ca4da6 37
7c50328b 38#define SPLAT_CONDVAR_TEST2_ID 0x0502
39#define SPLAT_CONDVAR_TEST2_NAME "broadcast1"
40#define SPLAT_CONDVAR_TEST2_DESC "Wake all threads, cv_wait()/cv_broadcast()"
f1ca4da6 41
7c50328b 42#define SPLAT_CONDVAR_TEST3_ID 0x0503
43#define SPLAT_CONDVAR_TEST3_NAME "signal2"
44#define SPLAT_CONDVAR_TEST3_DESC "Wake a single thread, cv_wait_timeout()/cv_signal()"
f1ca4da6 45
7c50328b 46#define SPLAT_CONDVAR_TEST4_ID 0x0504
47#define SPLAT_CONDVAR_TEST4_NAME "broadcast2"
48#define SPLAT_CONDVAR_TEST4_DESC "Wake all threads, cv_wait_timeout()/cv_broadcast()"
f1ca4da6 49
7c50328b 50#define SPLAT_CONDVAR_TEST5_ID 0x0505
51#define SPLAT_CONDVAR_TEST5_NAME "timeout"
52#define SPLAT_CONDVAR_TEST5_DESC "Timeout thread, cv_wait_timeout()"
f1ca4da6 53
7c50328b 54#define SPLAT_CONDVAR_TEST_MAGIC 0x115599DDUL
b84412a6 55#define SPLAT_CONDVAR_TEST_NAME "condvar"
7c50328b 56#define SPLAT_CONDVAR_TEST_COUNT 8
f1ca4da6 57
58typedef struct condvar_priv {
b84412a6
BB
59 unsigned long cv_magic;
60 struct file *cv_file;
f1ca4da6 61 kcondvar_t cv_condvar;
62 kmutex_t cv_mtx;
63} condvar_priv_t;
64
65typedef struct condvar_thr {
f1ca4da6 66 const char *ct_name;
67 condvar_priv_t *ct_cvp;
b84412a6 68 struct task_struct *ct_thread;
f1ca4da6 69 int ct_rc;
70} condvar_thr_t;
71
72int
7c50328b 73splat_condvar_test12_thread(void *arg)
f1ca4da6 74{
75 condvar_thr_t *ct = (condvar_thr_t *)arg;
76 condvar_priv_t *cv = ct->ct_cvp;
f1ca4da6 77
7c50328b 78 ASSERT(cv->cv_magic == SPLAT_CONDVAR_TEST_MAGIC);
f1ca4da6 79
80 mutex_enter(&cv->cv_mtx);
7c50328b 81 splat_vprint(cv->cv_file, ct->ct_name,
b84412a6
BB
82 "%s thread sleeping with %d waiters\n",
83 ct->ct_thread->comm, atomic_read(&cv->cv_condvar.cv_waiters));
f1ca4da6 84 cv_wait(&cv->cv_condvar, &cv->cv_mtx);
7c50328b 85 splat_vprint(cv->cv_file, ct->ct_name,
b84412a6
BB
86 "%s thread woken %d waiters remain\n",
87 ct->ct_thread->comm, atomic_read(&cv->cv_condvar.cv_waiters));
f1ca4da6 88 mutex_exit(&cv->cv_mtx);
89
90 return 0;
91}
92
93static int
7c50328b 94splat_condvar_test1(struct file *file, void *arg)
f1ca4da6 95{
96 int i, count = 0, rc = 0;
7c50328b 97 condvar_thr_t ct[SPLAT_CONDVAR_TEST_COUNT];
f1ca4da6 98 condvar_priv_t cv;
99
7c50328b 100 cv.cv_magic = SPLAT_CONDVAR_TEST_MAGIC;
f1ca4da6 101 cv.cv_file = file;
7c50328b 102 mutex_init(&cv.cv_mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL);
b29012b9 103 cv_init(&cv.cv_condvar, NULL, CV_DEFAULT, NULL);
f1ca4da6 104
105 /* Create some threads, the exact number isn't important just as
106 * long as we know how many we managed to create and should expect. */
7c50328b 107 for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) {
f1ca4da6 108 ct[i].ct_cvp = &cv;
7c50328b 109 ct[i].ct_name = SPLAT_CONDVAR_TEST1_NAME;
f1ca4da6 110 ct[i].ct_rc = 0;
b84412a6
BB
111 ct[i].ct_thread = kthread_create(splat_condvar_test12_thread,
112 &ct[i], "%s/%d", SPLAT_CONDVAR_TEST_NAME, i);
f1ca4da6 113
b84412a6
BB
114 if (!IS_ERR(ct[i].ct_thread)) {
115 wake_up_process(ct[i].ct_thread);
f1ca4da6 116 count++;
b84412a6 117 }
f1ca4da6 118 }
119
120 /* Wait until all threads are waiting on the condition variable */
121 while (atomic_read(&cv.cv_condvar.cv_waiters) != count)
122 schedule();
123
124 /* Wake a single thread at a time, wait until it exits */
125 for (i = 1; i <= count; i++) {
126 cv_signal(&cv.cv_condvar);
127
128 while (atomic_read(&cv.cv_condvar.cv_waiters) > (count - i))
129 schedule();
130
131 /* Correct behavior 1 thread woken */
132 if (atomic_read(&cv.cv_condvar.cv_waiters) == (count - i))
133 continue;
134
7c50328b 135 splat_vprint(file, SPLAT_CONDVAR_TEST1_NAME, "Attempted to "
f1ca4da6 136 "wake %d thread but work %d threads woke\n",
137 1, count - atomic_read(&cv.cv_condvar.cv_waiters));
138 rc = -EINVAL;
139 break;
140 }
141
142 if (!rc)
7c50328b 143 splat_vprint(file, SPLAT_CONDVAR_TEST1_NAME, "Correctly woke "
f1ca4da6 144 "%d sleeping threads %d at a time\n", count, 1);
145
146 /* Wait until that last nutex is dropped */
147 while (mutex_owner(&cv.cv_mtx))
148 schedule();
149
150 /* Wake everything for the failure case */
151 cv_broadcast(&cv.cv_condvar);
152 cv_destroy(&cv.cv_condvar);
153 mutex_destroy(&cv.cv_mtx);
154
155 return rc;
156}
157
158static int
7c50328b 159splat_condvar_test2(struct file *file, void *arg)
f1ca4da6 160{
161 int i, count = 0, rc = 0;
7c50328b 162 condvar_thr_t ct[SPLAT_CONDVAR_TEST_COUNT];
f1ca4da6 163 condvar_priv_t cv;
164
7c50328b 165 cv.cv_magic = SPLAT_CONDVAR_TEST_MAGIC;
f1ca4da6 166 cv.cv_file = file;
7c50328b 167 mutex_init(&cv.cv_mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL);
b29012b9 168 cv_init(&cv.cv_condvar, NULL, CV_DEFAULT, NULL);
f1ca4da6 169
170 /* Create some threads, the exact number isn't important just as
171 * long as we know how many we managed to create and should expect. */
7c50328b 172 for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) {
f1ca4da6 173 ct[i].ct_cvp = &cv;
7c50328b 174 ct[i].ct_name = SPLAT_CONDVAR_TEST2_NAME;
f1ca4da6 175 ct[i].ct_rc = 0;
b84412a6
BB
176 ct[i].ct_thread = kthread_create(splat_condvar_test12_thread,
177 &ct[i], "%s/%d", SPLAT_CONDVAR_TEST_NAME, i);
f1ca4da6 178
b84412a6
BB
179 if (!IS_ERR(ct[i].ct_thread)) {
180 wake_up_process(ct[i].ct_thread);
f1ca4da6 181 count++;
b84412a6 182 }
f1ca4da6 183 }
184
185 /* Wait until all threads are waiting on the condition variable */
186 while (atomic_read(&cv.cv_condvar.cv_waiters) != count)
187 schedule();
188
189 /* Wake all threads waiting on the condition variable */
190 cv_broadcast(&cv.cv_condvar);
191
192 /* Wait until all threads have exited */
193 while ((atomic_read(&cv.cv_condvar.cv_waiters) > 0) || mutex_owner(&cv.cv_mtx))
194 schedule();
195
7c50328b 196 splat_vprint(file, SPLAT_CONDVAR_TEST2_NAME, "Correctly woke all "
f1ca4da6 197 "%d sleeping threads at once\n", count);
198
199 /* Wake everything for the failure case */
200 cv_destroy(&cv.cv_condvar);
201 mutex_destroy(&cv.cv_mtx);
202
203 return rc;
204}
205
206int
7c50328b 207splat_condvar_test34_thread(void *arg)
f1ca4da6 208{
209 condvar_thr_t *ct = (condvar_thr_t *)arg;
210 condvar_priv_t *cv = ct->ct_cvp;
f1ca4da6 211 clock_t rc;
212
7c50328b 213 ASSERT(cv->cv_magic == SPLAT_CONDVAR_TEST_MAGIC);
f1ca4da6 214
215 mutex_enter(&cv->cv_mtx);
7c50328b 216 splat_vprint(cv->cv_file, ct->ct_name,
b84412a6
BB
217 "%s thread sleeping with %d waiters\n",
218 ct->ct_thread->comm, atomic_read(&cv->cv_condvar.cv_waiters));
f1ca4da6 219
220 /* Sleep no longer than 3 seconds, for this test we should
221 * actually never sleep that long without being woken up. */
222 rc = cv_timedwait(&cv->cv_condvar, &cv->cv_mtx, lbolt + HZ * 3);
223 if (rc == -1) {
224 ct->ct_rc = -ETIMEDOUT;
7c50328b 225 splat_vprint(cv->cv_file, ct->ct_name, "%s thread timed out, "
b84412a6 226 "should have been woken\n", ct->ct_thread->comm);
f1ca4da6 227 } else {
7c50328b 228 splat_vprint(cv->cv_file, ct->ct_name,
b84412a6
BB
229 "%s thread woken %d waiters remain\n",
230 ct->ct_thread->comm,
231 atomic_read(&cv->cv_condvar.cv_waiters));
f1ca4da6 232 }
233
234 mutex_exit(&cv->cv_mtx);
235
236 return 0;
237}
238
239static int
7c50328b 240splat_condvar_test3(struct file *file, void *arg)
f1ca4da6 241{
242 int i, count = 0, rc = 0;
7c50328b 243 condvar_thr_t ct[SPLAT_CONDVAR_TEST_COUNT];
f1ca4da6 244 condvar_priv_t cv;
245
7c50328b 246 cv.cv_magic = SPLAT_CONDVAR_TEST_MAGIC;
f1ca4da6 247 cv.cv_file = file;
7c50328b 248 mutex_init(&cv.cv_mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL);
b29012b9 249 cv_init(&cv.cv_condvar, NULL, CV_DEFAULT, NULL);
f1ca4da6 250
251 /* Create some threads, the exact number isn't important just as
252 * long as we know how many we managed to create and should expect. */
7c50328b 253 for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) {
f1ca4da6 254 ct[i].ct_cvp = &cv;
7c50328b 255 ct[i].ct_name = SPLAT_CONDVAR_TEST3_NAME;
f1ca4da6 256 ct[i].ct_rc = 0;
b84412a6
BB
257 ct[i].ct_thread = kthread_create(splat_condvar_test34_thread,
258 &ct[i], "%s/%d", SPLAT_CONDVAR_TEST_NAME, i);
f1ca4da6 259
b84412a6
BB
260 if (!IS_ERR(ct[i].ct_thread)) {
261 wake_up_process(ct[i].ct_thread);
f1ca4da6 262 count++;
b84412a6 263 }
f1ca4da6 264 }
265
266 /* Wait until all threads are waiting on the condition variable */
267 while (atomic_read(&cv.cv_condvar.cv_waiters) != count)
268 schedule();
269
270 /* Wake a single thread at a time, wait until it exits */
271 for (i = 1; i <= count; i++) {
272 cv_signal(&cv.cv_condvar);
273
274 while (atomic_read(&cv.cv_condvar.cv_waiters) > (count - i))
275 schedule();
276
277 /* Correct behavior 1 thread woken */
278 if (atomic_read(&cv.cv_condvar.cv_waiters) == (count - i))
279 continue;
280
7c50328b 281 splat_vprint(file, SPLAT_CONDVAR_TEST3_NAME, "Attempted to "
f1ca4da6 282 "wake %d thread but work %d threads woke\n",
283 1, count - atomic_read(&cv.cv_condvar.cv_waiters));
284 rc = -EINVAL;
285 break;
286 }
287
288 /* Validate no waiting thread timed out early */
289 for (i = 0; i < count; i++)
290 if (ct[i].ct_rc)
291 rc = ct[i].ct_rc;
292
293 if (!rc)
7c50328b 294 splat_vprint(file, SPLAT_CONDVAR_TEST3_NAME, "Correctly woke "
f1ca4da6 295 "%d sleeping threads %d at a time\n", count, 1);
296
297 /* Wait until that last nutex is dropped */
298 while (mutex_owner(&cv.cv_mtx))
299 schedule();
300
301 /* Wake everything for the failure case */
302 cv_broadcast(&cv.cv_condvar);
303 cv_destroy(&cv.cv_condvar);
304 mutex_destroy(&cv.cv_mtx);
305
306 return rc;
307}
308
309static int
7c50328b 310splat_condvar_test4(struct file *file, void *arg)
f1ca4da6 311{
312 int i, count = 0, rc = 0;
7c50328b 313 condvar_thr_t ct[SPLAT_CONDVAR_TEST_COUNT];
f1ca4da6 314 condvar_priv_t cv;
315
7c50328b 316 cv.cv_magic = SPLAT_CONDVAR_TEST_MAGIC;
f1ca4da6 317 cv.cv_file = file;
7c50328b 318 mutex_init(&cv.cv_mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL);
b29012b9 319 cv_init(&cv.cv_condvar, NULL, CV_DEFAULT, NULL);
f1ca4da6 320
321 /* Create some threads, the exact number isn't important just as
322 * long as we know how many we managed to create and should expect. */
7c50328b 323 for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) {
f1ca4da6 324 ct[i].ct_cvp = &cv;
7c50328b 325 ct[i].ct_name = SPLAT_CONDVAR_TEST3_NAME;
f1ca4da6 326 ct[i].ct_rc = 0;
b84412a6
BB
327 ct[i].ct_thread = kthread_create(splat_condvar_test34_thread,
328 &ct[i], "%s/%d", SPLAT_CONDVAR_TEST_NAME, i);
f1ca4da6 329
b84412a6
BB
330 if (!IS_ERR(ct[i].ct_thread)) {
331 wake_up_process(ct[i].ct_thread);
f1ca4da6 332 count++;
b84412a6 333 }
f1ca4da6 334 }
335
336 /* Wait until all threads are waiting on the condition variable */
337 while (atomic_read(&cv.cv_condvar.cv_waiters) != count)
338 schedule();
339
340 /* Wake a single thread at a time, wait until it exits */
341 for (i = 1; i <= count; i++) {
342 cv_signal(&cv.cv_condvar);
343
344 while (atomic_read(&cv.cv_condvar.cv_waiters) > (count - i))
345 schedule();
346
347 /* Correct behavior 1 thread woken */
348 if (atomic_read(&cv.cv_condvar.cv_waiters) == (count - i))
349 continue;
350
7c50328b 351 splat_vprint(file, SPLAT_CONDVAR_TEST3_NAME, "Attempted to "
f1ca4da6 352 "wake %d thread but work %d threads woke\n",
353 1, count - atomic_read(&cv.cv_condvar.cv_waiters));
354 rc = -EINVAL;
355 break;
356 }
357
358 /* Validate no waiting thread timed out early */
359 for (i = 0; i < count; i++)
360 if (ct[i].ct_rc)
361 rc = ct[i].ct_rc;
362
363 if (!rc)
7c50328b 364 splat_vprint(file, SPLAT_CONDVAR_TEST3_NAME, "Correctly woke "
f1ca4da6 365 "%d sleeping threads %d at a time\n", count, 1);
366
367 /* Wait until that last nutex is dropped */
368 while (mutex_owner(&cv.cv_mtx))
369 schedule();
370
371 /* Wake everything for the failure case */
372 cv_broadcast(&cv.cv_condvar);
373 cv_destroy(&cv.cv_condvar);
374 mutex_destroy(&cv.cv_mtx);
375
376 return rc;
377}
378
379static int
7c50328b 380splat_condvar_test5(struct file *file, void *arg)
f1ca4da6 381{
382 kcondvar_t condvar;
383 kmutex_t mtx;
384 clock_t time_left, time_before, time_after, time_delta;
385 int64_t whole_delta;
386 int32_t remain_delta;
387 int rc = 0;
388
7c50328b 389 mutex_init(&mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL);
b29012b9 390 cv_init(&condvar, NULL, CV_DEFAULT, NULL);
f1ca4da6 391
7c50328b 392 splat_vprint(file, SPLAT_CONDVAR_TEST5_NAME, "Thread going to sleep for "
f1ca4da6 393 "%d second and expecting to be woken by timeout\n", 1);
394
395 /* Allow a 1 second timeout, plenty long to validate correctness. */
396 time_before = lbolt;
397 mutex_enter(&mtx);
398 time_left = cv_timedwait(&condvar, &mtx, lbolt + HZ);
399 mutex_exit(&mtx);
400 time_after = lbolt;
401 time_delta = time_after - time_before; /* XXX - Handle jiffie wrap */
402 whole_delta = time_delta;
403 remain_delta = do_div(whole_delta, HZ);
404
405 if (time_left == -1) {
406 if (time_delta >= HZ) {
7c50328b 407 splat_vprint(file, SPLAT_CONDVAR_TEST5_NAME,
f1ca4da6 408 "Thread correctly timed out and was asleep "
409 "for %d.%d seconds (%d second min)\n",
410 (int)whole_delta, remain_delta, 1);
411 } else {
7c50328b 412 splat_vprint(file, SPLAT_CONDVAR_TEST5_NAME,
f1ca4da6 413 "Thread correctly timed out but was only "
414 "asleep for %d.%d seconds (%d second "
415 "min)\n", (int)whole_delta, remain_delta, 1);
416 rc = -ETIMEDOUT;
417 }
418 } else {
7c50328b 419 splat_vprint(file, SPLAT_CONDVAR_TEST5_NAME,
f1ca4da6 420 "Thread exited after only %d.%d seconds, it "
421 "did not hit the %d second timeout\n",
422 (int)whole_delta, remain_delta, 1);
423 rc = -ETIMEDOUT;
424 }
425
426 cv_destroy(&condvar);
427 mutex_destroy(&mtx);
428
429 return rc;
430}
431
7c50328b 432splat_subsystem_t *
433splat_condvar_init(void)
f1ca4da6 434{
7c50328b 435 splat_subsystem_t *sub;
f1ca4da6 436
437 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
438 if (sub == NULL)
439 return NULL;
440
441 memset(sub, 0, sizeof(*sub));
7c50328b 442 strncpy(sub->desc.name, SPLAT_CONDVAR_NAME, SPLAT_NAME_SIZE);
443 strncpy(sub->desc.desc, SPLAT_CONDVAR_DESC, SPLAT_DESC_SIZE);
f1ca4da6 444 INIT_LIST_HEAD(&sub->subsystem_list);
445 INIT_LIST_HEAD(&sub->test_list);
446 spin_lock_init(&sub->test_lock);
7c50328b 447 sub->desc.id = SPLAT_SUBSYSTEM_CONDVAR;
448
449 SPLAT_TEST_INIT(sub, SPLAT_CONDVAR_TEST1_NAME, SPLAT_CONDVAR_TEST1_DESC,
450 SPLAT_CONDVAR_TEST1_ID, splat_condvar_test1);
451 SPLAT_TEST_INIT(sub, SPLAT_CONDVAR_TEST2_NAME, SPLAT_CONDVAR_TEST2_DESC,
452 SPLAT_CONDVAR_TEST2_ID, splat_condvar_test2);
453 SPLAT_TEST_INIT(sub, SPLAT_CONDVAR_TEST3_NAME, SPLAT_CONDVAR_TEST3_DESC,
454 SPLAT_CONDVAR_TEST3_ID, splat_condvar_test3);
455 SPLAT_TEST_INIT(sub, SPLAT_CONDVAR_TEST4_NAME, SPLAT_CONDVAR_TEST4_DESC,
456 SPLAT_CONDVAR_TEST4_ID, splat_condvar_test4);
457 SPLAT_TEST_INIT(sub, SPLAT_CONDVAR_TEST5_NAME, SPLAT_CONDVAR_TEST5_DESC,
458 SPLAT_CONDVAR_TEST5_ID, splat_condvar_test5);
f1ca4da6 459
460 return sub;
461}
462
463void
7c50328b 464splat_condvar_fini(splat_subsystem_t *sub)
f1ca4da6 465{
466 ASSERT(sub);
7c50328b 467 SPLAT_TEST_FINI(sub, SPLAT_CONDVAR_TEST5_ID);
468 SPLAT_TEST_FINI(sub, SPLAT_CONDVAR_TEST4_ID);
469 SPLAT_TEST_FINI(sub, SPLAT_CONDVAR_TEST3_ID);
470 SPLAT_TEST_FINI(sub, SPLAT_CONDVAR_TEST2_ID);
471 SPLAT_TEST_FINI(sub, SPLAT_CONDVAR_TEST1_ID);
f1ca4da6 472
473 kfree(sub);
474}
475
476int
7c50328b 477splat_condvar_id(void) {
478 return SPLAT_SUBSYSTEM_CONDVAR;
f1ca4da6 479}