1*da668aa1SThomas Huth /* 2*da668aa1SThomas Huth * QEMU I/O task tests 3*da668aa1SThomas Huth * 4*da668aa1SThomas Huth * Copyright (c) 2015 Red Hat, Inc. 5*da668aa1SThomas Huth * 6*da668aa1SThomas Huth * This library is free software; you can redistribute it and/or 7*da668aa1SThomas Huth * modify it under the terms of the GNU Lesser General Public 8*da668aa1SThomas Huth * License as published by the Free Software Foundation; either 9*da668aa1SThomas Huth * version 2.1 of the License, or (at your option) any later version. 10*da668aa1SThomas Huth * 11*da668aa1SThomas Huth * This library is distributed in the hope that it will be useful, 12*da668aa1SThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*da668aa1SThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14*da668aa1SThomas Huth * Lesser General Public License for more details. 15*da668aa1SThomas Huth * 16*da668aa1SThomas Huth * You should have received a copy of the GNU Lesser General Public 17*da668aa1SThomas Huth * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18*da668aa1SThomas Huth * 19*da668aa1SThomas Huth */ 20*da668aa1SThomas Huth 21*da668aa1SThomas Huth #include "qemu/osdep.h" 22*da668aa1SThomas Huth 23*da668aa1SThomas Huth #include "qom/object.h" 24*da668aa1SThomas Huth #include "io/task.h" 25*da668aa1SThomas Huth #include "qapi/error.h" 26*da668aa1SThomas Huth #include "qemu/module.h" 27*da668aa1SThomas Huth 28*da668aa1SThomas Huth #define TYPE_DUMMY "qemu:dummy" 29*da668aa1SThomas Huth 30*da668aa1SThomas Huth typedef struct DummyObject DummyObject; 31*da668aa1SThomas Huth typedef struct DummyObjectClass DummyObjectClass; 32*da668aa1SThomas Huth 33*da668aa1SThomas Huth struct DummyObject { 34*da668aa1SThomas Huth Object parent; 35*da668aa1SThomas Huth }; 36*da668aa1SThomas Huth 37*da668aa1SThomas Huth struct DummyObjectClass { 38*da668aa1SThomas Huth ObjectClass parent; 39*da668aa1SThomas Huth }; 40*da668aa1SThomas Huth 41*da668aa1SThomas Huth static const TypeInfo dummy_info = { 42*da668aa1SThomas Huth .parent = TYPE_OBJECT, 43*da668aa1SThomas Huth .name = TYPE_DUMMY, 44*da668aa1SThomas Huth .instance_size = sizeof(DummyObject), 45*da668aa1SThomas Huth .class_size = sizeof(DummyObjectClass), 46*da668aa1SThomas Huth }; 47*da668aa1SThomas Huth 48*da668aa1SThomas Huth struct TestTaskData { 49*da668aa1SThomas Huth Object *source; 50*da668aa1SThomas Huth Error *err; 51*da668aa1SThomas Huth bool freed; 52*da668aa1SThomas Huth }; 53*da668aa1SThomas Huth 54*da668aa1SThomas Huth 55*da668aa1SThomas Huth static void task_callback(QIOTask *task, 56*da668aa1SThomas Huth gpointer opaque) 57*da668aa1SThomas Huth { 58*da668aa1SThomas Huth struct TestTaskData *data = opaque; 59*da668aa1SThomas Huth 60*da668aa1SThomas Huth data->source = qio_task_get_source(task); 61*da668aa1SThomas Huth qio_task_propagate_error(task, &data->err); 62*da668aa1SThomas Huth } 63*da668aa1SThomas Huth 64*da668aa1SThomas Huth 65*da668aa1SThomas Huth static void test_task_complete(void) 66*da668aa1SThomas Huth { 67*da668aa1SThomas Huth QIOTask *task; 68*da668aa1SThomas Huth Object *obj = object_new(TYPE_DUMMY); 69*da668aa1SThomas Huth Object *src; 70*da668aa1SThomas Huth struct TestTaskData data = { NULL, NULL, false }; 71*da668aa1SThomas Huth 72*da668aa1SThomas Huth task = qio_task_new(obj, task_callback, &data, NULL); 73*da668aa1SThomas Huth src = qio_task_get_source(task); 74*da668aa1SThomas Huth 75*da668aa1SThomas Huth qio_task_complete(task); 76*da668aa1SThomas Huth 77*da668aa1SThomas Huth g_assert(obj == src); 78*da668aa1SThomas Huth 79*da668aa1SThomas Huth object_unref(obj); 80*da668aa1SThomas Huth 81*da668aa1SThomas Huth g_assert(data.source == obj); 82*da668aa1SThomas Huth g_assert(data.err == NULL); 83*da668aa1SThomas Huth g_assert(data.freed == false); 84*da668aa1SThomas Huth } 85*da668aa1SThomas Huth 86*da668aa1SThomas Huth 87*da668aa1SThomas Huth static void task_data_free(gpointer opaque) 88*da668aa1SThomas Huth { 89*da668aa1SThomas Huth struct TestTaskData *data = opaque; 90*da668aa1SThomas Huth 91*da668aa1SThomas Huth data->freed = true; 92*da668aa1SThomas Huth } 93*da668aa1SThomas Huth 94*da668aa1SThomas Huth 95*da668aa1SThomas Huth static void test_task_data_free(void) 96*da668aa1SThomas Huth { 97*da668aa1SThomas Huth QIOTask *task; 98*da668aa1SThomas Huth Object *obj = object_new(TYPE_DUMMY); 99*da668aa1SThomas Huth struct TestTaskData data = { NULL, NULL, false }; 100*da668aa1SThomas Huth 101*da668aa1SThomas Huth task = qio_task_new(obj, task_callback, &data, task_data_free); 102*da668aa1SThomas Huth 103*da668aa1SThomas Huth qio_task_complete(task); 104*da668aa1SThomas Huth 105*da668aa1SThomas Huth object_unref(obj); 106*da668aa1SThomas Huth 107*da668aa1SThomas Huth g_assert(data.source == obj); 108*da668aa1SThomas Huth g_assert(data.err == NULL); 109*da668aa1SThomas Huth g_assert(data.freed == true); 110*da668aa1SThomas Huth } 111*da668aa1SThomas Huth 112*da668aa1SThomas Huth 113*da668aa1SThomas Huth static void test_task_failure(void) 114*da668aa1SThomas Huth { 115*da668aa1SThomas Huth QIOTask *task; 116*da668aa1SThomas Huth Object *obj = object_new(TYPE_DUMMY); 117*da668aa1SThomas Huth struct TestTaskData data = { NULL, NULL, false }; 118*da668aa1SThomas Huth Error *err = NULL; 119*da668aa1SThomas Huth 120*da668aa1SThomas Huth task = qio_task_new(obj, task_callback, &data, NULL); 121*da668aa1SThomas Huth 122*da668aa1SThomas Huth error_setg(&err, "Some error"); 123*da668aa1SThomas Huth 124*da668aa1SThomas Huth qio_task_set_error(task, err); 125*da668aa1SThomas Huth qio_task_complete(task); 126*da668aa1SThomas Huth 127*da668aa1SThomas Huth object_unref(obj); 128*da668aa1SThomas Huth 129*da668aa1SThomas Huth g_assert(data.source == obj); 130*da668aa1SThomas Huth g_assert(data.err == err); 131*da668aa1SThomas Huth g_assert(data.freed == false); 132*da668aa1SThomas Huth error_free(data.err); 133*da668aa1SThomas Huth } 134*da668aa1SThomas Huth 135*da668aa1SThomas Huth 136*da668aa1SThomas Huth struct TestThreadWorkerData { 137*da668aa1SThomas Huth Object *source; 138*da668aa1SThomas Huth Error *err; 139*da668aa1SThomas Huth bool fail; 140*da668aa1SThomas Huth GThread *worker; 141*da668aa1SThomas Huth GThread *complete; 142*da668aa1SThomas Huth GMainLoop *loop; 143*da668aa1SThomas Huth }; 144*da668aa1SThomas Huth 145*da668aa1SThomas Huth static void test_task_thread_worker(QIOTask *task, 146*da668aa1SThomas Huth gpointer opaque) 147*da668aa1SThomas Huth { 148*da668aa1SThomas Huth struct TestThreadWorkerData *data = opaque; 149*da668aa1SThomas Huth 150*da668aa1SThomas Huth data->worker = g_thread_self(); 151*da668aa1SThomas Huth 152*da668aa1SThomas Huth if (data->fail) { 153*da668aa1SThomas Huth Error *err = NULL; 154*da668aa1SThomas Huth error_setg(&err, "Testing fail"); 155*da668aa1SThomas Huth qio_task_set_error(task, err); 156*da668aa1SThomas Huth } 157*da668aa1SThomas Huth } 158*da668aa1SThomas Huth 159*da668aa1SThomas Huth 160*da668aa1SThomas Huth static void test_task_thread_callback(QIOTask *task, 161*da668aa1SThomas Huth gpointer opaque) 162*da668aa1SThomas Huth { 163*da668aa1SThomas Huth struct TestThreadWorkerData *data = opaque; 164*da668aa1SThomas Huth 165*da668aa1SThomas Huth data->source = qio_task_get_source(task); 166*da668aa1SThomas Huth qio_task_propagate_error(task, &data->err); 167*da668aa1SThomas Huth 168*da668aa1SThomas Huth data->complete = g_thread_self(); 169*da668aa1SThomas Huth 170*da668aa1SThomas Huth g_main_loop_quit(data->loop); 171*da668aa1SThomas Huth } 172*da668aa1SThomas Huth 173*da668aa1SThomas Huth 174*da668aa1SThomas Huth static void test_task_thread_complete(void) 175*da668aa1SThomas Huth { 176*da668aa1SThomas Huth QIOTask *task; 177*da668aa1SThomas Huth Object *obj = object_new(TYPE_DUMMY); 178*da668aa1SThomas Huth struct TestThreadWorkerData data = { 0 }; 179*da668aa1SThomas Huth GThread *self; 180*da668aa1SThomas Huth 181*da668aa1SThomas Huth data.loop = g_main_loop_new(g_main_context_default(), 182*da668aa1SThomas Huth TRUE); 183*da668aa1SThomas Huth 184*da668aa1SThomas Huth task = qio_task_new(obj, 185*da668aa1SThomas Huth test_task_thread_callback, 186*da668aa1SThomas Huth &data, 187*da668aa1SThomas Huth NULL); 188*da668aa1SThomas Huth 189*da668aa1SThomas Huth qio_task_run_in_thread(task, 190*da668aa1SThomas Huth test_task_thread_worker, 191*da668aa1SThomas Huth &data, 192*da668aa1SThomas Huth NULL, 193*da668aa1SThomas Huth NULL); 194*da668aa1SThomas Huth 195*da668aa1SThomas Huth g_main_loop_run(data.loop); 196*da668aa1SThomas Huth 197*da668aa1SThomas Huth g_main_loop_unref(data.loop); 198*da668aa1SThomas Huth object_unref(obj); 199*da668aa1SThomas Huth 200*da668aa1SThomas Huth g_assert(data.source == obj); 201*da668aa1SThomas Huth g_assert(data.err == NULL); 202*da668aa1SThomas Huth 203*da668aa1SThomas Huth self = g_thread_self(); 204*da668aa1SThomas Huth 205*da668aa1SThomas Huth /* Make sure the test_task_thread_worker actually got 206*da668aa1SThomas Huth * run in a different thread */ 207*da668aa1SThomas Huth g_assert(data.worker != self); 208*da668aa1SThomas Huth 209*da668aa1SThomas Huth /* And that the test_task_thread_callback got rnu in 210*da668aa1SThomas Huth * the main loop thread (ie this one) */ 211*da668aa1SThomas Huth g_assert(data.complete == self); 212*da668aa1SThomas Huth } 213*da668aa1SThomas Huth 214*da668aa1SThomas Huth 215*da668aa1SThomas Huth static void test_task_thread_failure(void) 216*da668aa1SThomas Huth { 217*da668aa1SThomas Huth QIOTask *task; 218*da668aa1SThomas Huth Object *obj = object_new(TYPE_DUMMY); 219*da668aa1SThomas Huth struct TestThreadWorkerData data = { 0 }; 220*da668aa1SThomas Huth GThread *self; 221*da668aa1SThomas Huth 222*da668aa1SThomas Huth data.loop = g_main_loop_new(g_main_context_default(), 223*da668aa1SThomas Huth TRUE); 224*da668aa1SThomas Huth data.fail = true; 225*da668aa1SThomas Huth 226*da668aa1SThomas Huth task = qio_task_new(obj, 227*da668aa1SThomas Huth test_task_thread_callback, 228*da668aa1SThomas Huth &data, 229*da668aa1SThomas Huth NULL); 230*da668aa1SThomas Huth 231*da668aa1SThomas Huth qio_task_run_in_thread(task, 232*da668aa1SThomas Huth test_task_thread_worker, 233*da668aa1SThomas Huth &data, 234*da668aa1SThomas Huth NULL, 235*da668aa1SThomas Huth NULL); 236*da668aa1SThomas Huth 237*da668aa1SThomas Huth g_main_loop_run(data.loop); 238*da668aa1SThomas Huth 239*da668aa1SThomas Huth g_main_loop_unref(data.loop); 240*da668aa1SThomas Huth object_unref(obj); 241*da668aa1SThomas Huth 242*da668aa1SThomas Huth g_assert(data.source == obj); 243*da668aa1SThomas Huth error_free_or_abort(&data.err); 244*da668aa1SThomas Huth 245*da668aa1SThomas Huth self = g_thread_self(); 246*da668aa1SThomas Huth 247*da668aa1SThomas Huth /* Make sure the test_task_thread_worker actually got 248*da668aa1SThomas Huth * run in a different thread */ 249*da668aa1SThomas Huth g_assert(data.worker != self); 250*da668aa1SThomas Huth 251*da668aa1SThomas Huth /* And that the test_task_thread_callback got rnu in 252*da668aa1SThomas Huth * the main loop thread (ie this one) */ 253*da668aa1SThomas Huth g_assert(data.complete == self); 254*da668aa1SThomas Huth } 255*da668aa1SThomas Huth 256*da668aa1SThomas Huth 257*da668aa1SThomas Huth int main(int argc, char **argv) 258*da668aa1SThomas Huth { 259*da668aa1SThomas Huth g_test_init(&argc, &argv, NULL); 260*da668aa1SThomas Huth module_call_init(MODULE_INIT_QOM); 261*da668aa1SThomas Huth type_register_static(&dummy_info); 262*da668aa1SThomas Huth g_test_add_func("/crypto/task/complete", test_task_complete); 263*da668aa1SThomas Huth g_test_add_func("/crypto/task/datafree", test_task_data_free); 264*da668aa1SThomas Huth g_test_add_func("/crypto/task/failure", test_task_failure); 265*da668aa1SThomas Huth g_test_add_func("/crypto/task/thread_complete", test_task_thread_complete); 266*da668aa1SThomas Huth g_test_add_func("/crypto/task/thread_failure", test_task_thread_failure); 267*da668aa1SThomas Huth return g_test_run(); 268*da668aa1SThomas Huth } 269