[libvirt] [PATCH 0/6] Introduce virDomainGetControlInfo API

The API can be used to query current state of an interface to VMM used to control a domain. In QEMU world this translates into monitor connection and one can use the API, e.g., to check whether (and for how long) libvirtd is currently waiting for a reply from qemu process. Jiri Denemark (6): Introduce virTimeMs for getting current time in ms Use virTimeMs when appropriate Introduce virDomainGetControlInfo API Wire protocol and remote driver for virDomainGetControlInfo qemu: Implement virDomainGetControlInfo virsh: Add support for virDomainGetControlInfo daemon/remote_generator.pl | 20 +++++++--- include/libvirt/libvirt.h.in | 40 +++++++++++++++++++++ python/generator.py | 1 + python/libvirt-override-api.xml | 6 +++ src/driver.h | 5 +++ src/libvirt.c | 48 ++++++++++++++++++++++++++ src/libvirt_private.syms | 1 + src/libvirt_public.syms | 5 +++ src/qemu/qemu_domain.c | 28 ++++++--------- src/qemu/qemu_domain.h | 2 + src/qemu/qemu_driver.c | 72 ++++++++++++++++++++++++++++++++++----- src/qemu/qemu_migration.c | 31 +++++----------- src/qemu/qemu_process.c | 3 ++ src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 14 +++++++- src/remote_protocol-structs | 9 +++++ src/util/event_poll.c | 45 +++++++++--------------- src/util/util.c | 24 +++++++++++++ src/util/util.h | 2 + tools/virsh.c | 66 +++++++++++++++++++++++++++++++++++ tools/virsh.pod | 7 ++++ 21 files changed, 348 insertions(+), 82 deletions(-) -- 1.7.5.3

--- src/libvirt_private.syms | 1 + src/util/util.c | 24 ++++++++++++++++++++++++ src/util/util.h | 2 ++ 3 files changed, 27 insertions(+), 0 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index e6ab870..2415a89 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1027,6 +1027,7 @@ virStrToLong_ul; virStrToLong_ull; virStrcpy; virStrncpy; +virTimeMs; virTimestamp; virVasprintf; diff --git a/src/util/util.c b/src/util/util.c index e221abe..d758cf9 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -3117,6 +3117,30 @@ virTimestamp(void) return timestamp; } +#define timeval_to_ms(tv) (((tv).tv_sec * 1000ull) + ((tv).tv_usec / 1000)) + +/** + * virTimeMs: + * + * Get current time in milliseconds. + * + * Returns 0 on success, -1 on failure. + */ +int +virTimeMs(unsigned long long *ms) +{ + struct timeval now; + + if (gettimeofday(&now, NULL) < 0) { + virReportSystemError(errno, "%s", + _("cannot get time of day")); + return -1; + } + + *ms = timeval_to_ms(now); + return 0; +} + #if HAVE_LIBDEVMAPPER_H bool virIsDevMapperDevice(const char *devname) diff --git a/src/util/util.h b/src/util/util.h index a1bcca0..273248a 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -286,6 +286,8 @@ int virBuildPathInternal(char **path, ...) ATTRIBUTE_SENTINEL; char *virTimestamp(void); +int virTimeMs(unsigned long long *ms); + bool virIsDevMapperDevice(const char *devname) ATTRIBUTE_NONNULL(1); int virEmitXMLWarning(int fd, -- 1.7.5.3

--- src/libvirt_private.syms | 1 + src/util/util.c | 24 ++++++++++++++++++++++++ src/util/util.h | 2 ++ 3 files changed, 27 insertions(+), 0 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index e6ab870..2415a89 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1027,6 +1027,7 @@ virStrToLong_ul; virStrToLong_ull; virStrcpy; virStrncpy; +virTimeMs; virTimestamp; virVasprintf;
diff --git a/src/util/util.c b/src/util/util.c index e221abe..d758cf9 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -3117,6 +3117,30 @@ virTimestamp(void) return timestamp; }
+#define timeval_to_ms(tv) (((tv).tv_sec * 1000ull) + ((tv).tv_usec / 1000)) What about making this in util.h so we can have only one definition and
On 07.06.2011 15:01, Jiri Denemark wrote: then cleanup src/qemu/qemu_domain.c:48, src/qemu/qemu_driver.c:116, src/qemu/qemu_migration.c:49?
+ +/** + * virTimeMs: + * + * Get current time in milliseconds. + * + * Returns 0 on success, -1 on failure. + */ +int +virTimeMs(unsigned long long *ms) +{ + struct timeval now; + + if (gettimeofday(&now, NULL) < 0) { + virReportSystemError(errno, "%s", + _("cannot get time of day")); + return -1; + } + + *ms = timeval_to_ms(now); + return 0; +} + #if HAVE_LIBDEVMAPPER_H bool virIsDevMapperDevice(const char *devname) diff --git a/src/util/util.h b/src/util/util.h index a1bcca0..273248a 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -286,6 +286,8 @@ int virBuildPathInternal(char **path, ...) ATTRIBUTE_SENTINEL;
char *virTimestamp(void);
+int virTimeMs(unsigned long long *ms); I'd add ATTRIBUTE_NONNULL(1); here. + bool virIsDevMapperDevice(const char *devname) ATTRIBUTE_NONNULL(1);
int virEmitXMLWarning(int fd,
Otherwise looking good. ACK Michal

On Thu, Jun 09, 2011 at 16:06:48 +0200, Michal Privoznik wrote:
--- src/libvirt_private.syms | 1 + src/util/util.c | 24 ++++++++++++++++++++++++ src/util/util.h | 2 ++ 3 files changed, 27 insertions(+), 0 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index e6ab870..2415a89 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1027,6 +1027,7 @@ virStrToLong_ul; virStrToLong_ull; virStrcpy; virStrncpy; +virTimeMs; virTimestamp; virVasprintf;
diff --git a/src/util/util.c b/src/util/util.c index e221abe..d758cf9 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -3117,6 +3117,30 @@ virTimestamp(void) return timestamp; }
+#define timeval_to_ms(tv) (((tv).tv_sec * 1000ull) + ((tv).tv_usec / 1000)) What about making this in util.h so we can have only one definition and
On 07.06.2011 15:01, Jiri Denemark wrote: then cleanup src/qemu/qemu_domain.c:48, src/qemu/qemu_driver.c:116, src/qemu/qemu_migration.c:49?
Nope, one of the reasons for virTimeMs is to get rid of timeval_to_ms usage in those files (which is done by patch 2/6).
--- a/src/util/util.h +++ b/src/util/util.h @@ -286,6 +286,8 @@ int virBuildPathInternal(char **path, ...) ATTRIBUTE_SENTINEL;
char *virTimestamp(void);
+int virTimeMs(unsigned long long *ms); I'd add ATTRIBUTE_NONNULL(1); here.
Added and pushed, thanks. Jirka

On 13.06.2011 11:31, Jiri Denemark wrote:
On Thu, Jun 09, 2011 at 16:06:48 +0200, Michal Privoznik wrote:
--- src/libvirt_private.syms | 1 + src/util/util.c | 24 ++++++++++++++++++++++++ src/util/util.h | 2 ++ 3 files changed, 27 insertions(+), 0 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index e6ab870..2415a89 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1027,6 +1027,7 @@ virStrToLong_ul; virStrToLong_ull; virStrcpy; virStrncpy; +virTimeMs; virTimestamp; virVasprintf;
diff --git a/src/util/util.c b/src/util/util.c index e221abe..d758cf9 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -3117,6 +3117,30 @@ virTimestamp(void) return timestamp; }
+#define timeval_to_ms(tv) (((tv).tv_sec * 1000ull) + ((tv).tv_usec / 1000)) What about making this in util.h so we can have only one definition and
On 07.06.2011 15:01, Jiri Denemark wrote: then cleanup src/qemu/qemu_domain.c:48, src/qemu/qemu_driver.c:116, src/qemu/qemu_migration.c:49?
Nope, one of the reasons for virTimeMs is to get rid of timeval_to_ms usage in those files (which is done by patch 2/6).
Yeah, I realized when I replied to this and opened 2/6.
--- a/src/util/util.h +++ b/src/util/util.h @@ -286,6 +286,8 @@ int virBuildPathInternal(char **path, ...) ATTRIBUTE_SENTINEL;
char *virTimestamp(void);
+int virTimeMs(unsigned long long *ms); I'd add ATTRIBUTE_NONNULL(1); here.
Added and pushed, thanks.
Jirka

--- src/qemu/qemu_domain.c | 24 ++++++++---------------- src/qemu/qemu_driver.c | 11 ++--------- src/qemu/qemu_migration.c | 31 ++++++++++--------------------- src/util/event_poll.c | 45 ++++++++++++++++----------------------------- 4 files changed, 36 insertions(+), 75 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 332c09e..5f18ad3 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -45,8 +45,6 @@ #define QEMU_NAMESPACE_HREF "http://libvirt.org/schemas/domain/qemu/1.0" -#define timeval_to_ms(tv) (((tv).tv_sec * 1000ull) + ((tv).tv_usec / 1000)) - static void qemuDomainEventDispatchFunc(virConnectPtr conn, virDomainEventPtr event, @@ -492,15 +490,12 @@ void qemuDomainSetNamespaceHooks(virCapsPtr caps) int qemuDomainObjBeginJob(virDomainObjPtr obj) { qemuDomainObjPrivatePtr priv = obj->privateData; - struct timeval now; + unsigned long long now; unsigned long long then; - if (gettimeofday(&now, NULL) < 0) { - virReportSystemError(errno, "%s", - _("cannot get time of day")); + if (virTimeMs(&now) < 0) return -1; - } - then = timeval_to_ms(now) + QEMU_JOB_WAIT_TIME; + then = now + QEMU_JOB_WAIT_TIME; virDomainObjRef(obj); @@ -520,7 +515,7 @@ int qemuDomainObjBeginJob(virDomainObjPtr obj) priv->jobActive = QEMU_JOB_UNSPECIFIED; priv->jobSignals = 0; memset(&priv->jobSignalsData, 0, sizeof(priv->jobSignalsData)); - priv->jobStart = timeval_to_ms(now); + priv->jobStart = now; memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); return 0; @@ -536,15 +531,12 @@ int qemuDomainObjBeginJobWithDriver(struct qemud_driver *driver, virDomainObjPtr obj) { qemuDomainObjPrivatePtr priv = obj->privateData; - struct timeval now; + unsigned long long now; unsigned long long then; - if (gettimeofday(&now, NULL) < 0) { - virReportSystemError(errno, "%s", - _("cannot get time of day")); + if (virTimeMs(&now) < 0) return -1; - } - then = timeval_to_ms(now) + QEMU_JOB_WAIT_TIME; + then = now + QEMU_JOB_WAIT_TIME; virDomainObjRef(obj); qemuDriverUnlock(driver); @@ -568,7 +560,7 @@ int qemuDomainObjBeginJobWithDriver(struct qemud_driver *driver, priv->jobActive = QEMU_JOB_UNSPECIFIED; priv->jobSignals = 0; memset(&priv->jobSignalsData, 0, sizeof(priv->jobSignalsData)); - priv->jobStart = timeval_to_ms(now); + priv->jobStart = now; memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); virDomainObjUnlock(obj); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 2957467..470573e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -113,8 +113,6 @@ #define QEMU_NB_BLKIO_PARAM 1 -#define timeval_to_ms(tv) (((tv).tv_sec * 1000ull) + ((tv).tv_usec / 1000)) - static void processWatchdogEvent(void *data, void *opaque); static int qemudShutdown(void); @@ -6843,8 +6841,6 @@ static int qemuDomainGetJobInfo(virDomainPtr dom, if (virDomainObjIsActive(vm)) { if (priv->jobActive) { - struct timeval now; - memcpy(info, &priv->jobInfo, sizeof(*info)); /* Refresh elapsed time again just to ensure it @@ -6852,12 +6848,9 @@ static int qemuDomainGetJobInfo(virDomainPtr dom, * of incoming migration which we don't currently * monitor actively in the background thread */ - if (gettimeofday(&now, NULL) < 0) { - virReportSystemError(errno, "%s", - _("cannot get time of day")); + if (virTimeMs(&info->timeElapsed) < 0) goto cleanup; - } - info->timeElapsed = timeval_to_ms(now) - priv->jobStart; + info->timeElapsed -= priv->jobStart; } else { memset(info, 0, sizeof(*info)); info->type = VIR_DOMAIN_JOB_NONE; diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index f7eaa1c..5d7494b 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -46,8 +46,6 @@ #define VIR_FROM_THIS VIR_FROM_QEMU -#define timeval_to_ms(tv) (((tv).tv_sec * 1000ull) + ((tv).tv_usec / 1000)) - enum qemuMigrationCookieFlags { QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS, QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE, @@ -831,7 +829,6 @@ qemuMigrationUpdateJobStatus(struct qemud_driver *driver, unsigned long long memProcessed; unsigned long long memRemaining; unsigned long long memTotal; - struct timeval now; if (!virDomainObjIsActive(vm)) { qemuReportError(VIR_ERR_INTERNAL_ERROR, _("%s: %s"), @@ -852,13 +849,9 @@ qemuMigrationUpdateJobStatus(struct qemud_driver *driver, return -1; } - if (gettimeofday(&now, NULL) < 0) { - priv->jobInfo.type = VIR_DOMAIN_JOB_FAILED; - virReportSystemError(errno, "%s", - _("cannot get time of day")); + if (virTimeMs(&priv->jobInfo.timeElapsed) < 0) return -1; - } - priv->jobInfo.timeElapsed = timeval_to_ms(now) - priv->jobStart; + priv->jobInfo.timeElapsed -= priv->jobStart; switch (status) { case QEMU_MONITOR_MIGRATION_STATUS_INACTIVE: @@ -1069,18 +1062,16 @@ qemuMigrationPrepareTunnel(struct qemud_driver *driver, int internalret; int dataFD[2] = { -1, -1 }; qemuDomainObjPrivatePtr priv = NULL; - struct timeval now; + unsigned long long now; qemuMigrationCookiePtr mig = NULL; + VIR_DEBUG("driver=%p, dconn=%p, cookiein=%s, cookieinlen=%d, " "cookieout=%p, cookieoutlen=%p, st=%p, dname=%s, dom_xml=%s", driver, dconn, NULLSTR(cookiein), cookieinlen, cookieout, cookieoutlen, st, NULLSTR(dname), dom_xml); - if (gettimeofday(&now, NULL) < 0) { - virReportSystemError(errno, "%s", - _("cannot get time of day")); + if (virTimeMs(&now) < 0) return -1; - } /* Parse the domain XML. */ if (!(def = virDomainDefParseString(driver->caps, dom_xml, @@ -1190,7 +1181,7 @@ endjob: virDomainObjIsActive(vm)) { priv->jobActive = QEMU_JOB_MIGRATION_IN; priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED; - priv->jobStart = timeval_to_ms(now); + priv->jobStart = now; } cleanup: @@ -1229,8 +1220,9 @@ qemuMigrationPrepareDirect(struct qemud_driver *driver, int ret = -1; int internalret; qemuDomainObjPrivatePtr priv = NULL; - struct timeval now; + unsigned long long now; qemuMigrationCookiePtr mig = NULL; + VIR_DEBUG("driver=%p, dconn=%p, cookiein=%s, cookieinlen=%d, " "cookieout=%p, cookieoutlen=%p, uri_in=%s, uri_out=%p, " "dname=%s, dom_xml=%s", @@ -1238,11 +1230,8 @@ qemuMigrationPrepareDirect(struct qemud_driver *driver, cookieout, cookieoutlen, NULLSTR(uri_in), uri_out, NULLSTR(dname), dom_xml); - if (gettimeofday(&now, NULL) < 0) { - virReportSystemError(errno, "%s", - _("cannot get time of day")); + if (virTimeMs(&now) < 0) return -1; - } /* The URI passed in may be NULL or a string "tcp://somehostname:port". * @@ -1413,7 +1402,7 @@ endjob: virDomainObjIsActive(vm)) { priv->jobActive = QEMU_JOB_MIGRATION_IN; priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED; - priv->jobStart = timeval_to_ms(now); + priv->jobStart = now; } cleanup: diff --git a/src/util/event_poll.c b/src/util/event_poll.c index df2b28c..285ba50 100644 --- a/src/util/event_poll.c +++ b/src/util/event_poll.c @@ -201,11 +201,12 @@ int virEventPollRemoveHandle(int watch) { int virEventPollAddTimeout(int frequency, virEventTimeoutCallback cb, void *opaque, - virFreeCallback ff) { - struct timeval now; + virFreeCallback ff) +{ + unsigned long long now; int ret; EVENT_DEBUG("Adding timer %d with %d ms freq", nextTimer, frequency); - if (gettimeofday(&now, NULL) < 0) { + if (virTimeMs(&now) < 0) { return -1; } @@ -227,9 +228,7 @@ int virEventPollAddTimeout(int frequency, eventLoop.timeouts[eventLoop.timeoutsCount].opaque = opaque; eventLoop.timeouts[eventLoop.timeoutsCount].deleted = 0; eventLoop.timeouts[eventLoop.timeoutsCount].expiresAt = - frequency >= 0 ? frequency + - (((unsigned long long)now.tv_sec)*1000) + - (((unsigned long long)now.tv_usec)/1000) : 0; + frequency >= 0 ? frequency + now : 0; eventLoop.timeoutsCount++; ret = nextTimer-1; @@ -238,8 +237,9 @@ int virEventPollAddTimeout(int frequency, return ret; } -void virEventPollUpdateTimeout(int timer, int frequency) { - struct timeval tv; +void virEventPollUpdateTimeout(int timer, int frequency) +{ + unsigned long long now; int i; EVENT_DEBUG("Updating timer %d timeout with %d ms freq", timer, frequency); @@ -248,7 +248,7 @@ void virEventPollUpdateTimeout(int timer, int frequency) { return; } - if (gettimeofday(&tv, NULL) < 0) { + if (virTimeMs(&now) < 0) { return; } @@ -257,9 +257,7 @@ void virEventPollUpdateTimeout(int timer, int frequency) { if (eventLoop.timeouts[i].timer == timer) { eventLoop.timeouts[i].frequency = frequency; eventLoop.timeouts[i].expiresAt = - frequency >= 0 ? frequency + - (((unsigned long long)tv.tv_sec)*1000) + - (((unsigned long long)tv.tv_usec)/1000) : 0; + frequency >= 0 ? frequency + now : 0; virEventPollInterruptLocked(); break; } @@ -321,18 +319,12 @@ static int virEventPollCalculateTimeout(int *timeout) { /* Calculate how long we should wait for a timeout if needed */ if (then > 0) { - struct timeval tv; + unsigned long long now; - if (gettimeofday(&tv, NULL) < 0) { - virReportSystemError(errno, "%s", - _("Unable to get current time")); + if (virTimeMs(&now) < 0) return -1; - } - - *timeout = then - - ((((unsigned long long)tv.tv_sec)*1000) + - (((unsigned long long)tv.tv_usec)/1000)); + *timeout = then - now; if (*timeout < 0) *timeout = 0; } else { @@ -397,21 +389,16 @@ static struct pollfd *virEventPollMakePollFDs(int *nfds) { * * Returns 0 upon success, -1 if an error occurred */ -static int virEventPollDispatchTimeouts(void) { - struct timeval tv; +static int virEventPollDispatchTimeouts(void) +{ unsigned long long now; int i; /* Save this now - it may be changed during dispatch */ int ntimeouts = eventLoop.timeoutsCount; VIR_DEBUG("Dispatch %d", ntimeouts); - if (gettimeofday(&tv, NULL) < 0) { - virReportSystemError(errno, "%s", - _("Unable to get current time")); + if (virTimeMs(&now) < 0) return -1; - } - now = (((unsigned long long)tv.tv_sec)*1000) + - (((unsigned long long)tv.tv_usec)/1000); for (i = 0 ; i < ntimeouts ; i++) { if (eventLoop.timeouts[i].deleted || eventLoop.timeouts[i].frequency < 0) -- 1.7.5.3

On Tue, Jun 07, 2011 at 03:01:56PM +0200, Jiri Denemark wrote:
--- src/qemu/qemu_domain.c | 24 ++++++++---------------- src/qemu/qemu_driver.c | 11 ++--------- src/qemu/qemu_migration.c | 31 ++++++++++--------------------- src/util/event_poll.c | 45 ++++++++++++++++----------------------------- 4 files changed, 36 insertions(+), 75 deletions(-)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 332c09e..5f18ad3 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -45,8 +45,6 @@
#define QEMU_NAMESPACE_HREF "http://libvirt.org/schemas/domain/qemu/1.0"
-#define timeval_to_ms(tv) (((tv).tv_sec * 1000ull) + ((tv).tv_usec / 1000)) -
static void qemuDomainEventDispatchFunc(virConnectPtr conn, virDomainEventPtr event, @@ -492,15 +490,12 @@ void qemuDomainSetNamespaceHooks(virCapsPtr caps) int qemuDomainObjBeginJob(virDomainObjPtr obj) { qemuDomainObjPrivatePtr priv = obj->privateData; - struct timeval now; + unsigned long long now; unsigned long long then;
- if (gettimeofday(&now, NULL) < 0) { - virReportSystemError(errno, "%s", - _("cannot get time of day")); + if (virTimeMs(&now) < 0) return -1; - } - then = timeval_to_ms(now) + QEMU_JOB_WAIT_TIME; + then = now + QEMU_JOB_WAIT_TIME;
virDomainObjRef(obj);
@@ -520,7 +515,7 @@ int qemuDomainObjBeginJob(virDomainObjPtr obj) priv->jobActive = QEMU_JOB_UNSPECIFIED; priv->jobSignals = 0; memset(&priv->jobSignalsData, 0, sizeof(priv->jobSignalsData)); - priv->jobStart = timeval_to_ms(now); + priv->jobStart = now; memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
return 0; @@ -536,15 +531,12 @@ int qemuDomainObjBeginJobWithDriver(struct qemud_driver *driver, virDomainObjPtr obj) { qemuDomainObjPrivatePtr priv = obj->privateData; - struct timeval now; + unsigned long long now; unsigned long long then;
- if (gettimeofday(&now, NULL) < 0) { - virReportSystemError(errno, "%s", - _("cannot get time of day")); + if (virTimeMs(&now) < 0) return -1; - } - then = timeval_to_ms(now) + QEMU_JOB_WAIT_TIME; + then = now + QEMU_JOB_WAIT_TIME;
virDomainObjRef(obj); qemuDriverUnlock(driver); @@ -568,7 +560,7 @@ int qemuDomainObjBeginJobWithDriver(struct qemud_driver *driver, priv->jobActive = QEMU_JOB_UNSPECIFIED; priv->jobSignals = 0; memset(&priv->jobSignalsData, 0, sizeof(priv->jobSignalsData)); - priv->jobStart = timeval_to_ms(now); + priv->jobStart = now; memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
virDomainObjUnlock(obj); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 2957467..470573e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -113,8 +113,6 @@
#define QEMU_NB_BLKIO_PARAM 1
-#define timeval_to_ms(tv) (((tv).tv_sec * 1000ull) + ((tv).tv_usec / 1000)) - static void processWatchdogEvent(void *data, void *opaque);
static int qemudShutdown(void); @@ -6843,8 +6841,6 @@ static int qemuDomainGetJobInfo(virDomainPtr dom,
if (virDomainObjIsActive(vm)) { if (priv->jobActive) { - struct timeval now; - memcpy(info, &priv->jobInfo, sizeof(*info));
/* Refresh elapsed time again just to ensure it @@ -6852,12 +6848,9 @@ static int qemuDomainGetJobInfo(virDomainPtr dom, * of incoming migration which we don't currently * monitor actively in the background thread */ - if (gettimeofday(&now, NULL) < 0) { - virReportSystemError(errno, "%s", - _("cannot get time of day")); + if (virTimeMs(&info->timeElapsed) < 0) goto cleanup; - } - info->timeElapsed = timeval_to_ms(now) - priv->jobStart; + info->timeElapsed -= priv->jobStart; } else { memset(info, 0, sizeof(*info)); info->type = VIR_DOMAIN_JOB_NONE; diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index f7eaa1c..5d7494b 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -46,8 +46,6 @@
#define VIR_FROM_THIS VIR_FROM_QEMU
-#define timeval_to_ms(tv) (((tv).tv_sec * 1000ull) + ((tv).tv_usec / 1000)) - enum qemuMigrationCookieFlags { QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS, QEMU_MIGRATION_COOKIE_FLAG_LOCKSTATE, @@ -831,7 +829,6 @@ qemuMigrationUpdateJobStatus(struct qemud_driver *driver, unsigned long long memProcessed; unsigned long long memRemaining; unsigned long long memTotal; - struct timeval now;
if (!virDomainObjIsActive(vm)) { qemuReportError(VIR_ERR_INTERNAL_ERROR, _("%s: %s"), @@ -852,13 +849,9 @@ qemuMigrationUpdateJobStatus(struct qemud_driver *driver, return -1; }
- if (gettimeofday(&now, NULL) < 0) { - priv->jobInfo.type = VIR_DOMAIN_JOB_FAILED; - virReportSystemError(errno, "%s", - _("cannot get time of day")); + if (virTimeMs(&priv->jobInfo.timeElapsed) < 0) return -1; - } - priv->jobInfo.timeElapsed = timeval_to_ms(now) - priv->jobStart; + priv->jobInfo.timeElapsed -= priv->jobStart;
switch (status) { case QEMU_MONITOR_MIGRATION_STATUS_INACTIVE: @@ -1069,18 +1062,16 @@ qemuMigrationPrepareTunnel(struct qemud_driver *driver, int internalret; int dataFD[2] = { -1, -1 }; qemuDomainObjPrivatePtr priv = NULL; - struct timeval now; + unsigned long long now; qemuMigrationCookiePtr mig = NULL; + VIR_DEBUG("driver=%p, dconn=%p, cookiein=%s, cookieinlen=%d, " "cookieout=%p, cookieoutlen=%p, st=%p, dname=%s, dom_xml=%s", driver, dconn, NULLSTR(cookiein), cookieinlen, cookieout, cookieoutlen, st, NULLSTR(dname), dom_xml);
- if (gettimeofday(&now, NULL) < 0) { - virReportSystemError(errno, "%s", - _("cannot get time of day")); + if (virTimeMs(&now) < 0) return -1; - }
/* Parse the domain XML. */ if (!(def = virDomainDefParseString(driver->caps, dom_xml, @@ -1190,7 +1181,7 @@ endjob: virDomainObjIsActive(vm)) { priv->jobActive = QEMU_JOB_MIGRATION_IN; priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED; - priv->jobStart = timeval_to_ms(now); + priv->jobStart = now; }
cleanup: @@ -1229,8 +1220,9 @@ qemuMigrationPrepareDirect(struct qemud_driver *driver, int ret = -1; int internalret; qemuDomainObjPrivatePtr priv = NULL; - struct timeval now; + unsigned long long now; qemuMigrationCookiePtr mig = NULL; + VIR_DEBUG("driver=%p, dconn=%p, cookiein=%s, cookieinlen=%d, " "cookieout=%p, cookieoutlen=%p, uri_in=%s, uri_out=%p, " "dname=%s, dom_xml=%s", @@ -1238,11 +1230,8 @@ qemuMigrationPrepareDirect(struct qemud_driver *driver, cookieout, cookieoutlen, NULLSTR(uri_in), uri_out, NULLSTR(dname), dom_xml);
- if (gettimeofday(&now, NULL) < 0) { - virReportSystemError(errno, "%s", - _("cannot get time of day")); + if (virTimeMs(&now) < 0) return -1; - }
/* The URI passed in may be NULL or a string "tcp://somehostname:port". * @@ -1413,7 +1402,7 @@ endjob: virDomainObjIsActive(vm)) { priv->jobActive = QEMU_JOB_MIGRATION_IN; priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED; - priv->jobStart = timeval_to_ms(now); + priv->jobStart = now; }
cleanup: diff --git a/src/util/event_poll.c b/src/util/event_poll.c index df2b28c..285ba50 100644 --- a/src/util/event_poll.c +++ b/src/util/event_poll.c @@ -201,11 +201,12 @@ int virEventPollRemoveHandle(int watch) { int virEventPollAddTimeout(int frequency, virEventTimeoutCallback cb, void *opaque, - virFreeCallback ff) { - struct timeval now; + virFreeCallback ff) +{ + unsigned long long now; int ret; EVENT_DEBUG("Adding timer %d with %d ms freq", nextTimer, frequency); - if (gettimeofday(&now, NULL) < 0) { + if (virTimeMs(&now) < 0) { return -1; }
@@ -227,9 +228,7 @@ int virEventPollAddTimeout(int frequency, eventLoop.timeouts[eventLoop.timeoutsCount].opaque = opaque; eventLoop.timeouts[eventLoop.timeoutsCount].deleted = 0; eventLoop.timeouts[eventLoop.timeoutsCount].expiresAt = - frequency >= 0 ? frequency + - (((unsigned long long)now.tv_sec)*1000) + - (((unsigned long long)now.tv_usec)/1000) : 0; + frequency >= 0 ? frequency + now : 0;
eventLoop.timeoutsCount++; ret = nextTimer-1; @@ -238,8 +237,9 @@ int virEventPollAddTimeout(int frequency, return ret; }
-void virEventPollUpdateTimeout(int timer, int frequency) { - struct timeval tv; +void virEventPollUpdateTimeout(int timer, int frequency) +{ + unsigned long long now; int i; EVENT_DEBUG("Updating timer %d timeout with %d ms freq", timer, frequency);
@@ -248,7 +248,7 @@ void virEventPollUpdateTimeout(int timer, int frequency) { return; }
- if (gettimeofday(&tv, NULL) < 0) { + if (virTimeMs(&now) < 0) { return; }
@@ -257,9 +257,7 @@ void virEventPollUpdateTimeout(int timer, int frequency) { if (eventLoop.timeouts[i].timer == timer) { eventLoop.timeouts[i].frequency = frequency; eventLoop.timeouts[i].expiresAt = - frequency >= 0 ? frequency + - (((unsigned long long)tv.tv_sec)*1000) + - (((unsigned long long)tv.tv_usec)/1000) : 0; + frequency >= 0 ? frequency + now : 0; virEventPollInterruptLocked(); break; } @@ -321,18 +319,12 @@ static int virEventPollCalculateTimeout(int *timeout) {
/* Calculate how long we should wait for a timeout if needed */ if (then > 0) { - struct timeval tv; + unsigned long long now;
- if (gettimeofday(&tv, NULL) < 0) { - virReportSystemError(errno, "%s", - _("Unable to get current time")); + if (virTimeMs(&now) < 0) return -1; - } - - *timeout = then - - ((((unsigned long long)tv.tv_sec)*1000) + - (((unsigned long long)tv.tv_usec)/1000));
+ *timeout = then - now; if (*timeout < 0) *timeout = 0; } else { @@ -397,21 +389,16 @@ static struct pollfd *virEventPollMakePollFDs(int *nfds) { * * Returns 0 upon success, -1 if an error occurred */ -static int virEventPollDispatchTimeouts(void) { - struct timeval tv; +static int virEventPollDispatchTimeouts(void) +{ unsigned long long now; int i; /* Save this now - it may be changed during dispatch */ int ntimeouts = eventLoop.timeoutsCount; VIR_DEBUG("Dispatch %d", ntimeouts);
- if (gettimeofday(&tv, NULL) < 0) { - virReportSystemError(errno, "%s", - _("Unable to get current time")); + if (virTimeMs(&now) < 0) return -1; - } - now = (((unsigned long long)tv.tv_sec)*1000) + - (((unsigned long long)tv.tv_usec)/1000);
for (i = 0 ; i < ntimeouts ; i++) { if (eventLoop.timeouts[i].deleted || eventLoop.timeouts[i].frequency < 0)
ACK, this cleans things up on top of previous patch and looks correct Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Mon, Jun 13, 2011 at 16:15:39 +0800, Daniel Veillard wrote:
On Tue, Jun 07, 2011 at 03:01:56PM +0200, Jiri Denemark wrote: ...
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index f7eaa1c..5d7494b 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -852,13 +849,9 @@ qemuMigrationUpdateJobStatus(struct qemud_driver *driver, return -1; }
- if (gettimeofday(&now, NULL) < 0) { - priv->jobInfo.type = VIR_DOMAIN_JOB_FAILED; - virReportSystemError(errno, "%s", - _("cannot get time of day")); + if (virTimeMs(&priv->jobInfo.timeElapsed) < 0) return -1; - } - priv->jobInfo.timeElapsed = timeval_to_ms(now) - priv->jobStart; + priv->jobInfo.timeElapsed -= priv->jobStart;
switch (status) { case QEMU_MONITOR_MIGRATION_STATUS_INACTIVE:
Actually this chunk was wrong since it didn't set priv->jobInfo.type = VIR_DOMAIN_JOB_FAILED if virTimeMs failed. So I fixed it
ACK, this cleans things up on top of previous patch and looks correct
and pushed. Thanks, Jirka

The API can be used to query current state of an interface to VMM used to control a domain. In QEMU world this translates into monitor connection. --- include/libvirt/libvirt.h.in | 40 ++++++++++++++++++++++++++++++++ python/generator.py | 1 + python/libvirt-override-api.xml | 6 +++++ src/driver.h | 5 ++++ src/libvirt.c | 48 +++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 ++++ 6 files changed, 105 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index df213f1..1454ca0 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -141,6 +141,43 @@ typedef enum { VIR_DOMAIN_CRASHED_UNKNOWN = 0, /* crashed for unknown reason */ } virDomainCrashedReason; + +/** + * virDomainControlState: + * + * Current state of a control interface to the domain. + */ +typedef enum { + VIR_DOMAIN_CONTROL_OK = 0, /* operational, ready to accept commands */ + VIR_DOMAIN_CONTROL_JOB = 1, /* background job is running (can be + monitored by virDomainGetJobInfo); only + limited set of commands may be allowed */ + VIR_DOMAIN_CONTROL_OCCUPIED = 2, /* occupied by a running command */ + VIR_DOMAIN_CONTROL_ERROR = 3, /* unusable, domain cannot be fully operated */ +} virDomainControlState; + +/** + * virDomainControlInfo: + * + * Structure filled in by virDomainGetControlInfo and providing details about + * current state of control interface to a domain. + */ +typedef struct _virDomainControlInfo virDomainControlInfo; +struct _virDomainControlInfo { + unsigned int state; /* control state, one of virDomainControlState */ + unsigned int details; /* state details, currently 0 */ + unsigned long long stateTime; /* for how long (in msec) control interface + has been in current state (except for OK + and ERROR states) */ +}; + +/** + * virDomainControlInfoPtr: + * + * Pointer to virDomainControlInfo structure. + */ +typedef virDomainControlInfo *virDomainControlInfoPtr; + /** * virDomainModificationImpact: * @@ -781,6 +818,9 @@ int virDomainGetState (virDomainPtr domain, int *state, int *reason, unsigned int flags); +int virDomainGetControlInfo (virDomainPtr domain, + virDomainControlInfoPtr info, + unsigned int flags); /* * Return scheduler type in effect 'sedf', 'credit', 'linux' diff --git a/python/generator.py b/python/generator.py index 7c38fdd..4e3e9fa 100755 --- a/python/generator.py +++ b/python/generator.py @@ -306,6 +306,7 @@ skip_impl = ( 'virGetLastError', 'virDomainGetInfo', 'virDomainGetState', + 'virDomainGetControlInfo', 'virDomainGetBlockInfo', 'virDomainGetJobInfo', 'virNodeGetInfo', diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index ec08e69..01207d6 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -54,6 +54,12 @@ <arg name='domain' type='virDomainPtr' info='a domain object'/> <arg name='flags' type='unsigned int' info='additional flags'/> </function> + <function name='virDomainGetControlInfo' file='python'> + <info>Extract details about current state of control interface to a domain.</info> + <return type='int *' info='the list of information or None in case of error'/> + <arg name='domain' type='virDomainPtr' info='a domain object'/> + <arg name='flags' type='unsigned int' info='additional flags'/> + </function> <function name='virDomainGetBlockInfo' file='python'> <info>Extract information about a domain block device size</info> <return type='int *' info='the list of information or None in case of error'/> diff --git a/src/driver.h b/src/driver.h index 5df798a..ca49b08 100644 --- a/src/driver.h +++ b/src/driver.h @@ -171,6 +171,10 @@ typedef int int *reason, unsigned int flags); typedef int + (*virDrvDomainGetControlInfo) (virDomainPtr domain, + virDomainControlInfoPtr info, + unsigned int flags); +typedef int (*virDrvDomainSave) (virDomainPtr domain, const char *to); typedef int @@ -663,6 +667,7 @@ struct _virDriver { virDrvDomainGetBlkioParameters domainGetBlkioParameters; virDrvDomainGetInfo domainGetInfo; virDrvDomainGetState domainGetState; + virDrvDomainGetControlInfo domainGetControlInfo; virDrvDomainSave domainSave; virDrvDomainRestore domainRestore; virDrvDomainCoreDump domainCoreDump; diff --git a/src/libvirt.c b/src/libvirt.c index 18c4e08..81dd879 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3261,6 +3261,54 @@ error: } /** + * virDomainGetControlInfo: + * @domain: a domain object + * @info: pointer to a virDomainControlInfo structure allocated by the user + * @flags: additional flags, 0 for now + * + * Extract details about current state of control interface to a domain. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virDomainGetControlInfo(virDomainPtr domain, + virDomainControlInfoPtr info, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(domain, "info=%p", info); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (!info) { + virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + conn = domain->conn; + if (conn->driver->domainGetControlInfo) { + int ret; + ret = conn->driver->domainGetControlInfo(domain, info, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} + +/** * virDomainGetXMLDesc: * @domain: a domain object * @flags: an OR'ed set of virDomainXMLFlags diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 4d4299a..0e55097 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -450,4 +450,9 @@ LIBVIRT_0.9.2 { virInterfaceChangeRollback; } LIBVIRT_0.9.0; +LIBVIRT_0.9.3 { + global: + virDomainGetControlInfo; +} LIBVIRT_0.9.2; + # .... define new API here using predicted next version number .... -- 1.7.5.3

Hi Jiri, I don't see the libvirt_virDomainGetControlInfo implementation in libvirt-override.c. $ nm -D python/.libs/libvirtmod.so | grep virDomainGetControlInfo (empty) Is the python binding postponed to a future patch? -- Federico On Tue, Jun 7, 2011 at 3:01 PM, Jiri Denemark <jdenemar@redhat.com> wrote:
The API can be used to query current state of an interface to VMM used to control a domain. In QEMU world this translates into monitor connection. ---  include/libvirt/libvirt.h.in   |  40 ++++++++++++++++++++++++++++++++  python/generator.py       |   1 +  python/libvirt-override-api.xml |   6 +++++  src/driver.h           |   5 ++++  src/libvirt.c          |  48 +++++++++++++++++++++++++++++++++++++++  src/libvirt_public.syms     |   5 ++++  6 files changed, 105 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index df213f1..1454ca0 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -141,6 +141,43 @@ typedef enum { Â Â VIR_DOMAIN_CRASHED_UNKNOWN = 0, Â Â /* crashed for unknown reason */ Â } virDomainCrashedReason;
+ +/** + * virDomainControlState: + * + * Current state of a control interface to the domain. + */ +typedef enum { +   VIR_DOMAIN_CONTROL_OK = 0,    /* operational, ready to accept commands */ +   VIR_DOMAIN_CONTROL_JOB = 1,    /* background job is running (can be +                     monitored by virDomainGetJobInfo); only +                     limited set of commands may be allowed */ +   VIR_DOMAIN_CONTROL_OCCUPIED = 2, /* occupied by a running command */ +   VIR_DOMAIN_CONTROL_ERROR = 3,   /* unusable, domain cannot be fully operated */ +} virDomainControlState; + +/** + * virDomainControlInfo: + * + * Structure filled in by virDomainGetControlInfo and providing details about + * current state of control interface to a domain. + */ +typedef struct _virDomainControlInfo virDomainControlInfo; +struct _virDomainControlInfo { +   unsigned int state;   /* control state, one of virDomainControlState */ +   unsigned int details;  /* state details, currently 0 */ +   unsigned long long stateTime; /* for how long (in msec) control interface +                   has been in current state (except for OK +                   and ERROR states) */ +}; + +/** + * virDomainControlInfoPtr: + * + * Pointer to virDomainControlInfo structure. + */ +typedef virDomainControlInfo *virDomainControlInfoPtr; +  /**  * virDomainModificationImpact:  * @@ -781,6 +818,9 @@ int           virDomainGetState    (virDomainPtr domain,                          int *state,                          int *reason,                          unsigned int flags); +int           virDomainGetControlInfo (virDomainPtr domain, +                         virDomainControlInfoPtr info, +                         unsigned int flags);
 /*  * Return scheduler type in effect 'sedf', 'credit', 'linux' diff --git a/python/generator.py b/python/generator.py index 7c38fdd..4e3e9fa 100755 --- a/python/generator.py +++ b/python/generator.py @@ -306,6 +306,7 @@ skip_impl = (   'virGetLastError',   'virDomainGetInfo',   'virDomainGetState', +   'virDomainGetControlInfo',   'virDomainGetBlockInfo',   'virDomainGetJobInfo',   'virNodeGetInfo', diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index ec08e69..01207d6 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -54,6 +54,12 @@    <arg name='domain' type='virDomainPtr' info='a domain object'/>    <arg name='flags' type='unsigned int' info='additional flags'/>   </function> +   <function name='virDomainGetControlInfo' file='python'> +    <info>Extract details about current state of control interface to a domain.</info> +    <return type='int *' info='the list of information or None in case of error'/> +    <arg name='domain' type='virDomainPtr' info='a domain object'/> +    <arg name='flags' type='unsigned int' info='additional flags'/> +   </function>   <function name='virDomainGetBlockInfo' file='python'>    <info>Extract information about a domain block device size</info>    <return type='int *' info='the list of information or None in case of error'/> diff --git a/src/driver.h b/src/driver.h index 5df798a..ca49b08 100644 --- a/src/driver.h +++ b/src/driver.h @@ -171,6 +171,10 @@ typedef int                      int *reason,                      unsigned int flags);  typedef int +     (*virDrvDomainGetControlInfo)  (virDomainPtr domain, +                     virDomainControlInfoPtr info, +                     unsigned int flags); +typedef int     (*virDrvDomainSave)       (virDomainPtr domain,                      const char *to);  typedef int @@ -663,6 +667,7 @@ struct _virDriver {   virDrvDomainGetBlkioParameters domainGetBlkioParameters;   virDrvDomainGetInfo         domainGetInfo;   virDrvDomainGetState    domainGetState; +   virDrvDomainGetControlInfo  domainGetControlInfo;   virDrvDomainSave      domainSave;   virDrvDomainRestore         domainRestore;   virDrvDomainCoreDump     domainCoreDump; diff --git a/src/libvirt.c b/src/libvirt.c index 18c4e08..81dd879 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3261,6 +3261,54 @@ error:  }
 /** + * virDomainGetControlInfo: + * @domain: a domain object + * @info: pointer to a virDomainControlInfo structure allocated by the user + * @flags: additional flags, 0 for now + * + * Extract details about current state of control interface to a domain. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virDomainGetControlInfo(virDomainPtr domain, +             virDomainControlInfoPtr info, +             unsigned int flags) +{ +   virConnectPtr conn; + +   VIR_DOMAIN_DEBUG(domain, "info=%p", info); + +   virResetLastError(); + +   if (!VIR_IS_CONNECTED_DOMAIN(domain)) { +     virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); +     virDispatchError(NULL); +     return -1; +   } + +   if (!info) { +     virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__); +     goto error; +   } + +   conn = domain->conn; +   if (conn->driver->domainGetControlInfo) { +     int ret; +     ret = conn->driver->domainGetControlInfo(domain, info, flags); +     if (ret < 0) +       goto error; +     return ret; +   } + +   virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: +   virDispatchError(domain->conn); +   return -1; +} + +/**  * virDomainGetXMLDesc:  * @domain: a domain object  * @flags: an OR'ed set of virDomainXMLFlags diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 4d4299a..0e55097 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -450,4 +450,9 @@ LIBVIRT_0.9.2 {     virInterfaceChangeRollback;  } LIBVIRT_0.9.0;
+LIBVIRT_0.9.3 { + Â Â global: + Â Â Â Â virDomainGetControlInfo; +} LIBVIRT_0.9.2; + Â # .... define new API here using predicted next version number .... -- 1.7.5.3
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On Thu, Jun 09, 2011 at 17:08:14 +0200, Federico Simoncelli wrote:
Hi Jiri, I don't see the libvirt_virDomainGetControlInfo implementation in libvirt-override.c.
$ nm -D python/.libs/libvirtmod.so | grep virDomainGetControlInfo (empty)
Is the python binding postponed to a future patch?
Oops, no, it was supposed to be there. However, I apparently forgot to implement it. I'll fix that in v2. Jirka

On Tue, Jun 07, 2011 at 03:01:57PM +0200, Jiri Denemark wrote:
The API can be used to query current state of an interface to VMM used to control a domain. In QEMU world this translates into monitor connection. [...] diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index df213f1..1454ca0 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -141,6 +141,43 @@ typedef enum { VIR_DOMAIN_CRASHED_UNKNOWN = 0, /* crashed for unknown reason */ } virDomainCrashedReason;
+ +/** + * virDomainControlState: + * + * Current state of a control interface to the domain. + */ +typedef enum { + VIR_DOMAIN_CONTROL_OK = 0, /* operational, ready to accept commands */ + VIR_DOMAIN_CONTROL_JOB = 1, /* background job is running (can be + monitored by virDomainGetJobInfo); only + limited set of commands may be allowed */ + VIR_DOMAIN_CONTROL_OCCUPIED = 2, /* occupied by a running command */ + VIR_DOMAIN_CONTROL_ERROR = 3, /* unusable, domain cannot be fully operated */ +} virDomainControlState; + +/** + * virDomainControlInfo: + * + * Structure filled in by virDomainGetControlInfo and providing details about + * current state of control interface to a domain. + */ +typedef struct _virDomainControlInfo virDomainControlInfo; +struct _virDomainControlInfo { + unsigned int state; /* control state, one of virDomainControlState */ + unsigned int details; /* state details, currently 0 */ + unsigned long long stateTime; /* for how long (in msec) control interface + has been in current state (except for OK + and ERROR states) */ +}; + +/** + * virDomainControlInfoPtr: + * + * Pointer to virDomainControlInfo structure. + */ +typedef virDomainControlInfo *virDomainControlInfoPtr; + /** * virDomainModificationImpact: * @@ -781,6 +818,9 @@ int virDomainGetState (virDomainPtr domain, int *state, int *reason, unsigned int flags); +int virDomainGetControlInfo (virDomainPtr domain, + virDomainControlInfoPtr info, + unsigned int flags);
that's really the "meat" of that patchset, it looks fine, ACK from me but since you intent a v2 don't commit right now :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

The API can be used to query current state of an interface to VMM used to control a domain. In QEMU world this translates into monitor connection. --- Notes: Version 2: - really implement python binding include/libvirt/libvirt.h.in | 40 ++++++++++++++++++++++++++++++++ python/generator.py | 1 + python/libvirt-override-api.xml | 6 +++++ python/libvirt-override.c | 27 ++++++++++++++++++++++ src/driver.h | 5 ++++ src/libvirt.c | 48 +++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 ++++ 7 files changed, 132 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index df213f1..1454ca0 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -141,6 +141,43 @@ typedef enum { VIR_DOMAIN_CRASHED_UNKNOWN = 0, /* crashed for unknown reason */ } virDomainCrashedReason; + +/** + * virDomainControlState: + * + * Current state of a control interface to the domain. + */ +typedef enum { + VIR_DOMAIN_CONTROL_OK = 0, /* operational, ready to accept commands */ + VIR_DOMAIN_CONTROL_JOB = 1, /* background job is running (can be + monitored by virDomainGetJobInfo); only + limited set of commands may be allowed */ + VIR_DOMAIN_CONTROL_OCCUPIED = 2, /* occupied by a running command */ + VIR_DOMAIN_CONTROL_ERROR = 3, /* unusable, domain cannot be fully operated */ +} virDomainControlState; + +/** + * virDomainControlInfo: + * + * Structure filled in by virDomainGetControlInfo and providing details about + * current state of control interface to a domain. + */ +typedef struct _virDomainControlInfo virDomainControlInfo; +struct _virDomainControlInfo { + unsigned int state; /* control state, one of virDomainControlState */ + unsigned int details; /* state details, currently 0 */ + unsigned long long stateTime; /* for how long (in msec) control interface + has been in current state (except for OK + and ERROR states) */ +}; + +/** + * virDomainControlInfoPtr: + * + * Pointer to virDomainControlInfo structure. + */ +typedef virDomainControlInfo *virDomainControlInfoPtr; + /** * virDomainModificationImpact: * @@ -781,6 +818,9 @@ int virDomainGetState (virDomainPtr domain, int *state, int *reason, unsigned int flags); +int virDomainGetControlInfo (virDomainPtr domain, + virDomainControlInfoPtr info, + unsigned int flags); /* * Return scheduler type in effect 'sedf', 'credit', 'linux' diff --git a/python/generator.py b/python/generator.py index 7c38fdd..4e3e9fa 100755 --- a/python/generator.py +++ b/python/generator.py @@ -306,6 +306,7 @@ skip_impl = ( 'virGetLastError', 'virDomainGetInfo', 'virDomainGetState', + 'virDomainGetControlInfo', 'virDomainGetBlockInfo', 'virDomainGetJobInfo', 'virNodeGetInfo', diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index ec08e69..01207d6 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -54,6 +54,12 @@ <arg name='domain' type='virDomainPtr' info='a domain object'/> <arg name='flags' type='unsigned int' info='additional flags'/> </function> + <function name='virDomainGetControlInfo' file='python'> + <info>Extract details about current state of control interface to a domain.</info> + <return type='int *' info='the list of information or None in case of error'/> + <arg name='domain' type='virDomainPtr' info='a domain object'/> + <arg name='flags' type='unsigned int' info='additional flags'/> + </function> <function name='virDomainGetBlockInfo' file='python'> <info>Extract information about a domain block device size</info> <return type='int *' info='the list of information or None in case of error'/> diff --git a/python/libvirt-override.c b/python/libvirt-override.c index 974decb..c6a1d4f 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -1100,6 +1100,32 @@ libvirt_virDomainGetState(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) } static PyObject * +libvirt_virDomainGetControlInfo(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + int c_retval; + virDomainPtr domain; + PyObject *pyobj_domain; + virDomainControlInfo info; + unsigned int flags; + + if (!PyArg_ParseTuple(args, (char *)"Oi:virDomainGetControlInfo", + &pyobj_domain, &flags)) + return NULL; + domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virDomainGetControlInfo(domain, &info, flags); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + py_retval = PyList_New(3); + PyList_SetItem(py_retval, 0, libvirt_intWrap(info.state)); + PyList_SetItem(py_retval, 1, libvirt_intWrap(info.details)); + PyList_SetItem(py_retval, 2, libvirt_longlongWrap(info.stateTime)); + return py_retval; +} + +static PyObject * libvirt_virDomainGetBlockInfo(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *py_retval; int c_retval; @@ -3555,6 +3581,7 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virConnectDomainEventDeregisterAny", libvirt_virConnectDomainEventDeregisterAny, METH_VARARGS, NULL}, {(char *) "virDomainGetInfo", libvirt_virDomainGetInfo, METH_VARARGS, NULL}, {(char *) "virDomainGetState", libvirt_virDomainGetState, METH_VARARGS, NULL}, + {(char *) "virDomainGetControlInfo", libvirt_virDomainGetControlInfo, METH_VARARGS, NULL}, {(char *) "virDomainGetBlockInfo", libvirt_virDomainGetBlockInfo, METH_VARARGS, NULL}, {(char *) "virNodeGetInfo", libvirt_virNodeGetInfo, METH_VARARGS, NULL}, {(char *) "virDomainGetUUID", libvirt_virDomainGetUUID, METH_VARARGS, NULL}, diff --git a/src/driver.h b/src/driver.h index 5df798a..ca49b08 100644 --- a/src/driver.h +++ b/src/driver.h @@ -171,6 +171,10 @@ typedef int int *reason, unsigned int flags); typedef int + (*virDrvDomainGetControlInfo) (virDomainPtr domain, + virDomainControlInfoPtr info, + unsigned int flags); +typedef int (*virDrvDomainSave) (virDomainPtr domain, const char *to); typedef int @@ -663,6 +667,7 @@ struct _virDriver { virDrvDomainGetBlkioParameters domainGetBlkioParameters; virDrvDomainGetInfo domainGetInfo; virDrvDomainGetState domainGetState; + virDrvDomainGetControlInfo domainGetControlInfo; virDrvDomainSave domainSave; virDrvDomainRestore domainRestore; virDrvDomainCoreDump domainCoreDump; diff --git a/src/libvirt.c b/src/libvirt.c index 997d4a2..83adf33 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3274,6 +3274,54 @@ error: } /** + * virDomainGetControlInfo: + * @domain: a domain object + * @info: pointer to a virDomainControlInfo structure allocated by the user + * @flags: additional flags, 0 for now + * + * Extract details about current state of control interface to a domain. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +virDomainGetControlInfo(virDomainPtr domain, + virDomainControlInfoPtr info, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(domain, "info=%p", info); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (!info) { + virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__); + goto error; + } + + conn = domain->conn; + if (conn->driver->domainGetControlInfo) { + int ret; + ret = conn->driver->domainGetControlInfo(domain, info, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} + +/** * virDomainGetXMLDesc: * @domain: a domain object * @flags: an OR'ed set of virDomainXMLFlags diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 4d4299a..0e55097 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -450,4 +450,9 @@ LIBVIRT_0.9.2 { virInterfaceChangeRollback; } LIBVIRT_0.9.0; +LIBVIRT_0.9.3 { + global: + virDomainGetControlInfo; +} LIBVIRT_0.9.2; + # .... define new API here using predicted next version number .... -- 1.7.5.3

On Mon, Jun 13, 2011 at 12:13:15PM +0200, Jiri Denemark wrote:
The API can be used to query current state of an interface to VMM used to control a domain. In QEMU world this translates into monitor connection. --- Notes: Version 2: - really implement python binding
[...]
diff --git a/python/generator.py b/python/generator.py index 7c38fdd..4e3e9fa 100755 --- a/python/generator.py +++ b/python/generator.py @@ -306,6 +306,7 @@ skip_impl = ( 'virGetLastError', 'virDomainGetInfo', 'virDomainGetState', + 'virDomainGetControlInfo', 'virDomainGetBlockInfo', 'virDomainGetJobInfo', 'virNodeGetInfo', diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index ec08e69..01207d6 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -54,6 +54,12 @@ <arg name='domain' type='virDomainPtr' info='a domain object'/> <arg name='flags' type='unsigned int' info='additional flags'/> </function> + <function name='virDomainGetControlInfo' file='python'> + <info>Extract details about current state of control interface to a domain.</info> + <return type='int *' info='the list of information or None in case of error'/> + <arg name='domain' type='virDomainPtr' info='a domain object'/> + <arg name='flags' type='unsigned int' info='additional flags'/> + </function> <function name='virDomainGetBlockInfo' file='python'> <info>Extract information about a domain block device size</info> <return type='int *' info='the list of information or None in case of error'/> diff --git a/python/libvirt-override.c b/python/libvirt-override.c index 974decb..c6a1d4f 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -1100,6 +1100,32 @@ libvirt_virDomainGetState(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) }
static PyObject * +libvirt_virDomainGetControlInfo(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + int c_retval; + virDomainPtr domain; + PyObject *pyobj_domain; + virDomainControlInfo info; + unsigned int flags; + + if (!PyArg_ParseTuple(args, (char *)"Oi:virDomainGetControlInfo", + &pyobj_domain, &flags)) + return NULL; + domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virDomainGetControlInfo(domain, &info, flags); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + py_retval = PyList_New(3); + PyList_SetItem(py_retval, 0, libvirt_intWrap(info.state)); + PyList_SetItem(py_retval, 1, libvirt_intWrap(info.details)); + PyList_SetItem(py_retval, 2, libvirt_longlongWrap(info.stateTime)); + return py_retval; +} + +static PyObject * libvirt_virDomainGetBlockInfo(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *py_retval; int c_retval; @@ -3555,6 +3581,7 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virConnectDomainEventDeregisterAny", libvirt_virConnectDomainEventDeregisterAny, METH_VARARGS, NULL}, {(char *) "virDomainGetInfo", libvirt_virDomainGetInfo, METH_VARARGS, NULL}, {(char *) "virDomainGetState", libvirt_virDomainGetState, METH_VARARGS, NULL}, + {(char *) "virDomainGetControlInfo", libvirt_virDomainGetControlInfo, METH_VARARGS, NULL}, {(char *) "virDomainGetBlockInfo", libvirt_virDomainGetBlockInfo, METH_VARARGS, NULL}, {(char *) "virNodeGetInfo", libvirt_virNodeGetInfo, METH_VARARGS, NULL}, {(char *) "virDomainGetUUID", libvirt_virDomainGetUUID, METH_VARARGS, NULL},
Okay, ACK for the python side addition, could you just make 100% sure that the VIR_DOMAIN_CONTROL_... values are correctly grabbed by the the generator and put in the final libvirt.py ? thanks, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

--- daemon/remote_generator.pl | 20 ++++++++++++++------ src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 14 +++++++++++++- src/remote_protocol-structs | 9 +++++++++ 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/daemon/remote_generator.pl b/daemon/remote_generator.pl index 632972c..8881d6c 100755 --- a/daemon/remote_generator.pl +++ b/daemon/remote_generator.pl @@ -668,9 +668,13 @@ elsif ($opt_b) { my $struct_name = $call->{ProcName}; $struct_name =~ s/Get//; - if ($call->{ProcName} eq "DomainGetBlockInfo") { - # SPECIAL: virDomainGetBlockInfo has flags parameter after - # the struct parameter in its signature + if ($call->{ProcName} eq "DomainGetBlockInfo" || + $call->{ProcName} eq "DomainGetControlInfo") { + # SPECIAL: virDomainGetBlockInfo and virDomainGetControlInfo + # have flags parameter after the struct parameter in + # its signature + # FIXME: this doesn't sound special at all; flags parameter is + # almost always the last one; anything else is special my $flags = pop(@args_list); push(@args_list, "&tmp"); push(@args_list, $flags); @@ -1203,9 +1207,13 @@ elsif ($opt_k) { my $struct_name = $call->{ProcName}; $struct_name =~ s/Get//; - if ($call->{ProcName} eq "DomainGetBlockInfo") { - # SPECIAL: virDomainGetBlockInfo has flags parameter after - # the struct parameter in its signature + if ($call->{ProcName} eq "DomainGetBlockInfo" || + $call->{ProcName} eq "DomainGetControlInfo") { + # SPECIAL: virDomainGetBlockInfo and virDomainGetControlInfo + # have flags parameter after the struct parameter in + # its signature + # FIXME: this doesn't sound special at all; flags parameter is + # almost always the last one; anything else is special $last_arg = pop(@args_list); } diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 8335a1a..f1c6674 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -6251,6 +6251,7 @@ static virDriver remote_driver = { .domainGetBlkioParameters = remoteDomainGetBlkioParameters, /* 0.9.0 */ .domainGetInfo = remoteDomainGetInfo, /* 0.3.0 */ .domainGetState = remoteDomainGetState, /* 0.9.2 */ + .domainGetControlInfo = remoteDomainGetControlInfo, /* 0.9.3 */ .domainSave = remoteDomainSave, /* 0.3.0 */ .domainRestore = remoteDomainRestore, /* 0.3.0 */ .domainCoreDump = remoteDomainCoreDump, /* 0.3.0 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index c9b8cff..7e8ad6d 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -2035,6 +2035,17 @@ struct remote_domain_event_control_error_msg { remote_nonnull_domain dom; }; +struct remote_domain_get_control_info_args { + remote_nonnull_domain dom; + unsigned int flags; +}; + +struct remote_domain_get_control_info_ret { + unsigned int state; + unsigned int details; + unsigned hyper stateTime; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -2297,7 +2308,8 @@ enum remote_procedure { REMOTE_PROC_INTERFACE_CHANGE_COMMIT = 221, /* autogen autogen */ REMOTE_PROC_INTERFACE_CHANGE_ROLLBACK = 222, /* autogen autogen */ REMOTE_PROC_DOMAIN_GET_SCHEDULER_PARAMETERS_FLAGS = 223, /* skipgen autogen */ - REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR = 224 /* skipgen skipgen */ + REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR = 224, /* skipgen skipgen */ + REMOTE_PROC_DOMAIN_GET_CONTROL_INFO = 225 /* autogen autogen */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 1d90dd5..18511be 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1542,6 +1542,15 @@ struct remote_domain_migrate_confirm3_args { struct remote_domain_event_control_error_msg { remote_nonnull_domain dom; }; +struct remote_domain_get_control_info_args { + remote_nonnull_domain dom; + u_int flags; +}; +struct remote_domain_get_control_info_ret { + u_int state; + u_int details; + uint64_t stateTime; +}; struct remote_message_header { u_int prog; u_int vers; -- 1.7.5.3

On Tue, Jun 07, 2011 at 03:01:58PM +0200, Jiri Denemark wrote:
--- daemon/remote_generator.pl | 20 ++++++++++++++------ src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 14 +++++++++++++- src/remote_protocol-structs | 9 +++++++++ 4 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/daemon/remote_generator.pl b/daemon/remote_generator.pl index 632972c..8881d6c 100755 --- a/daemon/remote_generator.pl +++ b/daemon/remote_generator.pl @@ -668,9 +668,13 @@ elsif ($opt_b) { my $struct_name = $call->{ProcName}; $struct_name =~ s/Get//;
- if ($call->{ProcName} eq "DomainGetBlockInfo") { - # SPECIAL: virDomainGetBlockInfo has flags parameter after - # the struct parameter in its signature + if ($call->{ProcName} eq "DomainGetBlockInfo" || + $call->{ProcName} eq "DomainGetControlInfo") { + # SPECIAL: virDomainGetBlockInfo and virDomainGetControlInfo + # have flags parameter after the struct parameter in + # its signature + # FIXME: this doesn't sound special at all; flags parameter is + # almost always the last one; anything else is special my $flags = pop(@args_list); push(@args_list, "&tmp"); push(@args_list, $flags); @@ -1203,9 +1207,13 @@ elsif ($opt_k) { my $struct_name = $call->{ProcName}; $struct_name =~ s/Get//;
- if ($call->{ProcName} eq "DomainGetBlockInfo") { - # SPECIAL: virDomainGetBlockInfo has flags parameter after - # the struct parameter in its signature + if ($call->{ProcName} eq "DomainGetBlockInfo" || + $call->{ProcName} eq "DomainGetControlInfo") { + # SPECIAL: virDomainGetBlockInfo and virDomainGetControlInfo + # have flags parameter after the struct parameter in + # its signature + # FIXME: this doesn't sound special at all; flags parameter is + # almost always the last one; anything else is special $last_arg = pop(@args_list); }
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 8335a1a..f1c6674 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -6251,6 +6251,7 @@ static virDriver remote_driver = { .domainGetBlkioParameters = remoteDomainGetBlkioParameters, /* 0.9.0 */ .domainGetInfo = remoteDomainGetInfo, /* 0.3.0 */ .domainGetState = remoteDomainGetState, /* 0.9.2 */ + .domainGetControlInfo = remoteDomainGetControlInfo, /* 0.9.3 */ .domainSave = remoteDomainSave, /* 0.3.0 */ .domainRestore = remoteDomainRestore, /* 0.3.0 */ .domainCoreDump = remoteDomainCoreDump, /* 0.3.0 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index c9b8cff..7e8ad6d 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -2035,6 +2035,17 @@ struct remote_domain_event_control_error_msg { remote_nonnull_domain dom; };
+struct remote_domain_get_control_info_args { + remote_nonnull_domain dom; + unsigned int flags; +}; + +struct remote_domain_get_control_info_ret { + unsigned int state; + unsigned int details; + unsigned hyper stateTime; +}; + /*----- Protocol. -----*/
/* Define the program number, protocol version and procedure numbers here. */ @@ -2297,7 +2308,8 @@ enum remote_procedure { REMOTE_PROC_INTERFACE_CHANGE_COMMIT = 221, /* autogen autogen */ REMOTE_PROC_INTERFACE_CHANGE_ROLLBACK = 222, /* autogen autogen */ REMOTE_PROC_DOMAIN_GET_SCHEDULER_PARAMETERS_FLAGS = 223, /* skipgen autogen */ - REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR = 224 /* skipgen skipgen */ + REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR = 224, /* skipgen skipgen */ + REMOTE_PROC_DOMAIN_GET_CONTROL_INFO = 225 /* autogen autogen */
/* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 1d90dd5..18511be 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1542,6 +1542,15 @@ struct remote_domain_migrate_confirm3_args { struct remote_domain_event_control_error_msg { remote_nonnull_domain dom; }; +struct remote_domain_get_control_info_args { + remote_nonnull_domain dom; + u_int flags; +}; +struct remote_domain_get_control_info_ret { + u_int state; + u_int details; + uint64_t stateTime; +}; struct remote_message_header { u_int prog; u_int vers;
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

--- src/qemu/qemu_domain.c | 4 +++ src/qemu/qemu_domain.h | 2 + src/qemu/qemu_driver.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_process.c | 3 ++ 4 files changed, 70 insertions(+), 0 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 5f18ad3..06d2a5e 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -609,6 +609,7 @@ void qemuDomainObjEnterMonitor(virDomainObjPtr obj) qemuMonitorLock(priv->mon); qemuMonitorRef(priv->mon); + virTimeMs(&priv->monStart); virDomainObjUnlock(obj); } @@ -629,6 +630,7 @@ void qemuDomainObjExitMonitor(virDomainObjPtr obj) virDomainObjLock(obj); + priv->monStart = 0; if (refs == 0) { priv->mon = NULL; } @@ -650,6 +652,7 @@ void qemuDomainObjEnterMonitorWithDriver(struct qemud_driver *driver, qemuMonitorLock(priv->mon); qemuMonitorRef(priv->mon); + virTimeMs(&priv->monStart); virDomainObjUnlock(obj); qemuDriverUnlock(driver); } @@ -674,6 +677,7 @@ void qemuDomainObjExitMonitorWithDriver(struct qemud_driver *driver, qemuDriverLock(driver); virDomainObjLock(obj); + priv->monStart = 0; if (refs == 0) { priv->mon = NULL; } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index bacf5b5..3d041fc 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -79,6 +79,8 @@ struct _qemuDomainObjPrivate { qemuMonitorPtr mon; virDomainChrSourceDefPtr monConfig; int monJSON; + bool monError; + unsigned long long monStart; bool gotShutdown; int nvcpupids; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 470573e..8328757 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1873,6 +1873,66 @@ cleanup: return ret; } +static int +qemuDomainGetControlInfo(virDomainPtr dom, + virDomainControlInfoPtr info, + unsigned int flags) +{ + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + qemuDomainObjPrivatePtr priv; + int ret = -1; + + virCheckFlags(0, -1); + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + qemuDriverUnlock(driver); + + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + memset(info, 0, sizeof(*info)); + + if (priv->monError) { + info->state = VIR_DOMAIN_CONTROL_ERROR; + } else if (priv->jobActive) { + if (!priv->monStart) { + info->state = VIR_DOMAIN_CONTROL_JOB; + if (virTimeMs(&info->stateTime) < 0) + goto cleanup; + info->stateTime -= priv->jobStart; + } else { + info->state = VIR_DOMAIN_CONTROL_OCCUPIED; + if (virTimeMs(&info->stateTime) < 0) + goto cleanup; + info->stateTime -= priv->monStart; + } + } else { + info->state = VIR_DOMAIN_CONTROL_OK; + } + + ret = 0; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + return ret; +} + #define QEMUD_SAVE_MAGIC "LibvirtQemudSave" #define QEMUD_SAVE_VERSION 2 @@ -8001,6 +8061,7 @@ static virDriver qemuDriver = { .domainGetBlkioParameters = qemuDomainGetBlkioParameters, /* 0.9.0 */ .domainGetInfo = qemudDomainGetInfo, /* 0.2.0 */ .domainGetState = qemuDomainGetState, /* 0.9.2 */ + .domainGetControlInfo = qemuDomainGetControlInfo, /* 0.9.3 */ .domainSave = qemudDomainSave, /* 0.2.0 */ .domainRestore = qemuDomainRestore, /* 0.2.0 */ .domainCoreDump = qemudDomainCoreDump, /* 0.7.0 */ diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 40078e4..1790332 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -166,6 +166,7 @@ qemuProcessHandleMonitorError(qemuMonitorPtr mon ATTRIBUTE_UNUSED, qemuDriverLock(driver); virDomainObjLock(vm); + ((qemuDomainObjPrivatePtr) vm->privateData)->monError = true; event = virDomainEventControlErrorNewFromObj(vm); if (event) qemuDomainEventQueue(driver, event); @@ -2255,6 +2256,8 @@ int qemuProcessStart(virConnectPtr conn, #endif priv->monJSON = 0; + priv->monError = false; + priv->monStart = 0; priv->gotShutdown = false; if ((ret = virFileDeletePid(driver->stateDir, vm->def->name)) != 0) { -- 1.7.5.3

On Tue, Jun 07, 2011 at 03:01:59PM +0200, Jiri Denemark wrote:
--- src/qemu/qemu_domain.c | 4 +++ src/qemu/qemu_domain.h | 2 + src/qemu/qemu_driver.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_process.c | 3 ++ 4 files changed, 70 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 5f18ad3..06d2a5e 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -609,6 +609,7 @@ void qemuDomainObjEnterMonitor(virDomainObjPtr obj)
qemuMonitorLock(priv->mon); qemuMonitorRef(priv->mon); + virTimeMs(&priv->monStart); virDomainObjUnlock(obj); }
@@ -629,6 +630,7 @@ void qemuDomainObjExitMonitor(virDomainObjPtr obj)
virDomainObjLock(obj);
+ priv->monStart = 0; if (refs == 0) { priv->mon = NULL; } @@ -650,6 +652,7 @@ void qemuDomainObjEnterMonitorWithDriver(struct qemud_driver *driver,
qemuMonitorLock(priv->mon); qemuMonitorRef(priv->mon); + virTimeMs(&priv->monStart); virDomainObjUnlock(obj); qemuDriverUnlock(driver); } @@ -674,6 +677,7 @@ void qemuDomainObjExitMonitorWithDriver(struct qemud_driver *driver, qemuDriverLock(driver); virDomainObjLock(obj);
+ priv->monStart = 0; if (refs == 0) { priv->mon = NULL; }
Hum ... can we double-check that we can only enter and exit the monitor from those 4 entry points, for example in case of error. Having a small error leading to a miscategorization of the monitor being unresponsive would be a serious regression.
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index bacf5b5..3d041fc 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -79,6 +79,8 @@ struct _qemuDomainObjPrivate { qemuMonitorPtr mon; virDomainChrSourceDefPtr monConfig; int monJSON; + bool monError; + unsigned long long monStart; bool gotShutdown;
next step would probably to measure how long monitor commands take but that's beyond GetControlInfo reach :-) [...]
--- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -166,6 +166,7 @@ qemuProcessHandleMonitorError(qemuMonitorPtr mon ATTRIBUTE_UNUSED, qemuDriverLock(driver); virDomainObjLock(vm);
+ ((qemuDomainObjPrivatePtr) vm->privateData)->monError = true; event = virDomainEventControlErrorNewFromObj(vm); if (event) qemuDomainEventQueue(driver, event); @@ -2255,6 +2256,8 @@ int qemuProcessStart(virConnectPtr conn, #endif priv->monJSON = 0;
+ priv->monError = false; + priv->monStart = 0; priv->gotShutdown = false;
if ((ret = virFileDeletePid(driver->stateDir, vm->def->name)) != 0) {
Okay, looks fine, ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

--- tools/virsh.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 7 +++++ 2 files changed, 73 insertions(+), 0 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index d98be1c..2c81cf4 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -350,6 +350,7 @@ static void vshDebug(vshControl *ctl, int level, const char *format, ...) static int vshDomainState(vshControl *ctl, virDomainPtr dom, int *reason); static const char *vshDomainStateToString(int state); static const char *vshDomainStateReasonToString(int state, int reason); +static const char *vshDomainControlStateToString(int state); static const char *vshDomainVcpuStateToString(int state); static bool vshConnectionUsability(vshControl *ctl, virConnectPtr conn); @@ -976,6 +977,53 @@ cleanup: return ret; } +/* + * "domcontrol" command + */ +static const vshCmdInfo info_domcontrol[] = { + {"help", N_("domain control interface state")}, + {"desc", N_("Returns state of a control interface to the domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domcontrol[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomControl(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + bool ret = true; + virDomainControlInfo info; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (virDomainGetControlInfo(dom, &info, 0) < 0) { + ret = false; + goto cleanup; + } + + if (info.state != VIR_DOMAIN_CONTROL_OK && + info.state != VIR_DOMAIN_CONTROL_ERROR) { + vshPrint(ctl, "%s (%0.3fs)\n", + _(vshDomainControlStateToString(info.state)), + info.stateTime / 1000.0); + } else { + vshPrint(ctl, "%s\n", + _(vshDomainControlStateToString(info.state))); + } + +cleanup: + virDomainFree(dom); + return ret; +} + /* "domblkstat" command */ static const vshCmdInfo info_domblkstat[] = { @@ -11107,6 +11155,7 @@ static const vshCmdDef domManagementCmds[] = { static const vshCmdDef domMonitoringCmds[] = { {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo, 0}, {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat, 0}, + {"domcontrol", cmdDomControl, opts_domcontrol, info_domcontrol, 0}, {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat, 0}, {"dominfo", cmdDominfo, opts_dominfo, info_dominfo, 0}, {"dommemstat", cmdDomMemStat, opts_dommemstat, info_dommemstat, 0}, @@ -12621,6 +12670,23 @@ vshDomainStateReasonToString(int state, int reason) } static const char * +vshDomainControlStateToString(int state) +{ + switch ((virDomainControlState) state) { + case VIR_DOMAIN_CONTROL_OK: + return N_("ok"); + case VIR_DOMAIN_CONTROL_JOB: + return N_("background job"); + case VIR_DOMAIN_CONTROL_OCCUPIED: + return N_("occupied"); + case VIR_DOMAIN_CONTROL_ERROR: + return N_("error"); + } + + return N_("unknown"); +} + +static const char * vshDomainVcpuStateToString(int state) { switch (state) { diff --git a/tools/virsh.pod b/tools/virsh.pod index 7ed3003..3f55422 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -437,6 +437,13 @@ Convert a domain Id (or UUID) to domain name Returns state about a domain. I<--reason> tells virsh to also print reason for the state. +=item B<domcontrol> I<domain-id> + +Returns state of an interface to VMM used to control a domain. This +translates into monitor connection in QEMu world. For states other +than "ok" or "error" the command also prints number of seconds elapsed +since the control interface entered its current state. + =item B<domxml-from-native> I<format> I<config> Convert the file I<config> in the native guest configuration format -- 1.7.5.3

On Tue, Jun 07, 2011 at 03:02:00PM +0200, Jiri Denemark wrote:
--- tools/virsh.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 7 +++++ 2 files changed, 73 insertions(+), 0 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c index d98be1c..2c81cf4 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -350,6 +350,7 @@ static void vshDebug(vshControl *ctl, int level, const char *format, ...) static int vshDomainState(vshControl *ctl, virDomainPtr dom, int *reason); static const char *vshDomainStateToString(int state); static const char *vshDomainStateReasonToString(int state, int reason); +static const char *vshDomainControlStateToString(int state); static const char *vshDomainVcpuStateToString(int state); static bool vshConnectionUsability(vshControl *ctl, virConnectPtr conn);
@@ -976,6 +977,53 @@ cleanup: return ret; }
+/* + * "domcontrol" command + */ +static const vshCmdInfo info_domcontrol[] = { + {"help", N_("domain control interface state")}, + {"desc", N_("Returns state of a control interface to the domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domcontrol[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomControl(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + bool ret = true; + virDomainControlInfo info; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (virDomainGetControlInfo(dom, &info, 0) < 0) { + ret = false; + goto cleanup; + } + + if (info.state != VIR_DOMAIN_CONTROL_OK && + info.state != VIR_DOMAIN_CONTROL_ERROR) { + vshPrint(ctl, "%s (%0.3fs)\n", + _(vshDomainControlStateToString(info.state)), + info.stateTime / 1000.0); + } else { + vshPrint(ctl, "%s\n", + _(vshDomainControlStateToString(info.state))); + } + +cleanup: + virDomainFree(dom); + return ret; +} + /* "domblkstat" command */ static const vshCmdInfo info_domblkstat[] = { @@ -11107,6 +11155,7 @@ static const vshCmdDef domManagementCmds[] = { static const vshCmdDef domMonitoringCmds[] = { {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo, 0}, {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat, 0}, + {"domcontrol", cmdDomControl, opts_domcontrol, info_domcontrol, 0}, {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat, 0}, {"dominfo", cmdDominfo, opts_dominfo, info_dominfo, 0}, {"dommemstat", cmdDomMemStat, opts_dommemstat, info_dommemstat, 0}, @@ -12621,6 +12670,23 @@ vshDomainStateReasonToString(int state, int reason) }
static const char * +vshDomainControlStateToString(int state) +{ + switch ((virDomainControlState) state) { + case VIR_DOMAIN_CONTROL_OK: + return N_("ok"); + case VIR_DOMAIN_CONTROL_JOB: + return N_("background job"); + case VIR_DOMAIN_CONTROL_OCCUPIED: + return N_("occupied"); + case VIR_DOMAIN_CONTROL_ERROR: + return N_("error"); + } + + return N_("unknown"); +} + +static const char * vshDomainVcpuStateToString(int state) { switch (state) { diff --git a/tools/virsh.pod b/tools/virsh.pod index 7ed3003..3f55422 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -437,6 +437,13 @@ Convert a domain Id (or UUID) to domain name Returns state about a domain. I<--reason> tells virsh to also print reason for the state.
+=item B<domcontrol> I<domain-id> + +Returns state of an interface to VMM used to control a domain. This +translates into monitor connection in QEMu world. For states other
that's "QEmu" I think, and that could be QMP or the monitor, so I'm not sure we should try to give details about one specific implementation :-)
+than "ok" or "error" the command also prints number of seconds elapsed +since the control interface entered its current state. + =item B<domxml-from-native> I<format> I<config>
Convert the file I<config> in the native guest configuration format
ACK otherwise, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Tue, Jun 07, 2011 at 15:01:54 +0200, Jiri Denemark wrote:
The API can be used to query current state of an interface to VMM used to control a domain.
In QEMU world this translates into monitor connection and one can use the API, e.g., to check whether (and for how long) libvirtd is currently waiting for a reply from qemu process.
Jiri Denemark (6): Introduce virTimeMs for getting current time in ms Use virTimeMs when appropriate
Actually, these first two patches are independent and can be reviewed/applied before the rest of this series :-) Jirka

On Tue, Jun 07, 2011 at 15:01:54 +0200, Jiri Denemark wrote:
The API can be used to query current state of an interface to VMM used to control a domain.
In QEMU world this translates into monitor connection and one can use the API, e.g., to check whether (and for how long) libvirtd is currently waiting for a reply from qemu process.
Jiri Denemark (6): Introduce virTimeMs for getting current time in ms Use virTimeMs when appropriate Introduce virDomainGetControlInfo API Wire protocol and remote driver for virDomainGetControlInfo qemu: Implement virDomainGetControlInfo virsh: Add support for virDomainGetControlInfo
I checked what I was asked to check, removed QEMU specific note from virsh.pod, rebased on current master and pushed the series. Thanks for the review. Jirka
participants (4)
-
Daniel Veillard
-
Federico Simoncelli
-
Jiri Denemark
-
Michal Privoznik