On 08/03/2016 04:11 AM, Peter Krempa wrote:
Prepare to extract more data by returning a array of structs rather
than
just an array of thread ids. Additionally report fatal errors separately
from qemu not being able to produce data.
---
src/qemu/qemu_monitor.c | 31 ++++++++++++-------
src/qemu/qemu_monitor.h | 6 ++++
src/qemu/qemu_monitor_json.c | 71 ++++++++++++++++++++++----------------------
src/qemu/qemu_monitor_json.h | 2 +-
src/qemu/qemu_monitor_text.c | 37 +++++++++++------------
src/qemu/qemu_monitor_text.h | 2 +-
tests/qemumonitorjsontest.c | 31 ++++++++++++++-----
7 files changed, 104 insertions(+), 76 deletions(-)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 0011ceb..578b078 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1666,6 +1666,16 @@ qemuMonitorCPUInfoFree(qemuMonitorCPUInfoPtr cpus,
VIR_FREE(cpus);
}
+void
+qemuMonitorQueryCpusFree(struct qemuMonitorQueryCpusEntry *entries,
+ size_t nentries ATTRIBUTE_UNUSED)
+{
+ if (!entries)
+ return;
[1] Maybe this should be a 'int' parameter and a <= 0 check...
+
+ VIR_FREE(entries);
+}
+
/**
* qemuMonitorGetCPUInfo:
@@ -1686,10 +1696,10 @@ qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
size_t maxvcpus)
{
qemuMonitorCPUInfoPtr info = NULL;
- int *pids = NULL;
+ struct qemuMonitorQueryCpusEntry *cpuentries = NULL;
size_t i;
int ret = -1;
- int rc;
+ int ncpuentries;
QEMU_CHECK_MONITOR(mon);
@@ -1697,25 +1707,26 @@ qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
return -1;
if (mon->json)
- rc = qemuMonitorJSONQueryCPUs(mon, &pids);
+ ncpuentries = qemuMonitorJSONQueryCPUs(mon, &cpuentries);
else
- rc = qemuMonitorTextQueryCPUs(mon, &pids);
+ ncpuentries = qemuMonitorTextQueryCPUs(mon, &cpuentries);
+
+ if (ncpuentries < 0) {
+ if (ncpuentries == -2)
+ ret = 0;
Similar to previous patch w/r/t "ret = 0" and returning to caller
- if (rc < 0) {
- virResetLastError();
- ret = 0;
goto cleanup;
}
- for (i = 0; i < rc; i++)
- info[i].tid = pids[i];
+ for (i = 0; i < ncpuentries; i++)
+ info[i].tid = cpuentries[i].tid;
VIR_STEAL(*vcpus, info);
ret = 0;
cleanup:
qemuMonitorCPUInfoFree(info, maxvcpus);
- VIR_FREE(pids);
+ qemuMonitorQueryCpusFree(cpuentries, ncpuentries);
[1]Although not "currently" used, the ncpuentries is an int being passed
to a function that wants size_t
And yes, that's from a Coverity warning
return ret;
}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 1ef002a..6022b9d 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -390,6 +390,12 @@ int qemuMonitorGetStatus(qemuMonitorPtr mon,
int qemuMonitorSystemReset(qemuMonitorPtr mon);
int qemuMonitorSystemPowerdown(qemuMonitorPtr mon);
+struct qemuMonitorQueryCpusEntry {
+ pid_t tid;
+};
+void qemuMonitorQueryCpusFree(struct qemuMonitorQueryCpusEntry *entries,
+ size_t nentries);
+
struct _qemuMonitorCPUInfo {
pid_t tid;
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 715e1c7..8018860 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -1323,69 +1323,65 @@ int qemuMonitorJSONSystemReset(qemuMonitorPtr mon)
* { "CPU": 1, "current": false, "halted": true,
"pc": 7108165 } ]
*/
static int
-qemuMonitorJSONExtractCPUInfo(virJSONValuePtr reply,
- int **pids)
+qemuMonitorJSONExtractCPUInfo(virJSONValuePtr data,
+ struct qemuMonitorQueryCpusEntry **entries)
{
- virJSONValuePtr data;
+ struct qemuMonitorQueryCpusEntry *cpus = NULL;
int ret = -1;
size_t i;
- int *threads = NULL;
ssize_t ncpus;
- if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("cpu reply was missing return data"));
- goto cleanup;
- }
-
- if ((ncpus = virJSONValueArraySize(data)) <= 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("cpu information was empty"));
- goto cleanup;
- }
+ if ((ncpus = virJSONValueArraySize(data)) <= 0)
+ return -2;
- if (VIR_ALLOC_N(threads, ncpus) < 0)
+ if (VIR_ALLOC_N(cpus, ncpus) < 0)
goto cleanup;
for (i = 0; i < ncpus; i++) {
virJSONValuePtr entry = virJSONValueArrayGet(data, i);
- int thread;
+ int thread = 0;
if (!entry) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("cpu information was missing an array
element"));
+ ret = -2;
goto cleanup;
}
- if (virJSONValueObjectGetNumberInt(entry, "thread_id", &thread)
< 0) {
- /* Some older qemu versions don't report the thread_id,
- * so treat this as non-fatal, simply returning no data */
- ret = 0;
- goto cleanup;
- }
+ /* Some older qemu versions don't report the thread_id so treat this as
+ * non-fatal, simply returning no data */
+ ignore_value(virJSONValueObjectGetNumberInt(entry, "thread_id",
&thread));
So we're going to still make 'ncpus' calls to get the same answer...
Then we're going to return 5 elements with {0, 0, 0, 0, 0} and the
caller is going to do what? I think eventually we'll end up failing in
qemuDomainValidateVcpuInfo.
- threads[i] = thread;
+ cpus[i].tid = thread;
}
- *pids = threads;
- threads = NULL;
+ VIR_STEAL(*entries, cpus);
ret = ncpus;
cleanup:
- VIR_FREE(threads);
+ qemuMonitorQueryCpusFree(cpus, ncpus);
return ret;
}
+/**
+ * qemuMonitorJSONQueryCPUs:
+ *
+ * @mon: monitor object
+ * @entries: filled with detected entries on success
+ *
+ * Queries qemu for cpu-related information. Failure to execute the command or
+ * extract results does not produce an error as libvirt can continue without
+ * this information.
+ *
+ * Returns number of cpu data entries returned in @entries on success, -1 on a
+ * fatal error (oom ...) and -2 if the query failed gracefully.
+ */
int
qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon,
- int **pids)
+ struct qemuMonitorQueryCpusEntry **entries)
{
int ret = -1;
- virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-cpus",
- NULL);
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-cpus", NULL);
virJSONValuePtr reply = NULL;
-
- *pids = NULL;
+ virJSONValuePtr data;
if (!cmd)
return -1;
@@ -1393,10 +1389,13 @@ qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon,
if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
goto cleanup;
- if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+ if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
+ ret = -2;
goto cleanup;
+ }
+
+ ret = qemuMonitorJSONExtractCPUInfo(data, entries);
- ret = qemuMonitorJSONExtractCPUInfo(reply, pids);
cleanup:
virJSONValueFree(cmd);
virJSONValueFree(reply);
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 174f0ef..24b23d2 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -59,7 +59,7 @@ int qemuMonitorJSONSystemPowerdown(qemuMonitorPtr mon);
int qemuMonitorJSONSystemReset(qemuMonitorPtr mon);
int qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon,
- int **pids);
+ struct qemuMonitorQueryCpusEntry **entries);
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 ca04965..648c7db 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -502,12 +502,14 @@ int qemuMonitorTextSystemReset(qemuMonitorPtr mon)
int
qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
- int **pids)
+ struct qemuMonitorQueryCpusEntry **entries)
{
char *qemucpus = NULL;
char *line;
- pid_t *cpupids = NULL;
- size_t ncpupids = 0;
+ struct qemuMonitorQueryCpusEntry *cpus = NULL;
+ size_t ncpus;
Need to initialize to 0 (surprised neither compiler nor Coverity picked
up on it).
+ struct qemuMonitorQueryCpusEntry cpu = {0};
+ int ret = -2; /* -2 denotes a non-fatal error to get the data */
if (qemuMonitorHMPCommand(mon, "info cpus", &qemucpus) < 0)
return -1;
@@ -529,15 +531,17 @@ qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
/* 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;
+ cpu.tid = tid;
+
+ if (VIR_APPEND_ELEMENT_COPY(cpus, ncpus, cpu) < 0)
+ goto cleanup;
VIR_DEBUG("tid=%d", tid);
@@ -547,20 +551,13 @@ qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
line = strchr(offset, '\n');
} while (line != NULL);
- /* Validate we got data for all VCPUs we expected */
- VIR_FREE(qemucpus);
- *pids = cpupids;
- return ncpupids;
+ VIR_STEAL(*entries, cpus);
+ ret = ncpus;
- error:
+ cleanup:
+ qemuMonitorQueryCpusFree(cpus, ncpus);
VIR_FREE(qemucpus);
- VIR_FREE(cpupids);
-
- /* 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;
}
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index b7f0cab..f9e0f82 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -50,7 +50,7 @@ int qemuMonitorTextSystemPowerdown(qemuMonitorPtr mon);
int qemuMonitorTextSystemReset(qemuMonitorPtr mon);
int qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
- int **pids);
+ struct qemuMonitorQueryCpusEntry **entries);
int qemuMonitorTextGetVirtType(qemuMonitorPtr mon,
virDomainVirtType *virtType);
int qemuMonitorTextGetBalloonInfo(qemuMonitorPtr mon,
diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c
index 544b569..f848d80 100644
--- a/tests/qemumonitorjsontest.c
+++ b/tests/qemumonitorjsontest.c
Just a thought... should we have a test that returns "0" entries - does
it make sense?
I think this is close, but needs a few tweaks or explanation before ACK
John
@@ -1201,6 +1201,16 @@ GEN_TEST_FUNC(qemuMonitorJSONNBDServerStart,
"localhost", 12345)
GEN_TEST_FUNC(qemuMonitorJSONNBDServerAdd, "vda", true)
GEN_TEST_FUNC(qemuMonitorJSONDetachCharDev, "serial1")
+static bool
+testQemuMonitorJSONqemuMonitorJSONQueryCPUsEqual(struct qemuMonitorQueryCpusEntry *a,
+ struct qemuMonitorQueryCpusEntry *b)
+{
+ if (a->tid != b->tid)
+ return false;
+
+ return true;
+}
+
static int
testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
@@ -1208,9 +1218,14 @@ testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
qemuMonitorTestPtr test = qemuMonitorTestNewSimple(true, xmlopt);
int ret = -1;
- pid_t *cpupids = NULL;
- pid_t expected_cpupids[] = {17622, 17624, 17626, 17628};
- int ncpupids;
+ struct qemuMonitorQueryCpusEntry *cpudata = NULL;
+ struct qemuMonitorQueryCpusEntry expect[] = {
+ {17622},
+ {17624},
+ {17626},
+ {17628},
+ };
+ int ncpupids = 0;
size_t i;
if (!test)
@@ -1252,7 +1267,7 @@ testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
"}") < 0)
goto cleanup;
- ncpupids = qemuMonitorJSONQueryCPUs(qemuMonitorTestGetMonitor(test), &cpupids);
+ ncpupids = qemuMonitorJSONQueryCPUs(qemuMonitorTestGetMonitor(test), &cpudata);
if (ncpupids != 4) {
virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -1261,10 +1276,10 @@ testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
}
for (i = 0; i < ncpupids; i++) {
- if (cpupids[i] != expected_cpupids[i]) {
+ if (!testQemuMonitorJSONqemuMonitorJSONQueryCPUsEqual(cpudata + i,
+ expect + i)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
- "Expecting cpupids[%zu] = %d but got %d",
- i, expected_cpupids[i], cpupids[i]);
+ "vcpu entry %zu does not match expected data", i);
goto cleanup;
}
}
@@ -1272,7 +1287,7 @@ testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
ret = 0;
cleanup:
- VIR_FREE(cpupids);
+ qemuMonitorQueryCpusFree(cpudata, ncpupids);
qemuMonitorTestFree(test);
return ret;
}