Here the patch for virtual CPU functions.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The patch (vcpus.diff) is joined with this mail.

To apply the patch, untar the libvirt-0.1.3.tar.gz archive (if not already done).
Then in libvirt-0.1.3 directory, do
   ./configure --prefix=/usr
if not already done, and after this:
   patch -p1 < vcpus.diff
   make
   make install

From the initial patch of Michel Ponceau (not delivered), I've just modify the virDomainGetVcpus function and added some useful macro for bit manipulation in cpu bit maps.

TODO: These vcpus functions permits to dynamically change the vcpu/cpu relation after the domain has been started but nothing has been done regarding static cpus attribution in the XML configuration file of a domain.

Philippe Berthault.

--- libvirt-0.1.3/include/libvirt/libvirt.h	2006-07-11 18:05:07.000000000 +0200
+++ libvirt-0.1.3.with_vcpus/include/libvirt/libvirt.h	2006-08-02 16:42:51.000000000 +0200
@@ -289,6 +289,106 @@
 						 const char **names,
 						 int maxnames);
 int			virDomainCreate		(virDomainPtr domain);
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ * virVcpuInfo: structure for information about a virtual CPU in a domain.
+ */
+
+typedef enum {
+    VIR_VCPU_OFFLINE	= 0,	/* the virtual CPU is offline */
+    VIR_VCPU_RUNNING	= 1,	/* the virtual CPU is running */
+    VIR_VCPU_BLOCKED	= 2,	/* the virtual CPU is blocked on resource */
+} virVcpuState;
+
+typedef struct _virVcpuInfo virVcpuInfo;
+struct _virVcpuInfo {
+    unsigned int number;	/* virtual CPU number */
+    int state;			/* value from virVcpuState */
+    unsigned long long cpuTime; /* CPU time used, in nanoseconds */
+    int cpu;			/* real CPU number, or -1 if offline */
+};
+typedef virVcpuInfo *virVcpuInfoPtr;
+
+int			virDomainSetVcpus	(virDomainPtr domain,
+						 unsigned int nvcpus);
+
+int			virDomainPinVcpu	(virDomainPtr domain,
+						 unsigned int vcpu,
+						 unsigned char *cpumap,
+						 int maplen);
+
+/**
+ * USE_CPU:
+ * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN/OUT)
+ * @cpu: the physical CPU number
+ *
+ * This macro is to be used in conjonction with virDomainPinVcpu() API.
+ * USE_CPU macro set the bit (CPU usable) of the related cpu in cpumap.
+ */
+
+#define USE_CPU(cpumap,cpu)	(cpumap[(cpu)/8] |= (1<<((cpu)%8)))
+
+/**
+ * UNUSE_CPU:
+ * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN/OUT)
+ * @cpu: the physical CPU number
+ *
+ * This macro is to be used in conjonction with virDomainPinVcpu() API.
+ * USE_CPU macro reset the bit (CPU not usable) of the related cpu in cpumap.
+ */
+
+#define UNUSE_CPU(cpumap,cpu)	(cpumap[(cpu)/8] &= ~(1<<((cpu)%8)))
+
+int			virDomainGetVcpus	(virDomainPtr domain,
+						 virVcpuInfoPtr info,
+						 int maxinfo,
+						 unsigned char *cpumaps,
+						 int maplen);
+
+/**
+ * CPU_USABLE:
+ * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN)
+ * @maplen: the length (in bytes) of one cpumap
+ * @vcpu: the virtual CPU number
+ * @cpu: the physical CPU number
+ *
+ * This macro is to be used in conjonction with virDomainGetVcpus() API.
+ * CPU_USABLE macro returns a non zero value (true) if the cpu
+ * is usable by the vcpu, and 0 otherwise.
+ */
+
+#define CPU_USABLE(cpumaps,maplen,vcpu,cpu) \
+	(cpumaps[((vcpu)*(maplen))+((cpu)/8)] & (1<<((cpu)%8)))
+
+/**
+ * COPY_CPUMAP:
+ * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN)
+ * @maplen: the length (in bytes) of one cpumap
+ * @vcpu: the virtual CPU number
+ * @cpumap: pointer to a cpumap (in 8-bit bytes) (OUT)
+ *	This cpumap must be previously allocated by the caller (ie: malloc(maplen))
+ *
+ * This macro is to be used in conjonction with virDomainGetVcpus() and
+ * virDomainPinVcpu() APIs. COPY_CPUMAP macro extract the cpumap of the specified
+ * vcpu from cpumaps array and copy it into cpumap to be used later by virDomainPinVcpu() API.
+ */
+#define COPY_CPUMAP(cpumaps,maplen,vcpu,cpumap) \
+	memcpy(cpumap, &(cpumaps[(vcpu)*(maplen)]), (maplen))
+
+
+/**
+ * GET_CPUMAP:
+ * @cpumaps: pointer to an array of cpumap (in 8-bit bytes) (IN)
+ * @maplen: the length (in bytes) of one cpumap
+ * @vcpu: the virtual CPU number
+ *
+ * This macro is to be used in conjonction with virDomainGetVcpus() and
+ * virDomainPinVcpu() APIs. GET_CPUMAP macro returns a pointer to the cpumap
+ * of the specified vcpu from cpumaps array.
+ */
+#define GET_CPUMAP(cpumaps,maplen,vcpu)		&(cpumaps[(vcpu)*(maplen)])
+
 
 #ifdef __cplusplus
 }
--- libvirt-0.1.3/src/xen_internal.h	2006-07-03 17:09:24.000000000 +0200
+++ libvirt-0.1.3.with_vcpus/src/xen_internal.h	2006-08-02 16:53:42.000000000 +0200
@@ -44,6 +44,18 @@
 		      		  	 unsigned long memory);
 int	xenHypervisorCheckID		(virConnectPtr conn,
 					 int id);
+int	xenHypervisorSetVcpus		(virDomainPtr domain,
+					 unsigned int nvcpus);
+int	xenHypervisorPinVcpu		(virDomainPtr domain,
+					 unsigned int vcpu,
+					 unsigned char *cpumap,
+					 int maplen);
+int	xenHypervisorGetVcpus		(virDomainPtr domain,
+					 virVcpuInfoPtr info,
+					 int maxinfo,
+					 unsigned char *cpumaps,
+					 int maplen);
+
 #ifdef __cplusplus
 }
 #endif
--- libvirt-0.1.3/src/xen_internal.c	2006-07-03 17:09:24.000000000 +0200
+++ libvirt-0.1.3.with_vcpus/src/xen_internal.c	2006-08-03 13:52:28.000000000 +0200
@@ -18,7 +18,7 @@
 #include <fcntl.h>
 #include <sys/mman.h>
 #include <sys/ioctl.h>
-
+#include <limits.h>
 #include <stdint.h>
 
 /* required for dom0_getdomaininfo_t */
@@ -838,4 +838,138 @@
 
     return (0);
 }
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * xenHypervisorSetVcpus:
+ * @domain: pointer to domain object
+ * @nvcpus: the new number of virtual CPUs for this domain
+ *
+ * Dynamically change the number of virtual CPUs used by the domain.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+
+int
+xenHypervisorSetVcpus(virDomainPtr domain, unsigned int nvcpus)
+{
+    dom0_op_t op;
+
+    if ((domain == NULL) || (domain->conn == NULL) || (domain->conn->handle < 0)
+     || (nvcpus < 1))
+        return (-1);
+    op.cmd = DOM0_MAX_VCPUS;
+    op.u.max_vcpus.domain = (domid_t) domain->handle;
+    op.u.max_vcpus.max = nvcpus;
+    if (xenHypervisorDoOp(domain->conn->handle, &op) < 0)
+        return (-1);
+    return 0;
+}
+
+/**
+ * xenHypervisorPinVcpu:
+ * @domain: pointer to domain object
+ * @vcpu: virtual CPU number
+ * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes)
+ * @maplen: length of cpumap in bytes
+ * 
+ * Dynamically change the real CPUs which can be allocated to a virtual CPU.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+
+int
+xenHypervisorPinVcpu(virDomainPtr domain, unsigned int vcpu,
+                     unsigned char *cpumap, int maplen)
+{
+    dom0_op_t op;
+    uint64_t *pm = (uint64_t *)&op.u.setvcpuaffinity.cpumap; 
+    int j;
+
+    if ((domain == NULL) || (domain->conn == NULL) || (domain->conn->handle < 0)
+     || (cpumap == NULL) || (maplen < 1) || (maplen > (int)sizeof(cpumap_t))
+     || (sizeof(cpumap_t) & 7))
+        return (-1);
+    op.cmd = DOM0_SETVCPUAFFINITY;
+    op.u.setvcpuaffinity.domain = (domid_t) domain->handle;
+    op.u.setvcpuaffinity.vcpu = vcpu;
+    memset(pm, 0, sizeof(cpumap_t));
+    for (j = 0; j < maplen; j++)
+        *(pm + (j / 8)) |= cpumap[j] << (8 * (j & 7));
+    if (xenHypervisorDoOp(domain->conn->handle, &op) < 0)
+        return (-1);
+    return 0;
+}
 
+/**
+ * virDomainGetVcpus:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @info: pointer to an array of virVcpuInfo structures (OUT)
+ * @maxinfo: number of structures in info array
+ * @cpumaps: pointer to an bit map of real CPUs for all vcpus of this domain (in 8-bit bytes) (OUT)
+ *	If cpumaps is NULL, then no cupmap information is returned by the API.
+ *	It's assumed there is <maxinfo> cpumap in cpumaps array.
+ *	The memory allocated to cpumaps must be (maxinfo * maplen) bytes
+ *	(ie: calloc(maxinfo, maplen)).
+ *	One cpumap inside cpumaps has the format described in virDomainPinVcpu() API.
+ * @maplen: number of bytes in one cpumap, from 1 up to size of CPU map in
+ *	underlying virtualization system (Xen...).
+ * 
+ * Extract information about virtual CPUs of domain, store it in info array
+ * and also in cpumaps if this pointer is'nt NULL.
+ *
+ * Returns the number of info filled in case of success, -1 in case of failure.
+ */
+int
+xenHypervisorGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo,
+		      unsigned char *cpumaps, int maplen)
+{
+    dom0_op_t op;
+    uint64_t *pm = (uint64_t *)&op.u.getvcpuinfo.cpumap; 
+    virVcpuInfoPtr ipt;
+    int nbinfo, mapl, i;
+    unsigned char *cpumap;
+    int vcpu, cpu;
+
+    if ((domain == NULL) || (domain->conn == NULL) || (domain->conn->handle < 0)
+     || (info == NULL) || (maxinfo < 1)
+     || (sizeof(cpumap_t) & 7))
+        return (-1);
+    if (cpumaps != NULL && maplen < 1)
+	return -1;
+
+    /* first get the number of virtual CPUs in this domain */
+    op.cmd = DOM0_GETDOMAININFO;
+    op.u.getdomaininfo.domain = (domid_t) domain->handle;
+    if (xenHypervisorDoOp(domain->conn->handle, &op) < 0)
+        return (-1);
+    nbinfo = (int)op.u.getdomaininfo.max_vcpu_id + 1;
+    if (nbinfo > maxinfo) nbinfo = maxinfo;
+
+    if (cpumaps != NULL)
+	memset(cpumaps, 0, maxinfo * maplen);
+
+    op.cmd = DOM0_GETVCPUINFO;
+    for (i=0, ipt=info; i < nbinfo; i++, ipt++) {
+        vcpu = op.u.getvcpuinfo.vcpu = i;
+        if (xenHypervisorDoOp(domain->conn->handle, &op) < 0)
+            return (-1);
+        ipt->number = i;
+        if (op.u.getvcpuinfo.online) {
+            if (op.u.getvcpuinfo.running) ipt->state = VIR_VCPU_RUNNING;
+            if (op.u.getvcpuinfo.blocked) ipt->state = VIR_VCPU_BLOCKED;
+        }
+        else ipt->state = VIR_VCPU_OFFLINE;
+        ipt->cpuTime = op.u.getvcpuinfo.cpu_time;
+        ipt->cpu = op.u.getvcpuinfo.online ? (int)op.u.getvcpuinfo.cpu : -1;
+	if (cpumaps != NULL && vcpu >= 0 && vcpu < maxinfo) {
+	    cpumap = (unsigned char *)GET_CPUMAP(cpumaps, maplen, vcpu);
+	    mapl = (maplen > (int)sizeof(cpumap_t)) ? (int)sizeof(cpumap_t) : maplen;
+            for (cpu = 0; cpu < (mapl * CHAR_BIT); cpu++) {
+		if (*pm & ((uint64_t)1<<cpu))
+		    USE_CPU(cpumap, cpu);
+	    }
+	}
+    }
+    return nbinfo;
+}
--- libvirt-0.1.3/src/libvirt.c	2006-07-03 17:09:24.000000000 +0200
+++ libvirt-0.1.3.with_vcpus/src/libvirt.c	2006-08-02 15:30:29.000000000 +0200
@@ -1648,4 +1648,126 @@
     
     return(-1);
 }
+///////////////////////////////////////////////////////////////////////////
 
+/**
+ * virDomainSetVcpus:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @nvcpus: the new number of virtual CPUs for this domain
+ *
+ * Dynamically change the number of virtual CPUs used by the domain.
+ * Note that this call may fail if the underlying virtualization hypervisor
+ * does not support it or if growing the number is arbitrary limited.
+ * This function requires priviledged access to the hypervisor.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+
+int
+virDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus)
+{
+    if (domain == NULL) {
+        TODO
+	return (-1);
+    }
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        return (-1);
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO)
+        return (-1);
+    if (nvcpus < 1) {
+        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return (-1);
+    }
+//    if (xenHypervisorSetVcpus(domain, nvcpus) == 0)
+//        return 0;
+    return xenDaemonDomainSetVcpus(domain, nvcpus);
+}
+
+/**
+ * virDomainPinVcpu:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @vcpu: virtual CPU number
+ * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN)
+ * 	Each bit set to 1 means that corresponding CPU is usable.
+ * 	Bytes are stored in little-endian order: CPU0-7, 8-15...
+ * 	In each byte, lowest CPU number is least significant bit.
+ * @maplen: number of bytes in cpumap, from 1 up to size of CPU map in
+ *	underlying virtualization system (Xen...).
+ *	If maplen < size, missing bytes are set to zero.
+ *	If maplen > size, failure code is returned.
+ * 
+ * Dynamically change the real CPUs which can be allocated to a virtual CPU.
+ * This function requires priviledged access to the hypervisor.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
+                 unsigned char *cpumap, int maplen)
+{
+    if (domain == NULL) {
+        TODO
+	return (-1);
+    }
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        return (-1);
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO)
+        return (-1);
+    if ((vcpu < 1) || (cpumap == NULL) || (maplen < 1)) {
+        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return (-1);
+    }
+    if (xenHypervisorPinVcpu(domain, vcpu, cpumap, maplen) == 0)
+        return 0;
+    return (-1); //xenDaemonDomainPinVcpu(domain, vcpu, cpumap, maplen);
+}
+
+/**
+ * virDomainGetVcpus:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @info: pointer to an array of virVcpuInfo structures (OUT)
+ * @maxinfo: number of structures in info array
+ * @cpumaps: pointer to an bit map of real CPUs for all vcpus of this domain (in 8-bit bytes) (OUT)
+ *	If cpumaps is NULL, then no cupmap information is returned by the API.
+ *	It's assumed there is <maxinfo> cpumap in cpumaps array.
+ *	The memory allocated to cpumaps must be (maxinfo * maplen) bytes
+ *	(ie: calloc(maxinfo, maplen)).
+ *	One cpumap inside cpumaps has the format described in virDomainPinVcpu() API.
+ * @maplen: number of bytes in one cpumap, from 1 up to size of CPU map in
+ *	underlying virtualization system (Xen...).
+ * 
+ * Extract information about virtual CPUs of domain, store it in info array
+ * and also in cpumaps if this pointer is'nt NULL.
+ *
+ * Returns the number of info filled in case of success, -1 in case of failure.
+ */
+int
+virDomainGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo,
+		  unsigned char *cpumaps, int maplen)
+{
+    int ret;
+
+    if (domain == NULL) {
+        TODO
+	return (-1);
+    }
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        return (-1);
+    }
+    if ((info == NULL) || (maxinfo < 1)) {
+        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return (-1);
+    }
+    if (cpumaps != NULL && maplen < 1) {
+        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return (-1);
+    }
+    ret = xenHypervisorGetVcpus(domain, info, maxinfo, cpumaps, maplen);
+    if (ret != -1) return ret;
+    return xenDaemonDomainGetVcpus(domain, info, maxinfo, cpumaps, maplen);
+}
--- libvirt-0.1.3/src/xend_internal.h	2006-07-10 12:24:05.000000000 +0200
+++ libvirt-0.1.3.with_vcpus/src/xend_internal.h	2006-08-02 16:54:27.000000000 +0200
@@ -631,6 +631,18 @@
 unsigned long xenDaemonDomainGetMaxMemory(virDomainPtr domain);
 char **xenDaemonListDomainsOld(virConnectPtr xend);
 
+int	xenDaemonDomainSetVcpus		(virDomainPtr domain,
+					 int vcpus);
+int	xenDaemonDomainPinVcpu		(virDomainPtr domain,
+					 unsigned int vcpu,
+					 unsigned char *cpumap,
+					 int maplen);
+int	xenDaemonDomainGetVcpus		(virDomainPtr domain,
+					 virVcpuInfoPtr info,
+					 int maxinfo,
+					 unsigned char *cpumaps,
+					 int maplen);
+
 #ifdef __cplusplus
 }
 #endif
--- libvirt-0.1.3/src/libvirt_sym.version	2006-05-29 18:19:30.000000000 +0200
+++ libvirt-0.1.3.with_vcpus/src/libvirt_sym.version	2006-08-02 15:26:56.000000000 +0200
@@ -47,5 +47,9 @@
 	virConnResetLastError;
 	virDefaultErrorFunc;
 	virNodeGetInfo;
+
+	virDomainSetVcpus;
+	virDomainPinVcpu;
+	virDomainGetVcpus;
     local: *;
 };
--- libvirt-0.1.3/src/xend_internal.c	2006-07-10 16:41:54.000000000 +0200
+++ libvirt-0.1.3.with_vcpus/src/xend_internal.c	2006-08-02 16:48:24.000000000 +0200
@@ -2429,6 +2429,156 @@
       free(name);
     return (NULL);
 }
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ * xenDaemonDomainSetVcpus:
+ * @domain: pointer to domain object
+ * @nvcpus: the new number of virtual CPUs for this domain
+ *
+ * Dynamically change the number of virtual CPUs used by the domain.
+ *
+ * Returns 0 for success; -1 (with errno) on error
+ */
+int
+xenDaemonDomainSetVcpus(virDomainPtr domain, int vcpus)
+{
+    char buf[16];
+
+    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
+     || (vcpus < 1)) {
+        virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+	             __FUNCTION__);
+        return (-1);
+    }
+    snprintf(buf, sizeof(buf), "%d", vcpus);
+    return xend_op(domain->conn, domain->name, "op", "set_vcpus", "vcpus",
+                   buf, NULL);
+}
+
+/**
+ * xenDaemonDomainPinCpu:
+ * @domain: pointer to domain object
+ * @vcpu: virtual CPU number
+ * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes)
+ * @maplen: length of cpumap in bytes
+ * 
+ * Dynamically change the real CPUs which can be allocated to a virtual CPU.
+ *
+ * Returns 0 for success; -1 (with errno) on error
+ */
+int
+xenDaemonDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
+                     unsigned char *cpumap, int maplen)
+{
+    char buf[16], mapstr[sizeof(cpumap_t) * 64] = "[";
+    int i, j;
+
+    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
+     || (cpumap == NULL) || (maplen < 1) || (maplen > (int)sizeof(cpumap_t))) {
+        virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+	             __FUNCTION__);
+        return (-1);
+    }
+
+    /* from bit map, build character string of mapped CPU numbers */
+    for (i = 0; i < maplen; i++) for (j = 0; j < 8; j++)
+     if (cpumap[i] & (1 << j)) {
+        sprintf(buf, "%d,", (8 * i) + j);
+        strcat(mapstr, buf);
+    }
+    mapstr[strlen(mapstr) - 1] = ']';
+    snprintf(buf, sizeof(buf), "%d", vcpu);
+    return xend_op(domain->conn, domain->name, "op", "pincpu", "vcpu", buf,
+                  "cpumap", mapstr, NULL);
+}
+
+/**
+ * virDomainGetVcpus:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @info: pointer to an array of virVcpuInfo structures (OUT)
+ * @maxinfo: number of structures in info array
+ * @cpumaps: pointer to an bit map of real CPUs for all vcpus of this domain (in 8-bit bytes) (OUT)
+ *	If cpumaps is NULL, then no cupmap information is returned by the API.
+ *	It's assumed there is <maxinfo> cpumap in cpumaps array.
+ *	The memory allocated to cpumaps must be (maxinfo * maplen) bytes
+ *	(ie: calloc(maxinfo, maplen)).
+ *	One cpumap inside cpumaps has the format described in virDomainPinVcpu() API.
+ * @maplen: number of bytes in one cpumap, from 1 up to size of CPU map in
+ *	underlying virtualization system (Xen...).
+ * 
+ * Extract information about virtual CPUs of domain, store it in info array
+ * and also in cpumaps if this pointer is'nt NULL.
+ *
+ * Returns the number of info filled in case of success, -1 in case of failure.
+ */
+int
+xenDaemonDomainGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo,
+			unsigned char *cpumaps, int maplen)
+{
+    struct sexpr *root, *s, *t;
+    virVcpuInfoPtr ipt = info;
+    int nbinfo = 0, oln;
+    unsigned char *cpumap;
+    int vcpu, cpu;
+
+    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
+     || (info == NULL) || (maxinfo < 1)) {
+        virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+	             __FUNCTION__);
+        return (-1);
+    }
+    if (cpumaps != NULL && maplen < 1) {
+        virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+	             __FUNCTION__);
+        return (-1);
+    }
+    root = sexpr_get(domain->conn, "/xend/domain/%s?op=vcpuinfo", domain->name);
+    if (root == NULL)
+        return (-1);
+
+    if (cpumaps != NULL)
+	memset(cpumaps, 0, maxinfo * maplen);
+
+    /* scan the sexprs from "(vcpu (number x)...)" and get parameter values */
+    for (s = root; s->kind == SEXPR_CONS; s = s->cdr)
+     if ((s->car->kind == SEXPR_CONS) &&
+	 (s->car->car->kind == SEXPR_VALUE) &&
+	 !strcmp(s->car->car->value, "vcpu")) {
+        t = s->car;
+        vcpu = ipt->number = sexpr_int(t, "vcpu/number");
+        if (oln = sexpr_int(t, "vcpu/online")) {
+            if (sexpr_int(t, "vcpu/running")) ipt->state = VIR_VCPU_RUNNING;
+            if (sexpr_int(t, "vcpu/blocked")) ipt->state = VIR_VCPU_BLOCKED;
+        }
+        else ipt->state = VIR_VCPU_OFFLINE;
+        ipt->cpuTime = sexpr_float(t, "vcpu/cpu_time") * 1000000000;
+        ipt->cpu = oln ? sexpr_int(t, "vcpu/cpu") : -1;
+
+	if (cpumaps != NULL && vcpu >= 0 && vcpu < maxinfo) {
+	    cpumap = (unsigned char *)GET_CPUMAP(cpumaps, maplen, vcpu);
+            /* get sexpr from "(cpumap (x y z...))" and convert values to bitmap */
+            for (t = t->cdr; t->kind == SEXPR_CONS; t = t->cdr)
+             if ((t->car->kind == SEXPR_CONS) &&
+	     	 (t->car->car->kind == SEXPR_VALUE) &&
+		 !strcmp(t->car->car->value, "cpumap") &&
+		 (t->car->cdr->kind == SEXPR_CONS)) {
+        	for (t = t->car->cdr->car; t->kind == SEXPR_CONS; t = t->cdr)
+        	 if (t->car->kind == SEXPR_VALUE) {
+                    cpu = strtol(t->car->value, NULL, 0);
+		    if (cpu >= 0)
+			USE_CPU(cpumap, cpu);
+        	}
+        	break;
+            }
+	}
+
+        if (++nbinfo == maxinfo) break;
+        ipt++;
+    }
+    sexpr_free(root);
+    return nbinfo;
+}
 
 /**
  * xenDaemonLookupByUUID:

[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]