New monitor function qemuMonitorGetCPUState added to retrieve the halted state of VCPUs via the query-cpus command. Signed-off-by: Viktor Mihajlovski <mihajlov@xxxxxxxxxxxxxxxxxx> Reviewed-by: Bjoern Walk <bwalk@xxxxxxxxxxxxxxxxxx> Signed-off-by: Boris Fiuczynski <fiuczy@xxxxxxxxxxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list