test-io-task.c 6.3 KB

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