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_CONDVAR 0x0500
30 #define SPLAT_CONDVAR_NAME "condvar"
31 #define SPLAT_CONDVAR_DESC "Kernel Condition Variable Tests"
33 #define SPLAT_CONDVAR_TEST1_ID 0x0501
34 #define SPLAT_CONDVAR_TEST1_NAME "signal1"
35 #define SPLAT_CONDVAR_TEST1_DESC "Wake a single thread, cv_wait()/cv_signal()"
37 #define SPLAT_CONDVAR_TEST2_ID 0x0502
38 #define SPLAT_CONDVAR_TEST2_NAME "broadcast1"
39 #define SPLAT_CONDVAR_TEST2_DESC "Wake all threads, cv_wait()/cv_broadcast()"
41 #define SPLAT_CONDVAR_TEST3_ID 0x0503
42 #define SPLAT_CONDVAR_TEST3_NAME "signal2"
43 #define SPLAT_CONDVAR_TEST3_DESC "Wake a single thread, cv_wait_timeout()/cv_signal()"
45 #define SPLAT_CONDVAR_TEST4_ID 0x0504
46 #define SPLAT_CONDVAR_TEST4_NAME "broadcast2"
47 #define SPLAT_CONDVAR_TEST4_DESC "Wake all threads, cv_wait_timeout()/cv_broadcast()"
49 #define SPLAT_CONDVAR_TEST5_ID 0x0505
50 #define SPLAT_CONDVAR_TEST5_NAME "timeout"
51 #define SPLAT_CONDVAR_TEST5_DESC "Timeout thread, cv_wait_timeout()"
53 #define SPLAT_CONDVAR_TEST_MAGIC 0x115599DDUL
54 #define SPLAT_CONDVAR_TEST_NAME "condvar_test"
55 #define SPLAT_CONDVAR_TEST_COUNT 8
57 typedef struct condvar_priv
{
58 unsigned long cv_magic
;
60 kcondvar_t cv_condvar
;
64 typedef struct condvar_thr
{
67 condvar_priv_t
*ct_cvp
;
72 splat_condvar_test12_thread(void *arg
)
74 condvar_thr_t
*ct
= (condvar_thr_t
*)arg
;
75 condvar_priv_t
*cv
= ct
->ct_cvp
;
78 ASSERT(cv
->cv_magic
== SPLAT_CONDVAR_TEST_MAGIC
);
79 snprintf(name
, sizeof(name
),"%s%d",SPLAT_CONDVAR_TEST_NAME
,ct
->ct_id
);
82 mutex_enter(&cv
->cv_mtx
);
83 splat_vprint(cv
->cv_file
, ct
->ct_name
,
84 "%s thread sleeping with %d waiters\n",
85 name
, atomic_read(&cv
->cv_condvar
.cv_waiters
));
86 cv_wait(&cv
->cv_condvar
, &cv
->cv_mtx
);
87 splat_vprint(cv
->cv_file
, ct
->ct_name
,
88 "%s thread woken %d waiters remain\n",
89 name
, atomic_read(&cv
->cv_condvar
.cv_waiters
));
90 mutex_exit(&cv
->cv_mtx
);
96 splat_condvar_test1(struct file
*file
, void *arg
)
98 int i
, count
= 0, rc
= 0;
99 long pids
[SPLAT_CONDVAR_TEST_COUNT
];
100 condvar_thr_t ct
[SPLAT_CONDVAR_TEST_COUNT
];
103 cv
.cv_magic
= SPLAT_CONDVAR_TEST_MAGIC
;
105 mutex_init(&cv
.cv_mtx
, SPLAT_CONDVAR_TEST_NAME
, MUTEX_DEFAULT
, NULL
);
106 cv_init(&cv
.cv_condvar
, SPLAT_CONDVAR_TEST_NAME
, CV_DEFAULT
, NULL
);
108 /* Create some threads, the exact number isn't important just as
109 * long as we know how many we managed to create and should expect. */
110 for (i
= 0; i
< SPLAT_CONDVAR_TEST_COUNT
; i
++) {
113 ct
[i
].ct_name
= SPLAT_CONDVAR_TEST1_NAME
;
116 pids
[i
] = kernel_thread(splat_condvar_test12_thread
, &ct
[i
], 0);
121 /* Wait until all threads are waiting on the condition variable */
122 while (atomic_read(&cv
.cv_condvar
.cv_waiters
) != count
)
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
);
129 while (atomic_read(&cv
.cv_condvar
.cv_waiters
) > (count
- i
))
132 /* Correct behavior 1 thread woken */
133 if (atomic_read(&cv
.cv_condvar
.cv_waiters
) == (count
- i
))
136 splat_vprint(file
, SPLAT_CONDVAR_TEST1_NAME
, "Attempted to "
137 "wake %d thread but work %d threads woke\n",
138 1, count
- atomic_read(&cv
.cv_condvar
.cv_waiters
));
144 splat_vprint(file
, SPLAT_CONDVAR_TEST1_NAME
, "Correctly woke "
145 "%d sleeping threads %d at a time\n", count
, 1);
147 /* Wait until that last nutex is dropped */
148 while (mutex_owner(&cv
.cv_mtx
))
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
);
160 splat_condvar_test2(struct file
*file
, void *arg
)
162 int i
, count
= 0, rc
= 0;
163 long pids
[SPLAT_CONDVAR_TEST_COUNT
];
164 condvar_thr_t ct
[SPLAT_CONDVAR_TEST_COUNT
];
167 cv
.cv_magic
= SPLAT_CONDVAR_TEST_MAGIC
;
169 mutex_init(&cv
.cv_mtx
, SPLAT_CONDVAR_TEST_NAME
, MUTEX_DEFAULT
, NULL
);
170 cv_init(&cv
.cv_condvar
, SPLAT_CONDVAR_TEST_NAME
, CV_DEFAULT
, NULL
);
172 /* Create some threads, the exact number isn't important just as
173 * long as we know how many we managed to create and should expect. */
174 for (i
= 0; i
< SPLAT_CONDVAR_TEST_COUNT
; i
++) {
177 ct
[i
].ct_name
= SPLAT_CONDVAR_TEST2_NAME
;
180 pids
[i
] = kernel_thread(splat_condvar_test12_thread
, &ct
[i
], 0);
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
;
214 ASSERT(cv
->cv_magic
== SPLAT_CONDVAR_TEST_MAGIC
);
215 snprintf(name
, sizeof(name
), "%s%d", SPLAT_CONDVAR_TEST_NAME
, ct
->ct_id
);
218 mutex_enter(&cv
->cv_mtx
);
219 splat_vprint(cv
->cv_file
, ct
->ct_name
,
220 "%s thread sleeping with %d waiters\n",
221 name
, atomic_read(&cv
->cv_condvar
.cv_waiters
));
223 /* Sleep no longer than 3 seconds, for this test we should
224 * actually never sleep that long without being woken up. */
225 rc
= cv_timedwait(&cv
->cv_condvar
, &cv
->cv_mtx
, lbolt
+ HZ
* 3);
227 ct
->ct_rc
= -ETIMEDOUT
;
228 splat_vprint(cv
->cv_file
, ct
->ct_name
, "%s thread timed out, "
229 "should have been woken\n", name
);
231 splat_vprint(cv
->cv_file
, ct
->ct_name
,
232 "%s thread woken %d waiters remain\n",
233 name
, atomic_read(&cv
->cv_condvar
.cv_waiters
));
236 mutex_exit(&cv
->cv_mtx
);
242 splat_condvar_test3(struct file
*file
, void *arg
)
244 int i
, count
= 0, rc
= 0;
245 long pids
[SPLAT_CONDVAR_TEST_COUNT
];
246 condvar_thr_t ct
[SPLAT_CONDVAR_TEST_COUNT
];
249 cv
.cv_magic
= SPLAT_CONDVAR_TEST_MAGIC
;
251 mutex_init(&cv
.cv_mtx
, SPLAT_CONDVAR_TEST_NAME
, MUTEX_DEFAULT
, NULL
);
252 cv_init(&cv
.cv_condvar
, SPLAT_CONDVAR_TEST_NAME
, CV_DEFAULT
, NULL
);
254 /* Create some threads, the exact number isn't important just as
255 * long as we know how many we managed to create and should expect. */
256 for (i
= 0; i
< SPLAT_CONDVAR_TEST_COUNT
; i
++) {
259 ct
[i
].ct_name
= SPLAT_CONDVAR_TEST3_NAME
;
262 pids
[i
] = kernel_thread(splat_condvar_test34_thread
, &ct
[i
], 0);
267 /* Wait until all threads are waiting on the condition variable */
268 while (atomic_read(&cv
.cv_condvar
.cv_waiters
) != count
)
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
);
275 while (atomic_read(&cv
.cv_condvar
.cv_waiters
) > (count
- i
))
278 /* Correct behavior 1 thread woken */
279 if (atomic_read(&cv
.cv_condvar
.cv_waiters
) == (count
- i
))
282 splat_vprint(file
, SPLAT_CONDVAR_TEST3_NAME
, "Attempted to "
283 "wake %d thread but work %d threads woke\n",
284 1, count
- atomic_read(&cv
.cv_condvar
.cv_waiters
));
289 /* Validate no waiting thread timed out early */
290 for (i
= 0; i
< count
; i
++)
295 splat_vprint(file
, SPLAT_CONDVAR_TEST3_NAME
, "Correctly woke "
296 "%d sleeping threads %d at a time\n", count
, 1);
298 /* Wait until that last nutex is dropped */
299 while (mutex_owner(&cv
.cv_mtx
))
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
);
311 splat_condvar_test4(struct file
*file
, void *arg
)
313 int i
, count
= 0, rc
= 0;
314 long pids
[SPLAT_CONDVAR_TEST_COUNT
];
315 condvar_thr_t ct
[SPLAT_CONDVAR_TEST_COUNT
];
318 cv
.cv_magic
= SPLAT_CONDVAR_TEST_MAGIC
;
320 mutex_init(&cv
.cv_mtx
, SPLAT_CONDVAR_TEST_NAME
, MUTEX_DEFAULT
, NULL
);
321 cv_init(&cv
.cv_condvar
, SPLAT_CONDVAR_TEST_NAME
, CV_DEFAULT
, NULL
);
323 /* Create some threads, the exact number isn't important just as
324 * long as we know how many we managed to create and should expect. */
325 for (i
= 0; i
< SPLAT_CONDVAR_TEST_COUNT
; i
++) {
328 ct
[i
].ct_name
= SPLAT_CONDVAR_TEST3_NAME
;
331 pids
[i
] = kernel_thread(splat_condvar_test34_thread
, &ct
[i
], 0);
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
, SPLAT_CONDVAR_TEST_NAME
, 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
;