@@ -198,6 +198,16 @@ void qtest_qmp_vsend(QTestState *s, const char *fmt, va_list ap)
*/
QDict *qtest_qmp_receive_dict(QTestState *s);
+/**
+ * qtest_qmp_receive:
+ * @s: #QTestState instance to operate on.
+ *
+ * Reads a QMP message from QEMU and returns the response.
+ * Buffers all the events received meanwhile, until a
+ * call to qtest_qmp_eventwait
+ */
+QDict *qtest_qmp_receive(QTestState *s);
+
/**
* qtest_qmp_eventwait:
* @s: #QTestState instance to operate on.
@@ -217,6 +227,19 @@ void qtest_qmp_eventwait(QTestState *s, const char *event);
*/
QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event);
+/**
+ * qtest_qmp_event_ref:
+ * @s: #QTestState instance to operate on.
+ * @s: #event event to return.
+ *
+ * Removes non-matching events from the buffer that was set by
+ * qtest_qmp_receive, until an event bearing the given name is found,
+ * and returns it.
+ * If no event matches, clears the buffer and returns NULL.
+ *
+ */
+QDict *qtest_qmp_event_ref(QTestState *s, const char *event);
+
/**
* qtest_qmp_receive_success:
* @s: #QTestState instance to operate on
@@ -63,6 +63,7 @@ struct QTestState
bool irq_level[MAX_IRQ];
GString *rx;
QTestTransportOps ops;
+ GList *pending_events;
};
static GHookList abrt_hooks;
@@ -279,6 +280,7 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
g_test_message("starting QEMU: %s", command);
+ s->pending_events = NULL;
s->wstatus = 0;
s->expected_status = 0;
s->qemu_pid = fork();
@@ -386,6 +388,13 @@ void qtest_quit(QTestState *s)
close(s->fd);
close(s->qmp_fd);
g_string_free(s->rx, true);
+
+ for (GList *it = s->pending_events; it != NULL; it = it->next) {
+ qobject_unref((QDict *)it->data);
+ }
+
+ g_list_free(s->pending_events);
+
g_free(s);
}
@@ -603,6 +612,19 @@ QDict *qmp_fd_receive(int fd)
return qmp.response;
}
+QDict *qtest_qmp_receive(QTestState *s)
+{
+ while (true) {
+ QDict *response = qtest_qmp_receive_dict(s);
+
+ if (!qdict_get_try_str(response, "event")) {
+ return response;
+ }
+ /* Stash the event for a later consumption */
+ s->pending_events = g_list_prepend(s->pending_events, response);
+ }
+}
+
QDict *qtest_qmp_receive_dict(QTestState *s)
{
return qmp_fd_receive(s->qmp_fd);
@@ -771,10 +793,34 @@ void qtest_qmp_send_raw(QTestState *s, const char *fmt, ...)
va_end(ap);
}
-QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event)
+QDict *qtest_qmp_event_ref(QTestState *s, const char *event)
{
+ GList *next = NULL;
QDict *response;
+ for (GList *it = s->pending_events; it != NULL; it = next) {
+
+ next = it->next;
+ response = (QDict *)it->data;
+
+ s->pending_events = g_list_remove_link(s->pending_events, it);
+
+ if (!strcmp(qdict_get_str(response, "event"), event)) {
+ return response;
+ }
+ qobject_unref(response);
+ }
+ return NULL;
+}
+
+QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event)
+{
+ QDict *response = qtest_qmp_event_ref(s, event);
+
+ if (response) {
+ return response;
+ }
+
for (;;) {
response = qtest_qmp_receive_dict(s);
if ((qdict_haskey(response, "event")) &&
@@ -1403,6 +1449,7 @@ QTestState *qtest_inproc_init(QTestState **s, bool log, const char* arch,
{
QTestState *qts;
qts = g_new0(QTestState, 1);
+ qts->pending_events = NULL;
*s = qts; /* Expose qts early on, since the query endianness relies on it */
qts->wstatus = 0;
for (int i = 0; i < MAX_IRQ; i++) {