New monitor function qemuMonitorGetCPUState added to retrieve the
halted state of VCPUs via the query-cpus command.
Signed-off-by: Viktor Mihajlovski <mihajlov(a)linux.vnet.ibm.com>
Reviewed-by: Bjoern Walk <bwalk(a)linux.vnet.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy(a)linux.vnet.ibm.com>
---
src/qemu/qemu_monitor.c | 22 ++++++++++++++++++
src/qemu/qemu_monitor.h | 2 ++
src/qemu/qemu_monitor_json.c | 52 ++++++++++++++++++++++++++++++++++++++----
src/qemu/qemu_monitor_json.h | 2 ++
src/qemu/qemu_monitor_text.c | 54 +++++++++++++++++++++++++++++++++++---------
src/qemu/qemu_monitor_text.h | 2 ++
6 files changed, 119 insertions(+), 15 deletions(-)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 098e654..0fdee29 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1667,6 +1667,28 @@ qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
}
+/**
+ * qemuMonitorGetCPUState:
+ * @mon: monitor
+ * @halted: returned array of boolean containing the vCPUs halted state
+ *
+ * Detects whether vCPUs are halted. Returns count of detected vCPUs on success,
+ * 0 if qemu didn't report vcpus (does not report libvirt error),
+ * -1 on error (reports libvirt error).
+ */
+int
+qemuMonitorGetCPUState(qemuMonitorPtr mon,
+ bool **halted)
+{
+ QEMU_CHECK_MONITOR(mon);
+
+ if (mon->json)
+ return qemuMonitorJSONGetCPUState(mon, halted);
+ else
+ return qemuMonitorTextGetCPUState(mon, halted);
+}
+
+
int
qemuMonitorSetLink(qemuMonitorPtr mon,
const char *name,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index cb4cca8..6bbb8a5 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -392,6 +392,8 @@ int qemuMonitorSystemPowerdown(qemuMonitorPtr mon);
int qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
int **pids);
+int qemuMonitorGetCPUState(qemuMonitorPtr mon,
+ bool **halted);
int qemuMonitorGetVirtType(qemuMonitorPtr mon,
virDomainVirtType *virtType);
int qemuMonitorGetBalloonInfo(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index bb426dc..878efaa 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -1324,13 +1324,15 @@ int qemuMonitorJSONSystemReset(qemuMonitorPtr mon)
*/
static int
qemuMonitorJSONExtractCPUInfo(virJSONValuePtr reply,
- int **pids)
+ int **pids,
+ bool **halted)
{
virJSONValuePtr data;
int ret = -1;
size_t i;
int *threads = NULL;
ssize_t ncpus;
+ bool *haltedcpus = NULL;
if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -1347,9 +1349,13 @@ qemuMonitorJSONExtractCPUInfo(virJSONValuePtr reply,
if (VIR_ALLOC_N(threads, ncpus) < 0)
goto cleanup;
+ if (VIR_ALLOC_N(haltedcpus, ncpus) < 0)
+ goto cleanup;
+
for (i = 0; i < ncpus; i++) {
virJSONValuePtr entry = virJSONValueArrayGet(data, i);
int thread;
+ bool ishalted;
if (!entry) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("cpu information was missing an array element"));
@@ -1363,15 +1369,31 @@ qemuMonitorJSONExtractCPUInfo(virJSONValuePtr reply,
goto cleanup;
}
+ if (virJSONValueObjectGetBoolean(entry, "halted", &ishalted) <
0) {
+ /* Some older qemu versions may not report the halted state,
+ * for backward compatibility we assume it's not halted */
+ ishalted = false;
+ }
+
threads[i] = thread;
+ haltedcpus[i] = ishalted;
}
- *pids = threads;
- threads = NULL;
+ if (pids) {
+ VIR_FREE(*pids);
+ *pids = threads;
+ threads = NULL;
+ }
+ if (halted) {
+ VIR_FREE(*halted);
+ *halted = haltedcpus;
+ haltedcpus = NULL;
+ }
ret = ncpus;
cleanup:
VIR_FREE(threads);
+ VIR_FREE(haltedcpus);
return ret;
}
@@ -1394,8 +1416,30 @@ int qemuMonitorJSONGetCPUInfo(qemuMonitorPtr mon,
if (qemuMonitorJSONCheckError(cmd, reply) < 0)
goto cleanup;
+ ret = qemuMonitorJSONExtractCPUInfo(reply, pids, NULL);
+ cleanup:
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+int qemuMonitorJSONGetCPUState(qemuMonitorPtr mon,
+ bool **halted)
+{
+ int ret = -1;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-cpus",
+ NULL);
+ virJSONValuePtr reply = NULL;
+
+ if (!cmd)
+ return -1;
+
+ if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+ goto cleanup;
- ret = qemuMonitorJSONExtractCPUInfo(reply, pids);
+ if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+ goto cleanup;
+ ret = qemuMonitorJSONExtractCPUInfo(reply, NULL, halted);
cleanup:
virJSONValueFree(cmd);
virJSONValueFree(reply);
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 37a739e..5469079 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -60,6 +60,8 @@ int qemuMonitorJSONSystemReset(qemuMonitorPtr mon);
int qemuMonitorJSONGetCPUInfo(qemuMonitorPtr mon,
int **pids);
+int qemuMonitorJSONGetCPUState(qemuMonitorPtr mon,
+ bool **halted);
int qemuMonitorJSONGetVirtType(qemuMonitorPtr mon,
virDomainVirtType *virtType);
int qemuMonitorJSONUpdateVideoMemorySize(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 9295219..bdbf1a3 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -500,13 +500,17 @@ int qemuMonitorTextSystemReset(qemuMonitorPtr mon)
}
-int qemuMonitorTextGetCPUInfo(qemuMonitorPtr mon,
- int **pids)
+static int qemuMonitorTextGetCPUInfoInternal(qemuMonitorPtr mon,
+ int **pids,
+ bool **halted)
{
char *qemucpus = NULL;
char *line;
pid_t *cpupids = NULL;
size_t ncpupids = 0;
+ bool *cpuhalted = NULL;
+ size_t ncpuhalted = 0;
+ int ret = 0;
if (qemuMonitorHMPCommand(mon, "info cpus", &qemucpus) < 0)
return -1;
@@ -517,7 +521,7 @@ int qemuMonitorTextGetCPUInfo(qemuMonitorPtr mon,
* (qemu) info cpus
* * CPU #0: pc=0x00000000000f0c4a thread_id=30019
* CPU #1: pc=0x00000000fffffff0 thread_id=30020
- * CPU #2: pc=0x00000000fffffff0 thread_id=30021
+ * CPU #2: pc=0x00000000fffffff0 (halted) thread_id=30021
*
*/
line = qemucpus;
@@ -525,18 +529,26 @@ int qemuMonitorTextGetCPUInfo(qemuMonitorPtr mon,
char *offset = NULL;
char *end = NULL;
int tid = 0;
+ bool ishalted = false;
/* Extract host Thread ID */
if ((offset = strstr(line, "thread_id=")) == NULL)
- goto error;
+ goto cleanup;
if (virStrToLong_i(offset + strlen("thread_id="), &end, 10,
&tid) < 0)
- goto error;
+ goto cleanup;
if (end == NULL || !c_isspace(*end))
- goto error;
+ goto cleanup;
if (VIR_APPEND_ELEMENT_COPY(cpupids, ncpupids, tid) < 0)
- goto error;
+ goto cleanup;
+
+ /* Extract halted indicator */
+ if ((offset = strstr(line, "(halted)")) != NULL)
+ ishalted = true;
+
+ if (VIR_APPEND_ELEMENT_COPY(cpuhalted, ncpuhalted, ishalted) < 0)
+ goto cleanup;
VIR_DEBUG("tid=%d", tid);
@@ -548,18 +560,38 @@ int qemuMonitorTextGetCPUInfo(qemuMonitorPtr mon,
/* Validate we got data for all VCPUs we expected */
VIR_FREE(qemucpus);
- *pids = cpupids;
- return ncpupids;
+ if (pids) {
+ VIR_FREE(*pids);
+ *pids = cpupids;
+ }
+ if (halted) {
+ VIR_FREE(*halted);
+ *halted = cpuhalted;
+ }
+ ret = ncpupids;
- error:
+ cleanup:
VIR_FREE(qemucpus);
VIR_FREE(cpupids);
+ VIR_FREE(cpuhalted);
/* Returning 0 to indicate non-fatal failure, since
* older QEMU does not have VCPU<->PID mapping and
* we don't want to fail on that
*/
- return 0;
+ return ret;
+}
+
+int qemuMonitorTextGetCPUInfo(qemuMonitorPtr mon,
+ int **pids)
+{
+ return qemuMonitorTextGetCPUInfoInternal(mon, pids, NULL);
+}
+
+int qemuMonitorTextGetCPUState(qemuMonitorPtr mon,
+ bool **halted)
+{
+ return qemuMonitorTextGetCPUInfoInternal(mon, NULL, halted);
}
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index eeaca52..7c185ff 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -51,6 +51,8 @@ int qemuMonitorTextSystemReset(qemuMonitorPtr mon);
int qemuMonitorTextGetCPUInfo(qemuMonitorPtr mon,
int **pids);
+int qemuMonitorTextGetCPUState(qemuMonitorPtr mon,
+ bool **halted);
int qemuMonitorTextGetVirtType(qemuMonitorPtr mon,
virDomainVirtType *virtType);
int qemuMonitorTextGetBalloonInfo(qemuMonitorPtr mon,
--
1.9.1