From 4cf6bfab4cb9e47478e5e36f65bb3f3b9dd16fb8 Mon Sep 17 00:00:00 2001 From: John Ferlan Date: Fri, 29 Aug 2014 16:23:11 -0400 Subject: [PATCH] qemu: Issue query-iothreads and to get list of active IOThreads Generate infrastructure and test to handle fetching the QMP IOThreads data. --- src/qemu/qemu_monitor.c | 41 ++++++++++++++++ src/qemu/qemu_monitor.h | 12 +++++ src/qemu/qemu_monitor_json.c | 91 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 ++ tests/qemumonitorjsontest.c | 71 ++++++++++++++++++++++++++++ 5 files changed, 219 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 3a32a4f553..3603cd8122 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4061,3 +4061,44 @@ qemuMonitorRTCResetReinjection(qemuMonitorPtr mon) return qemuMonitorJSONRTCResetReinjection(mon); } + +/** + * qemuMonitorGetIOThreads: + * @mon: Pointer to the monitor + * @iothreads: Location to return array of IOThreadInfo data + * + * Issue query-iothreads command. + * Retrieve the list of iothreads defined/running for the machine + * + * Returns count of IOThreadInfo structures on success + * -1 on error. + */ +int +qemuMonitorGetIOThreads(qemuMonitorPtr mon, + qemuMonitorIOThreadsInfoPtr **iothreads) +{ + + VIR_DEBUG("mon=%p iothreads=%p", mon, iothreads); + + if (!mon) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("monitor must not be NULL")); + return -1; + } + + if (!mon->json) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("JSON monitor is required")); + return -1; + } + + return qemuMonitorJSONGetIOThreads(mon, iothreads); +} + +void qemuMonitorIOThreadsInfoFree(qemuMonitorIOThreadsInfoPtr iothread) +{ + if (!iothread) + return; + VIR_FREE(iothread->name); + VIR_FREE(iothread); +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c32001d7d2..61a14d442d 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -798,6 +798,18 @@ int qemuMonitorGetGuestCPU(qemuMonitorPtr mon, int qemuMonitorRTCResetReinjection(qemuMonitorPtr mon); +typedef struct _qemuMonitorIOThreadsInfo qemuMonitorIOThreadsInfo; +typedef qemuMonitorIOThreadsInfo *qemuMonitorIOThreadsInfoPtr; + +struct _qemuMonitorIOThreadsInfo { + char *name; + int thread_id; +}; +int qemuMonitorGetIOThreads(qemuMonitorPtr mon, + qemuMonitorIOThreadsInfoPtr **iothreads); + +void qemuMonitorIOThreadsInfoFree(qemuMonitorIOThreadsInfoPtr iothread); + /** * When running two dd process and using <> redirection, we need a * shell that will not truncate files. These two strings serve that diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 0c4832a5ba..1e14a95dad 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -5910,3 +5910,94 @@ qemuMonitorJSONRTCResetReinjection(qemuMonitorPtr mon) virJSONValueFree(reply); return ret; } + +/** + * Query and parse returned array of data such as: + * + * {u'return': [{u'id': u'iothread1', u'thread-id': 30992}, \ + * {u'id': u'iothread2', u'thread-id': 30993}]} + */ +int +qemuMonitorJSONGetIOThreads(qemuMonitorPtr mon, + qemuMonitorIOThreadsInfoPtr **iothreads) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + virJSONValuePtr data; + qemuMonitorIOThreadsInfoPtr *infolist = NULL; + int n = 0; + size_t i; + + *iothreads = NULL; + + if (!(cmd = qemuMonitorJSONMakeCommand("query-iothreads", NULL))) + return ret; + + ret = qemuMonitorJSONCommand(mon, cmd, &reply); + + if (ret == 0) + ret = qemuMonitorJSONCheckError(cmd, reply); + + if (ret < 0) + goto cleanup; + + ret = -1; + + if (!(data = virJSONValueObjectGet(reply, "return"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-iothreads reply was missing return data")); + goto cleanup; + } + + if ((n = virJSONValueArraySize(data)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-iothreads reply data was not an array")); + goto cleanup; + } + + /* null-terminated list */ + if (VIR_ALLOC_N(infolist, n + 1) < 0) + goto cleanup; + + for (i = 0; i < n; i++) { + virJSONValuePtr child = virJSONValueArrayGet(data, i); + const char *tmp; + qemuMonitorIOThreadsInfoPtr info; + + if (VIR_ALLOC(info) < 0) + goto cleanup; + + infolist[i] = info; + + if (!(tmp = virJSONValueObjectGetString(child, "id"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-iothreads reply data was missing 'id'")); + goto cleanup; + } + + if (VIR_STRDUP(info->name, tmp) < 0) + goto cleanup; + + if (virJSONValueObjectGetNumberInt(child, "thread-id", + &info->thread_id) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-iothreads reply has malformed " + "'thread-id' data")); + goto cleanup; + } + } + + ret = n; + *iothreads = infolist; + + cleanup: + if (ret < 0 && infolist) { + for (i = 0; i < n; i++) + qemuMonitorIOThreadsInfoFree(infolist[i]); + VIR_FREE(infolist); + } + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index b5c61ca614..732209dabe 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -446,4 +446,8 @@ int qemuMonitorJSONGetGuestCPU(qemuMonitorPtr mon, virCPUDataPtr *data); int qemuMonitorJSONRTCResetReinjection(qemuMonitorPtr mon); + +int qemuMonitorJSONGetIOThreads(qemuMonitorPtr mon, + qemuMonitorIOThreadsInfoPtr **iothreads) + ATTRIBUTE_NONNULL(2); #endif /* QEMU_MONITOR_JSON_H */ diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index afbf13a667..b8177c0dc7 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -2216,6 +2216,76 @@ testQemuMonitorJSONGetNonExistingCPUData(const void *opaque) return ret; } +static int +testQemuMonitorJSONGetIOThreads(const void *data) +{ + virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; + qemuMonitorTestPtr test = qemuMonitorTestNewSimple(true, xmlopt); + qemuMonitorIOThreadsInfoPtr *info; + int ninfo = 0; + int ret = -1; + size_t i; + + if (!test) + return -1; + + if (qemuMonitorTestAddItem(test, "query-iothreads", + "{ " + " \"return\": [ " + " { " + " \"id\": \"iothread1\", " + " \"thread-id\": 30992 " + " }, " + " { " + " \"id\": \"iothread2\", " + " \"thread-id\": 30993 " + " } " + " ]" + "}") < 0) + goto cleanup; + + if ((ninfo = qemuMonitorGetIOThreads(qemuMonitorTestGetMonitor(test), + &info)) < 0) + goto cleanup; + + if (ninfo != 2) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "ninfo %d is not 2", ninfo); + goto cleanup; + } + +#define CHECK(i, wantname, wantthread_id) \ + do { \ + if (STRNEQ(info[i]->name, (wantname))) { \ + virReportError(VIR_ERR_INTERNAL_ERROR, \ + "name %s is not %s", \ + info[i]->name, (wantname)); \ + goto cleanup; \ + } \ + if (info[i]->thread_id != (wantthread_id)) { \ + virReportError(VIR_ERR_INTERNAL_ERROR, \ + "thread_id %d is not %d", \ + info[i]->thread_id, (wantthread_id)); \ + goto cleanup; \ + } \ + } while (0) + + CHECK(0, "iothread1", 30992); + CHECK(1, "iothread2", 30993); + +#undef CHECK + + ret = 0; + + cleanup: + qemuMonitorTestFree(test); + for (i = 0; i < ninfo; i++) + qemuMonitorIOThreadsInfoFree(info[i]); + VIR_FREE(info); + + return ret; +} + static int mymain(void) { @@ -2272,6 +2342,7 @@ mymain(void) DO_TEST(GetDeviceAliases); DO_TEST(CPU); DO_TEST(GetNonExistingCPUData); + DO_TEST(GetIOThreads); DO_TEST_SIMPLE("qmp_capabilities", qemuMonitorJSONSetCapabilities); DO_TEST_SIMPLE("system_powerdown", qemuMonitorJSONSystemPowerdown); DO_TEST_SIMPLE("system_reset", qemuMonitorJSONSystemReset);