diff --git a/ChangeLog b/ChangeLog index 093b3785ce..0fa64ddb85 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Fri Nov 21 10:14:14 BST 2008 Daniel P. Berrange + + Fix crash due to failure to unregister event callbacks on + connection close (David Lively) + * src/domain_event.c, src/domain_event.h: Helper for unregistering + all callbacks + * src/qemu_driver.c: Unregister all callbacks on connection close + Fri Nov 21 10:10:14 BST 2008 Daniel P. Berrange * src/Makefile.am: Include Xen compile flags for libvirt_driver.la diff --git a/src/domain_event.c b/src/domain_event.c index 85ca9b7bd2..d5f54158c6 100644 --- a/src/domain_event.c +++ b/src/domain_event.c @@ -87,6 +87,44 @@ virDomainEventCallbackListRemove(virConnectPtr conn, return -1; } +/** + * virDomainEventCallbackListRemoveConn: + * @conn: pointer to the connection + * @cbList: the list + * + * Internal function to remove all of a given connection's callback + * from a virDomainEventCallbackListPtr + */ +int +virDomainEventCallbackListRemoveConn(virConnectPtr conn, + virDomainEventCallbackListPtr cbList) +{ + int old_count = cbList->count; + int i; + for (i = 0 ; i < cbList->count ; i++) { + if(cbList->callbacks[i]->conn == conn) { + virFreeCallback freecb = cbList->callbacks[i]->freecb; + if (freecb) + (*freecb)(cbList->callbacks[i]->opaque); + virUnrefConnect(cbList->callbacks[i]->conn); + VIR_FREE(cbList->callbacks[i]); + + if (i < (cbList->count - 1)) + memmove(cbList->callbacks + i, + cbList->callbacks + i + 1, + sizeof(*(cbList->callbacks)) * + (cbList->count - (i + 1))); + cbList->count--; + i--; + } + } + if (cbList->count < old_count && + VIR_REALLOC_N(cbList->callbacks, cbList->count) < 0) { + ; /* Failure to reduce memory allocation isn't fatal */ + } + return 0; +} + /** * virDomainEventCallbackListAdd: * @conn: pointer to the connection diff --git a/src/domain_event.h b/src/domain_event.h index cfec1e16cb..32ae0dbc47 100644 --- a/src/domain_event.h +++ b/src/domain_event.h @@ -55,6 +55,9 @@ int virDomainEventCallbackListRemove(virConnectPtr conn, virDomainEventCallbackListPtr cbList, virConnectDomainEventCallback callback); +int virDomainEventCallbackListRemoveConn(virConnectPtr conn, + virDomainEventCallbackListPtr cbList); + /** * Dispatching domain events that come in while * in a call / response rpc diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 5ad60f1dd2..7bec116bdc 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -1235,7 +1235,10 @@ static virDrvOpenStatus qemudOpen(virConnectPtr conn, } static int qemudClose(virConnectPtr conn) { - /*struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;*/ + struct qemud_driver *driver = (struct qemud_driver *)conn->privateData; + + /* Get rid of callbacks registered for this conn */ + virDomainEventCallbackListRemoveConn(conn, driver->domainEventCallbacks); conn->privateData = NULL;