aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2019-03-14 19:20:07 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2019-06-03 14:03:00 +0200
commitaa0d7ed658f6afbdbcf4ceb8613b3c2cf5fbc7c4 (patch)
tree56d9693250306121fbcc30fe56a259ed1ae37351
parentad88e4252f09c2956b99c90de39e95bab2e8e7af (diff)
test-thread-pool: be more reliable
There is a rare race between the atomic_cmpxchg and bdrv_aio_cancel/bdrv_aio_cancel_async invocations. Detect it, the only sensible we can do about it is to exit long_cb immediately. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--tests/test-thread-pool.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/tests/test-thread-pool.c b/tests/test-thread-pool.c
index 9cdccb3a47..0b675923f6 100644
--- a/tests/test-thread-pool.c
+++ b/tests/test-thread-pool.c
@@ -27,9 +27,10 @@ static int worker_cb(void *opaque)
static int long_cb(void *opaque)
{
WorkerTestData *data = opaque;
- atomic_inc(&data->n);
- g_usleep(2000000);
- atomic_inc(&data->n);
+ if (atomic_cmpxchg(&data->n, 0, 1) == 0) {
+ g_usleep(2000000);
+ atomic_or(&data->n, 2);
+ }
return 0;
}
@@ -171,7 +172,7 @@ static void do_test_cancel(bool sync)
/* Cancel the jobs that haven't been started yet. */
num_canceled = 0;
for (i = 0; i < 100; i++) {
- if (atomic_cmpxchg(&data[i].n, 0, 3) == 0) {
+ if (atomic_cmpxchg(&data[i].n, 0, 4) == 0) {
data[i].ret = -ECANCELED;
if (sync) {
bdrv_aio_cancel(data[i].aiocb);
@@ -185,7 +186,7 @@ static void do_test_cancel(bool sync)
g_assert_cmpint(num_canceled, <, 100);
for (i = 0; i < 100; i++) {
- if (data[i].aiocb && data[i].n != 3) {
+ if (data[i].aiocb && atomic_read(&data[i].n) < 4) {
if (sync) {
/* Canceling the others will be a blocking operation. */
bdrv_aio_cancel(data[i].aiocb);
@@ -201,13 +202,22 @@ static void do_test_cancel(bool sync)
}
g_assert_cmpint(active, ==, 0);
for (i = 0; i < 100; i++) {
- if (data[i].n == 3) {
+ g_assert(data[i].aiocb == NULL);
+ switch (data[i].n) {
+ case 0:
+ fprintf(stderr, "Callback not canceled but never started?\n");
+ abort();
+ case 3:
+ /* Couldn't be canceled asynchronously, must have completed. */
+ g_assert_cmpint(data[i].ret, ==, 0);
+ break;
+ case 4:
+ /* Could be canceled asynchronously, never started. */
g_assert_cmpint(data[i].ret, ==, -ECANCELED);
- g_assert(data[i].aiocb == NULL);
- } else {
- g_assert_cmpint(data[i].n, ==, 2);
- g_assert(data[i].ret == 0 || data[i].ret == -ECANCELED);
- g_assert(data[i].aiocb == NULL);
+ break;
+ default:
+ fprintf(stderr, "Callback aborted while running?\n");
+ abort();
}
}
}