With the domain events code, the callbacks triggered upon events get given
a virDomainPtr object instance. In many cases it'd be desirable to grab
this object and keep it in your app code. Unfortunately it is free'd the
moment the callback finishes executing.
When allowing multiple threads to access a single virConnectPtr object
it is neccessary to ensure no thread releases it (virConnectCLose) while
another thread is still using it.
The way to address both of these problems is to allow an application to
take an explicit reference on the object in question. So this patch
exposes methods to allow an app to increment the ref count on all our
public objects. To release the ref count, the existing virConectClose/
virDOmainFree, etc methods suffice
include/libvirt/libvirt.h | 6 +
include/libvirt/libvirt.h.in | 6 +
src/libvirt.c | 183 +++++++++++++++++++++++++++++++++++++++++++
src/libvirt_public.syms | 12 ++
4 files changed, 206 insertions(+), 1 deletion(-)
Daniel
diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h
--- a/include/libvirt/libvirt.h
+++ b/include/libvirt/libvirt.h
@@ -396,6 +396,7 @@ virConnectPtr virConnectOpenAu
virConnectPtr virConnectOpenAuth (const char *name,
virConnectAuthPtr auth,
int flags);
+int virConnectRef (virConnectPtr conn);
int virConnectClose (virConnectPtr conn);
const char * virConnectGetType (virConnectPtr conn);
int virConnectGetVersion (virConnectPtr conn,
@@ -453,6 +454,7 @@ int virDomainReboot
int virDomainReboot (virDomainPtr domain,
unsigned int flags);
int virDomainDestroy (virDomainPtr domain);
+int virDomainRef (virDomainPtr domain);
int virDomainFree (virDomainPtr domain);
/*
@@ -765,6 +767,7 @@ int virNetworkCreate
* Network destroy/free
*/
int virNetworkDestroy (virNetworkPtr network);
+int virNetworkRef (virNetworkPtr network);
int virNetworkFree (virNetworkPtr network);
/*
@@ -925,6 +928,7 @@ int virStoragePoolDe
int virStoragePoolDestroy (virStoragePoolPtr pool);
int virStoragePoolDelete (virStoragePoolPtr pool,
unsigned int flags);
+int virStoragePoolRef (virStoragePoolPtr pool);
int virStoragePoolFree (virStoragePoolPtr pool);
int virStoragePoolRefresh (virStoragePoolPtr pool,
unsigned int flags);
@@ -978,6 +982,7 @@ virStorageVolPtr virStorageVolCre
unsigned int flags);
int virStorageVolDelete (virStorageVolPtr vol,
unsigned int flags);
+int virStorageVolRef (virStorageVolPtr vol);
int virStorageVolFree (virStorageVolPtr vol);
int virStorageVolGetInfo (virStorageVolPtr vol,
@@ -1045,6 +1050,7 @@ char * virNodeDeviceGet
char * virNodeDeviceGetXMLDesc (virNodeDevicePtr dev,
unsigned int flags);
+int virNodeDeviceRef (virNodeDevicePtr dev);
int virNodeDeviceFree (virNodeDevicePtr dev);
/*
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -396,6 +396,7 @@ virConnectPtr virConnectOpenAu
virConnectPtr virConnectOpenAuth (const char *name,
virConnectAuthPtr auth,
int flags);
+int virConnectRef (virConnectPtr conn);
int virConnectClose (virConnectPtr conn);
const char * virConnectGetType (virConnectPtr conn);
int virConnectGetVersion (virConnectPtr conn,
@@ -453,6 +454,7 @@ int virDomainReboot
int virDomainReboot (virDomainPtr domain,
unsigned int flags);
int virDomainDestroy (virDomainPtr domain);
+int virDomainRef (virDomainPtr domain);
int virDomainFree (virDomainPtr domain);
/*
@@ -765,6 +767,7 @@ int virNetworkCreate
* Network destroy/free
*/
int virNetworkDestroy (virNetworkPtr network);
+int virNetworkRef (virNetworkPtr network);
int virNetworkFree (virNetworkPtr network);
/*
@@ -925,6 +928,7 @@ int virStoragePoolDe
int virStoragePoolDestroy (virStoragePoolPtr pool);
int virStoragePoolDelete (virStoragePoolPtr pool,
unsigned int flags);
+int virStoragePoolRef (virStoragePoolPtr pool);
int virStoragePoolFree (virStoragePoolPtr pool);
int virStoragePoolRefresh (virStoragePoolPtr pool,
unsigned int flags);
@@ -978,6 +982,7 @@ virStorageVolPtr virStorageVolCre
unsigned int flags);
int virStorageVolDelete (virStorageVolPtr vol,
unsigned int flags);
+int virStorageVolRef (virStorageVolPtr vol);
int virStorageVolFree (virStorageVolPtr vol);
int virStorageVolGetInfo (virStorageVolPtr vol,
@@ -1045,6 +1050,7 @@ char * virNodeDeviceGet
char * virNodeDeviceGetXMLDesc (virNodeDevicePtr dev,
unsigned int flags);
+int virNodeDeviceRef (virNodeDevicePtr dev);
int virNodeDeviceFree (virNodeDevicePtr dev);
/*
diff --git a/src/libvirt.c b/src/libvirt.c
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -1119,6 +1119,35 @@ virConnectClose(virConnectPtr conn)
return (0);
}
+/**
+ * virConnectRef:
+ * @conn: the connection to hold a reference on
+ *
+ * Increment the reference count on the connection. For each
+ * additional call to this method, there shall be a corresponding
+ * call to virConnectClose to release the reference count, once
+ * the caller no longer needs the reference to this object.
+ *
+ * This method is typically useful for applications where multiple
+ * threads are using a connection, and it is required that the
+ * connection remain open until all threads have finished using
+ * it. ie, each new thread using a connection would increment
+ * the reference count.
+ */
+int
+virConnectRef(virConnectPtr conn)
+{
+ if ((!VIR_IS_CONNECT(conn))) {
+ virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(-1);
+ }
+ virMutexLock(&conn->lock);
+ DEBUG("conn=%p refs=%d", conn, conn->refs);
+ conn->refs++;
+ virMutexUnlock(&conn->lock);
+ return 0;
+}
+
/*
* Not for public use. This function is part of the internal
* implementation of driver features in the remote case.
@@ -1775,6 +1804,36 @@ virDomainFree(virDomainPtr domain)
return -1;
return(0);
}
+
+/**
+ * virDomainRef:
+ * @conn: the domain to hold a reference on
+ *
+ * Increment the reference count on the domain. For each
+ * additional call to this method, there shall be a corresponding
+ * call to virDomainFree to release the reference count, once
+ * the caller no longer needs the reference to this object.
+ *
+ * This method is typically useful for applications where multiple
+ * threads are using a connection, and it is required that the
+ * connection remain open until all threads have finished using
+ * it. ie, each new thread using a domain would increment
+ * the reference count.
+ */
+int
+virDomainRef(virDomainPtr domain)
+{
+ if ((!VIR_IS_CONNECTED_DOMAIN(domain))) {
+ virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(-1);
+ }
+ virMutexLock(&domain->conn->lock);
+ DEBUG("domain=%p refs=%d", domain, domain->refs);
+ domain->refs++;
+ virMutexUnlock(&domain->conn->lock);
+ return 0;
+}
+
/**
* virDomainSuspend:
@@ -4814,6 +4873,35 @@ virNetworkFree(virNetworkPtr network)
}
/**
+ * virNetworkRef:
+ * @conn: the network to hold a reference on
+ *
+ * Increment the reference count on the network. For each
+ * additional call to this method, there shall be a corresponding
+ * call to virNetworkFree to release the reference count, once
+ * the caller no longer needs the reference to this object.
+ *
+ * This method is typically useful for applications where multiple
+ * threads are using a connection, and it is required that the
+ * connection remain open until all threads have finished using
+ * it. ie, each new thread using a network would increment
+ * the reference count.
+ */
+int
+virNetworkRef(virNetworkPtr network)
+{
+ if ((!VIR_IS_CONNECTED_NETWORK(network))) {
+ virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(-1);
+ }
+ virMutexLock(&network->conn->lock);
+ DEBUG("network=%p refs=%d", network, network->refs);
+ network->refs++;
+ virMutexUnlock(&network->conn->lock);
+ return 0;
+}
+
+/**
* virNetworkGetName:
* @network: a network object
*
@@ -5869,6 +5957,35 @@ virStoragePoolFree(virStoragePoolPtr poo
/**
+ * virStoragePoolRef:
+ * @conn: the pool to hold a reference on
+ *
+ * Increment the reference count on the pool. For each
+ * additional call to this method, there shall be a corresponding
+ * call to virStoragePoolFree to release the reference count, once
+ * the caller no longer needs the reference to this object.
+ *
+ * This method is typically useful for applications where multiple
+ * threads are using a connection, and it is required that the
+ * connection remain open until all threads have finished using
+ * it. ie, each new thread using a pool would increment
+ * the reference count.
+ */
+int
+virStoragePoolRef(virStoragePoolPtr pool)
+{
+ if ((!VIR_IS_CONNECTED_STORAGE_POOL(pool))) {
+ virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(-1);
+ }
+ virMutexLock(&pool->conn->lock);
+ DEBUG("pool=%p refs=%d", pool, pool->refs);
+ pool->refs++;
+ virMutexUnlock(&pool->conn->lock);
+ return 0;
+}
+
+/**
* virStoragePoolRefresh:
* @pool: pointer to storage pool
* @flags: flags to control refresh behaviour (currently unused, use 0)
@@ -6619,6 +6736,35 @@ virStorageVolFree(virStorageVolPtr vol)
return(0);
}
+
+/**
+ * virStorageVolRef:
+ * @conn: the vol to hold a reference on
+ *
+ * Increment the reference count on the vol. For each
+ * additional call to this method, there shall be a corresponding
+ * call to virStorageVolFree to release the reference count, once
+ * the caller no longer needs the reference to this object.
+ *
+ * This method is typically useful for applications where multiple
+ * threads are using a connection, and it is required that the
+ * connection remain open until all threads have finished using
+ * it. ie, each new thread using a vol would increment
+ * the reference count.
+ */
+int
+virStorageVolRef(virStorageVolPtr vol)
+{
+ if ((!VIR_IS_CONNECTED_STORAGE_VOL(vol))) {
+ virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(-1);
+ }
+ virMutexLock(&vol->conn->lock);
+ DEBUG("vol=%p refs=%d", vol, vol->refs);
+ vol->refs++;
+ virMutexUnlock(&vol->conn->lock);
+ return 0;
+}
/**
* virStorageVolGetInfo:
@@ -7093,6 +7239,36 @@ int virNodeDeviceFree(virNodeDevicePtr d
}
+/**
+ * virNodeDeviceRef:
+ * @conn: the dev to hold a reference on
+ *
+ * Increment the reference count on the dev. For each
+ * additional call to this method, there shall be a corresponding
+ * call to virNodeDeviceFree to release the reference count, once
+ * the caller no longer needs the reference to this object.
+ *
+ * This method is typically useful for applications where multiple
+ * threads are using a connection, and it is required that the
+ * connection remain open until all threads have finished using
+ * it. ie, each new thread using a dev would increment
+ * the reference count.
+ */
+int
+virNodeDeviceRef(virNodeDevicePtr dev)
+{
+ if ((!VIR_IS_CONNECTED_NODE_DEVICE(dev))) {
+ virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(-1);
+ }
+ virMutexLock(&dev->conn->lock);
+ DEBUG("dev=%p refs=%d", dev, dev->refs);
+ dev->refs++;
+ virMutexUnlock(&dev->conn->lock);
+ return 0;
+}
+
+
/*
* Domain Event Notification
*/
@@ -7107,6 +7283,13 @@ int virNodeDeviceFree(virNodeDevicePtr d
* Adds a Domain Event Callback.
* Registering for a domain callback will enable delivery of the events
*
+ * The virDomainPtr object handle passed into the callback upon delivery
+ * of an event is only valid for the duration of execution of the callback.
+ * If the callback wishes to keep the domain object after the callback
+ * returns, it shall take a reference to it, by calling virDomainRef.
+ * The reference can be released once the object is no longer required
+ * by calling virDomainFree.
+ *
* Returns 0 on success, -1 on failure
*/
int
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -236,5 +236,15 @@ LIBVIRT_0.5.0 {
} LIBVIRT_0.4.5;
-# no new entry point in 0.5.1
+LIBVIRT_0.6.0 {
+ global:
+ virConnectRef;
+ virDomainRef;
+ virNetworkRef;
+ virStoragePoolRef;
+ virStorageVolRef;
+ virNodeDeviceRef;
+
+} LIBVIRT_0.5.0;
+
# .... define new API here using predicted next version number ....
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|