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