mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-28 03:21:19 +00:00
virclosecallbacks: Add new close callbacks APIs
The new APIs store the list of callbacks for a VM inside the virDomainObj and also allow registering multiple callbacks for a single domain and also for multiple connections. For now this code is dormant until each driver using the old APIs is not refactored to use the new APIs. Signed-off-by: Peter Krempa <pkrempa@redhat.com> Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
This commit is contained in:
parent
2cb13113c2
commit
cb195c19b7
@ -310,3 +310,339 @@ virCloseCallbacksRun(virCloseCallbacks *closeCallbacks,
|
|||||||
VIR_FREE(list->entries);
|
VIR_FREE(list->entries);
|
||||||
VIR_FREE(list);
|
VIR_FREE(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct _virCloseCallbacksDomainData {
|
||||||
|
virConnectPtr conn;
|
||||||
|
virCloseCallback cb;
|
||||||
|
};
|
||||||
|
typedef struct _virCloseCallbacksDomainData virCloseCallbacksDomainData;
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
virCloseCallbacksDomainDataFree(virCloseCallbacksDomainData* data)
|
||||||
|
{
|
||||||
|
g_free(data);
|
||||||
|
}
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCloseCallbacksDomainData, virCloseCallbacksDomainDataFree);
|
||||||
|
|
||||||
|
|
||||||
|
virClass *virCloseCallbacksDomainListClass;
|
||||||
|
|
||||||
|
struct _virCloseCallbacksDomainList {
|
||||||
|
virObjectLockable parent;
|
||||||
|
|
||||||
|
GList *callbacks;
|
||||||
|
};
|
||||||
|
typedef struct _virCloseCallbacksDomainList virCloseCallbacksDomainList;
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
virCloseCallbacksDomainListDispose(void *obj G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
virCloseCallbacksDomainList *cc = obj;
|
||||||
|
|
||||||
|
g_list_free_full(cc->callbacks, (GDestroyNotify) virCloseCallbacksDomainDataFree);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
virCloseCallbacksDomainListOnceInit(void)
|
||||||
|
{
|
||||||
|
if (!(VIR_CLASS_NEW(virCloseCallbacksDomainList, virClassForObjectLockable())))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VIR_ONCE_GLOBAL_INIT(virCloseCallbacksDomainList);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virCloseCallbacksDomainAlloc:
|
||||||
|
*
|
||||||
|
* Allocates and returns a data structure for holding close callback data in
|
||||||
|
* a virDomainObj.
|
||||||
|
*/
|
||||||
|
virObject *
|
||||||
|
virCloseCallbacksDomainAlloc(void)
|
||||||
|
{
|
||||||
|
if (virCloseCallbacksDomainListInitialize() < 0)
|
||||||
|
abort();
|
||||||
|
|
||||||
|
return virObjectNew(virCloseCallbacksDomainListClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virCloseCallbacksDomainAdd:
|
||||||
|
* @vm: domain object
|
||||||
|
* @conn: pointer to the connection which should trigger the close callback
|
||||||
|
* @cb: pointer to the callback function
|
||||||
|
*
|
||||||
|
* Registers @cb as a connection close callback for the @conn connection with
|
||||||
|
* the @vm domain. Duplicate registrations are ignored.
|
||||||
|
*
|
||||||
|
* Caller must hold lock on @vm.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
virCloseCallbacksDomainAdd(virDomainObj *vm,
|
||||||
|
virConnectPtr conn,
|
||||||
|
virCloseCallback cb)
|
||||||
|
{
|
||||||
|
virCloseCallbacksDomainList *cc = (virCloseCallbacksDomainList *) vm->closecallbacks;
|
||||||
|
|
||||||
|
if (!conn || !cb)
|
||||||
|
return;
|
||||||
|
|
||||||
|
VIR_WITH_OBJECT_LOCK_GUARD(cc) {
|
||||||
|
virCloseCallbacksDomainData *data;
|
||||||
|
GList *n;
|
||||||
|
|
||||||
|
for (n = cc->callbacks; n; n = n->next) {
|
||||||
|
data = n->data;
|
||||||
|
|
||||||
|
if (data->cb == cb && data->conn == conn)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = g_new0(virCloseCallbacksDomainData, 1);
|
||||||
|
data->conn = conn;
|
||||||
|
data->cb = cb;
|
||||||
|
|
||||||
|
cc->callbacks = g_list_prepend(cc->callbacks, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virCloseCallbacksDomainMatch:
|
||||||
|
* @data: pointer to a close callback data structure
|
||||||
|
* @conn: connection pointer matched against @data
|
||||||
|
* @cb: callback pointer matched against @data
|
||||||
|
*
|
||||||
|
* Returns true if the @data callback structure matches the requested @conn
|
||||||
|
* and/or @cb parameters. If either of @conn/@cb is NULL it is interpreted as
|
||||||
|
* a wildcard.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
virCloseCallbacksDomainMatch(virCloseCallbacksDomainData *data,
|
||||||
|
virConnectPtr conn,
|
||||||
|
virCloseCallback cb)
|
||||||
|
{
|
||||||
|
if (conn && cb)
|
||||||
|
return data->conn == conn && data->cb == cb;
|
||||||
|
|
||||||
|
if (conn)
|
||||||
|
return data->conn == conn;
|
||||||
|
|
||||||
|
if (cb)
|
||||||
|
return data->cb == cb;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virCloseCallbacksDomainIsRegistered:
|
||||||
|
* @vm: domain object
|
||||||
|
* @conn: connection pointer
|
||||||
|
* @cb: callback pointer
|
||||||
|
*
|
||||||
|
* Returns true if @vm has one or more matching (see virCloseCallbacksDomainMatch)
|
||||||
|
* callback(s) registered. Caller must hold lock on @vm.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
virCloseCallbacksDomainIsRegistered(virDomainObj *vm,
|
||||||
|
virConnectPtr conn,
|
||||||
|
virCloseCallback cb)
|
||||||
|
{
|
||||||
|
virCloseCallbacksDomainList *cc = (virCloseCallbacksDomainList *) vm->closecallbacks;
|
||||||
|
|
||||||
|
VIR_WITH_OBJECT_LOCK_GUARD(cc) {
|
||||||
|
GList *n;
|
||||||
|
|
||||||
|
for (n = cc->callbacks; n; n = n->next) {
|
||||||
|
virCloseCallbacksDomainData *data = n->data;
|
||||||
|
|
||||||
|
if (virCloseCallbacksDomainMatch(data, conn, cb))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virCloseCallbacksDomainRemove:
|
||||||
|
* @vm: domain object
|
||||||
|
* @conn: connection pointer
|
||||||
|
* @cb: callback pointer
|
||||||
|
*
|
||||||
|
* Removes all the registered matching (see virCloseCallbacksDomainMatch)
|
||||||
|
* callbacks for @vm. Caller must hold lock on @vm.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
virCloseCallbacksDomainRemove(virDomainObj *vm,
|
||||||
|
virConnectPtr conn,
|
||||||
|
virCloseCallback cb)
|
||||||
|
{
|
||||||
|
virCloseCallbacksDomainList *cc = (virCloseCallbacksDomainList *) vm->closecallbacks;
|
||||||
|
|
||||||
|
VIR_WITH_OBJECT_LOCK_GUARD(cc) {
|
||||||
|
GList *n = cc->callbacks;
|
||||||
|
|
||||||
|
while (n) {
|
||||||
|
GList *cur = n;
|
||||||
|
|
||||||
|
n = n->next;
|
||||||
|
|
||||||
|
if (virCloseCallbacksDomainMatch(cur->data, conn, cb)) {
|
||||||
|
cc->callbacks = g_list_remove_link(cc->callbacks, cur);
|
||||||
|
g_list_free_full(cur, (GDestroyNotify) virCloseCallbacksDomainDataFree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virCloseCallbacksDomainFetchForConn:
|
||||||
|
* @vm: domain object
|
||||||
|
* @conn: pointer to connection being closed
|
||||||
|
*
|
||||||
|
* Fetches connection close callbacks for @conn from @vm. The fetched close
|
||||||
|
* callbacks are removed from the list of callbacks of @vm. This function
|
||||||
|
* must be called with lock on @vm held. Caller is responsible for freeing the
|
||||||
|
* returned list.
|
||||||
|
*/
|
||||||
|
static GList *
|
||||||
|
virCloseCallbacksDomainFetchForConn(virDomainObj *vm,
|
||||||
|
virConnectPtr conn)
|
||||||
|
{
|
||||||
|
virCloseCallbacksDomainList *cc = (virCloseCallbacksDomainList *) vm->closecallbacks;
|
||||||
|
GList *conncallbacks = NULL;
|
||||||
|
|
||||||
|
VIR_WITH_OBJECT_LOCK_GUARD(cc) {
|
||||||
|
GList *n;
|
||||||
|
|
||||||
|
for (n = cc->callbacks; n;) {
|
||||||
|
virCloseCallbacksDomainData *data = n->data;
|
||||||
|
GList *cur = n;
|
||||||
|
|
||||||
|
n = n->next;
|
||||||
|
|
||||||
|
if (data->conn == conn) {
|
||||||
|
cc->callbacks = g_list_remove_link(cc->callbacks, cur);
|
||||||
|
conncallbacks = g_list_concat(cur, conncallbacks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return conncallbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virCloseCallbacksDomainRun
|
||||||
|
* @vm: domain object
|
||||||
|
* @conn: pointer to connection being closed
|
||||||
|
*
|
||||||
|
* Fetches and sequentially calls all connection close callbacks for @conn from
|
||||||
|
* @vm. This function must be called with lock on @vm held.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
virCloseCallbacksDomainRun(virDomainObj *vm,
|
||||||
|
virConnectPtr conn)
|
||||||
|
{
|
||||||
|
g_autolist(virCloseCallbacksDomainData) callbacks = NULL;
|
||||||
|
GList *n;
|
||||||
|
|
||||||
|
callbacks = virCloseCallbacksDomainFetchForConn(vm, conn);
|
||||||
|
|
||||||
|
for (n = callbacks; n; n = n->next) {
|
||||||
|
virCloseCallbacksDomainData *data = n->data;
|
||||||
|
|
||||||
|
VIR_DEBUG("vm='%s' cb='%p'", vm->def->name, data->cb);
|
||||||
|
|
||||||
|
(data->cb)(vm, conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virCloseCallbacksDomainHasCallbackForConn:
|
||||||
|
* @vm: domain object
|
||||||
|
* @conn: connection being closed
|
||||||
|
*
|
||||||
|
* Returns true if @vm has a callback registered for the @conn connection. This
|
||||||
|
* function doesn't require a lock being held on @vm.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
virCloseCallbacksDomainHasCallbackForConn(virDomainObj *vm,
|
||||||
|
virConnectPtr conn)
|
||||||
|
{
|
||||||
|
/* we can access vm->closecallbacks as it's a immutable pointer */
|
||||||
|
virCloseCallbacksDomainList *cc = (virCloseCallbacksDomainList *) vm->closecallbacks;
|
||||||
|
|
||||||
|
if (!cc)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
VIR_WITH_OBJECT_LOCK_GUARD(cc) {
|
||||||
|
GList *n;
|
||||||
|
|
||||||
|
for (n = cc->callbacks; n; n = n->next) {
|
||||||
|
virCloseCallbacksDomainData *data = n->data;
|
||||||
|
|
||||||
|
if (data->conn == conn)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virCloseCallbacksDomainRunForConn:
|
||||||
|
* @domains: domain list object
|
||||||
|
* @conn: connection being closed
|
||||||
|
*
|
||||||
|
* Finds all domains in @domains which registered one or more connection close
|
||||||
|
* callbacks for @conn and calls the callbacks. This function is designed to
|
||||||
|
* be called from virDrvConnectClose function of individual drivers.
|
||||||
|
*
|
||||||
|
* To minimize lock contention the function first fetches a list of all domain
|
||||||
|
* objects, then checks whether a connect close callback is actually registered
|
||||||
|
* for the domain object and just then acquires the lock on the VM object.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
virCloseCallbacksDomainRunForConn(virDomainObjList *domains,
|
||||||
|
virConnectPtr conn)
|
||||||
|
{
|
||||||
|
virDomainObj **vms = NULL;
|
||||||
|
size_t nvms;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
VIR_DEBUG("conn=%p", conn);
|
||||||
|
|
||||||
|
virDomainObjListCollectAll(domains, &vms, &nvms);
|
||||||
|
|
||||||
|
for (i = 0; i < nvms; i++) {
|
||||||
|
virDomainObj *vm = vms[i];
|
||||||
|
|
||||||
|
if (!virCloseCallbacksDomainHasCallbackForConn(vm, conn))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
VIR_WITH_OBJECT_LOCK_GUARD(vm) {
|
||||||
|
/* VIR_WITH_OBJECT_LOCK_GUARD is a for loop, so this break applies to that */
|
||||||
|
if (vm->removing)
|
||||||
|
break;
|
||||||
|
|
||||||
|
virCloseCallbacksDomainRun(vm, conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virObjectListFreeCount(vms, nvms);
|
||||||
|
}
|
||||||
|
@ -49,3 +49,27 @@ void
|
|||||||
virCloseCallbacksRun(virCloseCallbacks *closeCallbacks,
|
virCloseCallbacksRun(virCloseCallbacks *closeCallbacks,
|
||||||
virConnectPtr conn,
|
virConnectPtr conn,
|
||||||
virDomainObjList *domains);
|
virDomainObjList *domains);
|
||||||
|
|
||||||
|
/* ---- */
|
||||||
|
|
||||||
|
virObject *
|
||||||
|
virCloseCallbacksDomainAlloc(void);
|
||||||
|
|
||||||
|
void
|
||||||
|
virCloseCallbacksDomainAdd(virDomainObj *vm,
|
||||||
|
virConnectPtr conn,
|
||||||
|
virCloseCallback cb);
|
||||||
|
|
||||||
|
void
|
||||||
|
virCloseCallbacksDomainRemove(virDomainObj *vm,
|
||||||
|
virConnectPtr conn,
|
||||||
|
virCloseCallback cb);
|
||||||
|
|
||||||
|
bool
|
||||||
|
virCloseCallbacksDomainIsRegistered(virDomainObj *vm,
|
||||||
|
virConnectPtr conn,
|
||||||
|
virCloseCallback cb);
|
||||||
|
|
||||||
|
void
|
||||||
|
virCloseCallbacksDomainRunForConn(virDomainObjList *domains,
|
||||||
|
virConnectPtr conn);
|
||||||
|
@ -1607,6 +1607,11 @@ virDomainDriverSetupPersistentDefBlkioParams;
|
|||||||
|
|
||||||
|
|
||||||
# hypervisor/virclosecallbacks.h
|
# hypervisor/virclosecallbacks.h
|
||||||
|
virCloseCallbacksDomainAdd;
|
||||||
|
virCloseCallbacksDomainAlloc;
|
||||||
|
virCloseCallbacksDomainIsRegistered;
|
||||||
|
virCloseCallbacksDomainRemove;
|
||||||
|
virCloseCallbacksDomainRunForConn;
|
||||||
virCloseCallbacksGet;
|
virCloseCallbacksGet;
|
||||||
virCloseCallbacksNew;
|
virCloseCallbacksNew;
|
||||||
virCloseCallbacksRun;
|
virCloseCallbacksRun;
|
||||||
|
Loading…
Reference in New Issue
Block a user