[libvirt] [PATCH 2/5] qemu: Add monitor APIs for the detection of halted VCPUs

Viktor Mihajlovski mihajlov at linux.vnet.ibm.com
Thu Jul 14 14:35:39 UTC 2016


New monitor function qemuMonitorGetCPUState added to retrieve the
halted state of VCPUs via the query-cpus command.

Signed-off-by: Viktor Mihajlovski <mihajlov at linux.vnet.ibm.com>
Reviewed-by: Bjoern Walk <bwalk at linux.vnet.ibm.com>
Signed-off-by: Boris Fiuczynski <fiuczy at 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




More information about the libvir-list mailing list