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://zfsonlinux.org/>.
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) Condition Variable Tests.
25 \*****************************************************************************/
27 #include <linux/kthread.h>
28 #include <sys/condvar.h>
29 #include "splat-internal.h"
31 #define SPLAT_CONDVAR_NAME "condvar"
32 #define SPLAT_CONDVAR_DESC "Kernel Condition Variable Tests"
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()"
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()"
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()"
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()"
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()"
54 #define SPLAT_CONDVAR_TEST_MAGIC 0x115599DDUL
55 #define SPLAT_CONDVAR_TEST_NAME "condvar"
56 #define SPLAT_CONDVAR_TEST_COUNT 8
58 typedef struct condvar_priv
{
59 unsigned long cv_magic
;
61 kcondvar_t cv_condvar
;
65 typedef struct condvar_thr
{
67 condvar_priv_t
*ct_cvp
;
68 struct task_struct
*ct_thread
;
73 splat_condvar_test12_thread(void *arg
)
75 condvar_thr_t
*ct
= (condvar_thr_t
*)arg
;
76 condvar_priv_t
*cv
= ct
->ct_cvp
;
78 ASSERT(cv
->cv_magic
== SPLAT_CONDVAR_TEST_MAGIC
);
80 mutex_enter(&cv
->cv_mtx
);
81 splat_vprint(cv
->cv_file
, ct
->ct_name
,
82 "%s thread sleeping with %d waiters\n",
83 ct
->ct_thread
->comm
, atomic_read(&cv
->cv_condvar
.cv_waiters
));
84 cv_wait(&cv
->cv_condvar
, &cv
->cv_mtx
);
85 splat_vprint(cv
->cv_file
, ct
->ct_name
,
86 "%s thread woken %d waiters remain\n",
87 ct
->ct_thread
->comm
, atomic_read(&cv
->cv_condvar
.cv_waiters
));
88 mutex_exit(&cv
->cv_mtx
);
94 splat_condvar_test1(struct file
*file
, void *arg
)
96 int i
, count
= 0, rc
= 0;
97 condvar_thr_t ct
[SPLAT_CONDVAR_TEST_COUNT
];
100 cv
.cv_magic
= SPLAT_CONDVAR_TEST_MAGIC
;
102 mutex_init(&cv
.cv_mtx
, SPLAT_CONDVAR_TEST_NAME
, MUTEX_DEFAULT
, NULL
);
103 cv_init(&cv
.cv_condvar
, NULL
, CV_DEFAULT
, NULL
);
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. */
107 for (i
= 0; i
< SPLAT_CONDVAR_TEST_COUNT
; i
++) {
109 ct
[i
].ct_name
= SPLAT_CONDVAR_TEST1_NAME
;
111 ct
[i
].ct_thread
= spl_kthread_create(splat_condvar_test12_thread
,
112 &ct
[i
], "%s/%d", SPLAT_CONDVAR_TEST_NAME
, i
);
114 if (!IS_ERR(ct
[i
].ct_thread
)) {
115 wake_up_process(ct
[i
].ct_thread
);
120 /* Wait until all threads are waiting on the condition variable */
121 while (atomic_read(&cv
.cv_condvar
.cv_waiters
) != count
)
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
);
128 while (atomic_read(&cv
.cv_condvar
.cv_waiters
) > (count
- i
))
131 /* Correct behavior 1 thread woken */
132 if (atomic_read(&cv
.cv_condvar
.cv_waiters
) == (count
- i
))
135 splat_vprint(file
, SPLAT_CONDVAR_TEST1_NAME
, "Attempted to "
136 "wake %d thread but work %d threads woke\n",
137 1, count
- atomic_read(&cv
.cv_condvar
.cv_waiters
));
143 splat_vprint(file
, SPLAT_CONDVAR_TEST1_NAME
, "Correctly woke "
144 "%d sleeping threads %d at a time\n", count
, 1);
146 /* Wait until that last nutex is dropped */
147 while (mutex_owner(&cv
.cv_mtx
))
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
);
159 splat_condvar_test2(struct file
*file
, void *arg
)
161 int i
, count
= 0, rc
= 0;
162 condvar_thr_t ct
[SPLAT_CONDVAR_TEST_COUNT
];
165 cv
.cv_magic
= SPLAT_CONDVAR_TEST_MAGIC
;
167 mutex_init(&cv
.cv_mtx
, SPLAT_CONDVAR_TEST_NAME
, MUTEX_DEFAULT
, NULL
);
168 cv_init(&cv
.cv_condvar
, NULL
, CV_DEFAULT
, NULL
);
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. */
172 for (i
= 0; i
< SPLAT_CONDVAR_TEST_COUNT
; i
++) {
174 ct
[i
].ct_name
= SPLAT_CONDVAR_TEST2_NAME
;
176 ct
[i
].ct_thread
= spl_kthread_create(splat_condvar_test12_thread
,
177 &ct
[i
], "%s/%d", SPLAT_CONDVAR_TEST_NAME
, i
);
179 if (!IS_ERR(ct
[i
].ct_thread
)) {
180 wake_up_process(ct
[i
].ct_thread
);
185 /* Wait until all threads are waiting on the condition variable */
186 while (atomic_read(&cv
.cv_condvar
.cv_waiters
) != count
)
189 /* Wake all threads waiting on the condition variable */
190 cv_broadcast(&cv
.cv_condvar
);
192 /* Wait until all threads have exited */
193 while ((atomic_read(&cv
.cv_condvar
.cv_waiters
) > 0) || mutex_owner(&cv
.cv_mtx
))
196 splat_vprint(file
, SPLAT_CONDVAR_TEST2_NAME
, "Correctly woke all "
197 "%d sleeping threads at once\n", count
);
199 /* Wake everything for the failure case */
200 cv_destroy(&cv
.cv_condvar
);
201 mutex_destroy(&cv
.cv_mtx
);
207 splat_condvar_test34_thread(void *arg
)
209 condvar_thr_t
*ct
= (condvar_thr_t
*)arg
;
210 condvar_priv_t
*cv
= ct
->ct_cvp
;
213 ASSERT(cv
->cv_magic
== SPLAT_CONDVAR_TEST_MAGIC
);
215 mutex_enter(&cv
->cv_mtx
);
216 splat_vprint(cv
->cv_file
, ct
->ct_name
,
217 "%s thread sleeping with %d waiters\n",
218 ct
->ct_thread
->comm
, atomic_read(&cv
->cv_condvar
.cv_waiters
));
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);
224 ct
->ct_rc
= -ETIMEDOUT
;
225 splat_vprint(cv
->cv_file
, ct
->ct_name
, "%s thread timed out, "
226 "should have been woken\n", ct
->ct_thread
->comm
);
228 splat_vprint(cv
->cv_file
, ct
->ct_name
,
229 "%s thread woken %d waiters remain\n",
231 atomic_read(&cv
->cv_condvar
.cv_waiters
));
234 mutex_exit(&cv
->cv_mtx
);
240 splat_condvar_test3(struct file
*file
, void *arg
)
242 int i
, count
= 0, rc
= 0;
243 condvar_thr_t ct
[SPLAT_CONDVAR_TEST_COUNT
];
246 cv
.cv_magic
= SPLAT_CONDVAR_TEST_MAGIC
;
248 mutex_init(&cv
.cv_mtx
, SPLAT_CONDVAR_TEST_NAME
, MUTEX_DEFAULT
, NULL
);
249 cv_init(&cv
.cv_condvar
, NULL
, CV_DEFAULT
, NULL
);
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. */
253 for (i
= 0; i
< SPLAT_CONDVAR_TEST_COUNT
; i
++) {
255 ct
[i
].ct_name
= SPLAT_CONDVAR_TEST3_NAME
;
257 ct
[i
].ct_thread
= spl_kthread_create(splat_condvar_test34_thread
,
258 &ct
[i
], "%s/%d", SPLAT_CONDVAR_TEST_NAME
, i
);
260 if (!IS_ERR(ct
[i
].ct_thread
)) {
261 wake_up_process(ct
[i
].ct_thread
);
266 /* Wait until all threads are waiting on the condition variable */
267 while (atomic_read(&cv
.cv_condvar
.cv_waiters
) != count
)
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
);
274 while (atomic_read(&cv
.cv_condvar
.cv_waiters
) > (count
- i
))
277 /* Correct behavior 1 thread woken */
278 if (atomic_read(&cv
.cv_condvar
.cv_waiters
) == (count
- i
))
281 splat_vprint(file
, SPLAT_CONDVAR_TEST3_NAME
, "Attempted to "
282 "wake %d thread but work %d threads woke\n",
283 1, count
- atomic_read(&cv
.cv_condvar
.cv_waiters
));
288 /* Validate no waiting thread timed out early */
289 for (i
= 0; i
< count
; i
++)
294 splat_vprint(file
, SPLAT_CONDVAR_TEST3_NAME
, "Correctly woke "
295 "%d sleeping threads %d at a time\n", count
, 1);
297 /* Wait until that last nutex is dropped */
298 while (mutex_owner(&cv
.cv_mtx
))
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
);
310 splat_condvar_test4(struct file
*file
, void *arg
)
312 int i
, count
= 0, rc
= 0;
313 condvar_thr_t ct
[SPLAT_CONDVAR_TEST_COUNT
];
316 cv
.cv_magic
= SPLAT_CONDVAR_TEST_MAGIC
;
318 mutex_init(&cv
.cv_mtx
, SPLAT_CONDVAR_TEST_NAME
, MUTEX_DEFAULT
, NULL
);
319 cv_init(&cv
.cv_condvar
, NULL
, CV_DEFAULT
, NULL
);
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. */
323 for (i
= 0; i
< SPLAT_CONDVAR_TEST_COUNT
; i
++) {
325 ct
[i
].ct_name
= SPLAT_CONDVAR_TEST3_NAME
;
327 ct
[i
].ct_thread
= spl_kthread_create(splat_condvar_test34_thread
,
328 &ct
[i
], "%s/%d", SPLAT_CONDVAR_TEST_NAME
, i
);
330 if (!IS_ERR(ct
[i
].ct_thread
)) {
331 wake_up_process(ct
[i
].ct_thread
);
336 /* Wait until all threads are waiting on the condition variable */
337 while (atomic_read(&cv
.cv_condvar
.cv_waiters
) != count
)
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
);
344 while (atomic_read(&cv
.cv_condvar
.cv_waiters
) > (count
- i
))
347 /* Correct behavior 1 thread woken */
348 if (atomic_read(&cv
.cv_condvar
.cv_waiters
) == (count
- i
))
351 splat_vprint(file
, SPLAT_CONDVAR_TEST3_NAME
, "Attempted to "
352 "wake %d thread but work %d threads woke\n",
353 1, count
- atomic_read(&cv
.cv_condvar
.cv_waiters
));
358 /* Validate no waiting thread timed out early */
359 for (i
= 0; i
< count
; i
++)
364 splat_vprint(file
, SPLAT_CONDVAR_TEST3_NAME
, "Correctly woke "
365 "%d sleeping threads %d at a time\n", count
, 1);
367 /* Wait until that last nutex is dropped */
368 while (mutex_owner(&cv
.cv_mtx
))
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
);
380 splat_condvar_test5(struct file
*file
, void *arg
)
384 clock_t time_left
, time_before
, time_after
, time_delta
;
386 int32_t remain_delta
;
389 mutex_init(&mtx
, SPLAT_CONDVAR_TEST_NAME
, MUTEX_DEFAULT
, NULL
);
390 cv_init(&condvar
, NULL
, CV_DEFAULT
, NULL
);
392 splat_vprint(file
, SPLAT_CONDVAR_TEST5_NAME
, "Thread going to sleep for "
393 "%d second and expecting to be woken by timeout\n", 1);
395 /* Allow a 1 second timeout, plenty long to validate correctness. */
398 time_left
= cv_timedwait(&condvar
, &mtx
, lbolt
+ HZ
);
401 time_delta
= time_after
- time_before
; /* XXX - Handle jiffie wrap */
402 whole_delta
= time_delta
;
403 remain_delta
= do_div(whole_delta
, HZ
);
405 if (time_left
== -1) {
406 if (time_delta
>= HZ
) {
407 splat_vprint(file
, SPLAT_CONDVAR_TEST5_NAME
,
408 "Thread correctly timed out and was asleep "
409 "for %d.%d seconds (%d second min)\n",
410 (int)whole_delta
, remain_delta
, 1);
412 splat_vprint(file
, SPLAT_CONDVAR_TEST5_NAME
,
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);
419 splat_vprint(file
, SPLAT_CONDVAR_TEST5_NAME
,
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);
426 cv_destroy(&condvar
);
433 splat_condvar_init(void)
435 splat_subsystem_t
*sub
;
437 sub
= kmalloc(sizeof(*sub
), GFP_KERNEL
);
441 memset(sub
, 0, sizeof(*sub
));
442 strncpy(sub
->desc
.name
, SPLAT_CONDVAR_NAME
, SPLAT_NAME_SIZE
);
443 strncpy(sub
->desc
.desc
, SPLAT_CONDVAR_DESC
, SPLAT_DESC_SIZE
);
444 INIT_LIST_HEAD(&sub
->subsystem_list
);
445 INIT_LIST_HEAD(&sub
->test_list
);
446 spin_lock_init(&sub
->test_lock
);
447 sub
->desc
.id
= SPLAT_SUBSYSTEM_CONDVAR
;
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
);
464 splat_condvar_fini(splat_subsystem_t
*sub
)
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
);
477 splat_condvar_id(void) {
478 return SPLAT_SUBSYSTEM_CONDVAR
;