[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]
Re: [libvirt] [PATCH 1/3] Domain events - primary implementation
- From: Ben Guthro <bguthro virtualiron com>
- To: libvir-list redhat com
- Subject: Re: [libvirt] [PATCH 1/3] Domain events - primary implementation
- Date: Thu, 09 Oct 2008 11:22:38 -0400
This patch is somewhat large, and touches many files.
However - please remember to ignore generated files
Signed-off-by: Ben Guthro <bguthro virtualiron com>
include/libvirt/libvirt.h | 44 ++++++
include/libvirt/libvirt.h.in | 44 ++++++
python/generator.py | 3
qemud/qemud.c | 2
qemud/qemud.h | 7 +
qemud/remote.c | 145 +++++++++++++++++++++
qemud/remote_dispatch_localvars.h | 3
qemud/remote_dispatch_proc_switch.h | 15 ++
qemud/remote_dispatch_prototypes.h | 2
qemud/remote_protocol.c | 31 ++++
qemud/remote_protocol.h | 25 +++
qemud/remote_protocol.x | 20 ++-
src/driver.h | 21 +++
src/event.c | 24 ++-
src/event.h | 23 +--
src/internal.h | 27 ++++
src/libvirt.c | 239 +++++++++++++++++++++++++++++++++---
src/libvirt_sym.version | 4
src/lxc_driver.c | 3
src/openvz_driver.c | 3
src/qemu_conf.h | 1
src/qemu_driver.c | 61 ++++++++-
src/remote_internal.c | 178 +++++++++++++++++++++++++-
src/test.c | 3
24 files changed, 878 insertions(+), 50 deletions(-)
diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h
index d519452..9b6e1da 100644
--- a/include/libvirt/libvirt.h
+++ b/include/libvirt/libvirt.h
@@ -987,6 +987,50 @@ char * virStorageVolGetXMLDesc (virStorageVolPtr pool,
char * virStorageVolGetPath (virStorageVolPtr vol);
+/*
+ * Domain Event Notification
+ */
+
+typedef enum {
+ VIR_DOMAIN_EVENT_ADDED,
+ VIR_DOMAIN_EVENT_REMOVED,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_SUSPENDED,
+ VIR_DOMAIN_EVENT_RESUMED,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_SAVED,
+ VIR_DOMAIN_EVENT_RESTORED,
+} virDomainEventType;
+
+typedef int (*virConnectDomainEventCallback)(virConnectPtr conn,
+ virDomainPtr dom,
+ int event,
+ void *opaque);
+
+int virConnectDomainEventRegister(virConnectPtr conn,
+ virConnectDomainEventCallback cb,
+ void *opaque);
+
+int virConnectDomainEventDeregister(virConnectPtr conn,
+ virConnectDomainEventCallback cb);
+
+/**
+ * virEventHandleCallback: callback for receiving file handle events
+ *
+ * @fd: file handle on which the event occurred
+ * @events: bitset of events from POLLnnn constants
+ * @opaque: user data registered with handle
+ */
+typedef void (*virEventHandleCallback)(int fd, int events, void *opaque);
+
+typedef int (*virEventAddHandleFunc)(int, int, virEventHandleCallback, void *);
+typedef void (*virEventUpdateHandleFunc)(int, int);
+typedef int (*virEventRemoveHandleFunc)(int);
+
+void virEventRegisterHandleImpl(virEventAddHandleFunc addHandle,
+ virEventUpdateHandleFunc updateHandle,
+ virEventRemoveHandleFunc removeHandle);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 24b5680..71f4797 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -987,6 +987,50 @@ char * virStorageVolGetXMLDesc (virStorageVolPtr pool,
char * virStorageVolGetPath (virStorageVolPtr vol);
+/*
+ * Domain Event Notification
+ */
+
+typedef enum {
+ VIR_DOMAIN_EVENT_ADDED,
+ VIR_DOMAIN_EVENT_REMOVED,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_SUSPENDED,
+ VIR_DOMAIN_EVENT_RESUMED,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_SAVED,
+ VIR_DOMAIN_EVENT_RESTORED,
+} virDomainEventType;
+
+typedef int (*virConnectDomainEventCallback)(virConnectPtr conn,
+ virDomainPtr dom,
+ int event,
+ void *opaque);
+
+int virConnectDomainEventRegister(virConnectPtr conn,
+ virConnectDomainEventCallback cb,
+ void *opaque);
+
+int virConnectDomainEventDeregister(virConnectPtr conn,
+ virConnectDomainEventCallback cb);
+
+/**
+ * virEventHandleCallback: callback for receiving file handle events
+ *
+ * @fd: file handle on which the event occurred
+ * @events: bitset of events from POLLnnn constants
+ * @opaque: user data registered with handle
+ */
+typedef void (*virEventHandleCallback)(int fd, int events, void *opaque);
+
+typedef int (*virEventAddHandleFunc)(int, int, virEventHandleCallback, void *);
+typedef void (*virEventUpdateHandleFunc)(int, int);
+typedef int (*virEventRemoveHandleFunc)(int);
+
+void virEventRegisterHandleImpl(virEventAddHandleFunc addHandle,
+ virEventUpdateHandleFunc updateHandle,
+ virEventRemoveHandleFunc removeHandle);
+
#ifdef __cplusplus
}
#endif
diff --git a/python/generator.py b/python/generator.py
index c706b19..6816cc3 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -332,6 +332,9 @@ skip_function = (
'virCopyLastError', # Python API is called virGetLastError instead
'virConnectOpenAuth', # Python C code is manually written
'virDefaultErrorFunc', # Python virErrorFuncHandler impl calls this from C
+ 'virConnectDomainEventRegister', # TODO: generate python bindings for these below XXX
+ 'virConnectDomainEventDeregister',
+ 'virEventRegisterHandleImpl',
)
diff --git a/qemud/qemud.c b/qemud/qemud.c
index 9da27d2..2d7e959 100644
--- a/qemud/qemud.c
+++ b/qemud/qemud.c
@@ -1503,7 +1503,7 @@ static int qemudClientWrite(struct qemud_server *server,
}
-static void qemudDispatchClientWrite(struct qemud_server *server, struct qemud_client *client) {
+void qemudDispatchClientWrite(struct qemud_server *server, struct qemud_client *client) {
switch (client->mode) {
case QEMUD_MODE_TX_PACKET: {
if (qemudClientWrite(server, client) < 0)
diff --git a/qemud/qemud.h b/qemud/qemud.h
index 91cb939..63784cd 100644
--- a/qemud/qemud.h
+++ b/qemud/qemud.h
@@ -132,6 +132,10 @@ struct qemud_client {
*/
virConnectPtr conn;
+ /* This client supports events, and has registered for at least
+ one event type. This is a bitmask of requested event types */
+ int events_registered;
+
struct qemud_client *next;
};
@@ -179,6 +183,9 @@ void qemudLog(int priority, const char *fmt, ...)
void remoteDispatchClientRequest (struct qemud_server *server,
struct qemud_client *client);
+void qemudDispatchClientWrite(struct qemud_server *server,
+ struct qemud_client *client);
+
#if HAVE_POLKIT
int qemudGetSocketIdentity(int fd, uid_t *uid, pid_t *pid);
#endif
diff --git a/qemud/remote.c b/qemud/remote.c
index 8acd95d..55ccc2c 100644
--- a/qemud/remote.c
+++ b/qemud/remote.c
@@ -75,6 +75,18 @@ typedef int (*dispatch_fn) (struct qemud_server *server,
char *args,
char *ret);
+/* Prototypes */
+static void
+remoteDispatchDomainEventSend (struct qemud_client *client,
+ virDomainPtr dom,
+ virDomainEventType event);
+
+static int
+remoteRelayDomainEvent (virConnectPtr conn,
+ virDomainPtr dom,
+ int event,
+ void *opaque);
+
/* This function gets called from qemud when it detects an incoming
* remote protocol message. At this point, client->buffer contains
* the full call message (including length word which we skip).
@@ -405,12 +417,33 @@ remoteDispatchError (struct qemud_client *client,
remoteDispatchSendError (client, req, VIR_ERR_RPC, msg);
}
+static int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ int event,
+ void *opaque)
+{
+ struct qemud_server *server = opaque;
+ REMOTE_DEBUG("Relaying domain event %d", event);
+
+ struct qemud_client *c = server->clients;
+ while(c) {
+ if ( c->conn == conn &&
+ (c->events_registered & virDomainEvent) ) {
+ remoteDispatchDomainEventSend (c, dom, event);
+ qemudDispatchClientWrite(server,c);
+ } else {
+ REMOTE_DEBUG("Event class %d not registered for client", virDomainEvent);
+ }
+ c = c->next;
+ }
+ return 0;
+}
/*----- Functions. -----*/
static int
-remoteDispatchOpen (struct qemud_server *server ATTRIBUTE_UNUSED,
+remoteDispatchOpen (struct qemud_server *server,
struct qemud_client *client, remote_message_header *req,
struct remote_open_args *args, void *ret ATTRIBUTE_UNUSED)
{
@@ -436,6 +469,11 @@ remoteDispatchOpen (struct qemud_server *server ATTRIBUTE_UNUSED,
? virConnectOpenReadOnly (name)
: virConnectOpen (name);
+ /* Register event delivery callback */
+ if(client->conn) {
+ REMOTE_DEBUG("%s","Registering to relay remote events");
+ virConnectDomainEventRegister(client->conn, remoteRelayDomainEvent, server);
+ }
return client->conn ? 0 : -1;
}
@@ -3620,6 +3658,111 @@ remoteDispatchStorageVolLookupByPath (struct qemud_server *server ATTRIBUTE_UNUS
}
+/**************************
+ * Async Events
+ **************************/
+static int remoteDispatchEventsDomainEvent (struct qemud_server *server ATTRIBUTE_UNUSED,
+ struct qemud_client *client ATTRIBUTE_UNUSED,
+ remote_message_header *req ATTRIBUTE_UNUSED,
+ void *args ATTRIBUTE_UNUSED,
+ remote_events_domain_event_ret *ret ATTRIBUTE_UNUSED)
+{
+ /* This call gets dispatched from a client call.
+ * This does not make sense, as this should not be intiated
+ * from the client side in generated code.
+ */
+ return -1;
+}
+
+/***************************
+ * Enabe / disable event classes
+ ***************************/
+static int remoteDispatchEventsEnable (struct qemud_server *server ATTRIBUTE_UNUSED,
+ struct qemud_client *client,
+ remote_message_header *req ATTRIBUTE_UNUSED,
+ remote_events_enable_args *args,
+ remote_events_enable_ret *ret)
+{
+ CHECK_CONN(client);
+ if(args->enable) {
+ client->events_registered |= args->event_class;
+ } else {
+ client->events_registered &= ~args->event_class;
+ }
+ ret->success = 1;
+ return 0;
+}
+
+static void
+remoteDispatchDomainEventSend (struct qemud_client *client,
+ virDomainPtr dom,
+ virDomainEventType event)
+{
+ remote_message_header rep;
+ XDR xdr;
+ int len;
+ remote_events_domain_event_ret data;
+
+ if(!client) {
+ remoteDispatchError (client, NULL, "%s", _("Invalid Client"));
+ return;
+ }
+
+ /* Future versions of the protocol may use different vers or prog. Try
+ * our hardest to send back a message that such clients could see.
+ */
+ rep.prog = REMOTE_PROGRAM;
+ rep.vers = REMOTE_PROTOCOL_VERSION;
+ rep.proc = REMOTE_PROC_EVENTS_DOMAIN_EVENT;
+ rep.direction = REMOTE_MESSAGE;
+ rep.serial = 1;
+ rep.status = REMOTE_OK;
+
+ /* Serialise the return header and event. */
+ xdrmem_create (&xdr, client->buffer, sizeof client->buffer, XDR_ENCODE);
+
+ len = 0; /* We'll come back and write this later. */
+ if (!xdr_int (&xdr, &len)) {
+ remoteDispatchError (client, NULL, "%s", _("xdr_int failed (1)"));
+ xdr_destroy (&xdr);
+ return;
+ }
+
+ if (!xdr_remote_message_header (&xdr, &rep)) {
+ xdr_destroy (&xdr);
+ return;
+ }
+
+ /* build return data */
+ make_nonnull_domain (&data.dom, dom);
+ data.event = (int) event;
+
+ if (!xdr_remote_events_domain_event_ret(&xdr, &data)) {
+ remoteDispatchError (client, NULL, "%s", _("serialise return struct"));
+ xdr_destroy (&xdr);
+ return;
+ }
+
+ len = xdr_getpos (&xdr);
+ if (xdr_setpos (&xdr, 0) == 0) {
+ remoteDispatchError (client, NULL, "%s", _("xdr_setpos failed"));
+ xdr_destroy (&xdr);
+ return;
+ }
+
+ if (!xdr_int (&xdr, &len)) {
+ remoteDispatchError (client, NULL, "%s", _("xdr_int failed (2)"));
+ xdr_destroy (&xdr);
+ return;
+ }
+
+ xdr_destroy (&xdr);
+
+ /* Send it. */
+ client->mode = QEMUD_MODE_TX_PACKET;
+ client->bufferLength = len;
+ client->bufferOffset = 0;
+}
/*----- Helpers. -----*/
/* get_nonnull_domain and get_nonnull_network turn an on-wire
diff --git a/qemud/remote_dispatch_localvars.h b/qemud/remote_dispatch_localvars.h
index 18d71e9..bb28109 100644
--- a/qemud/remote_dispatch_localvars.h
+++ b/qemud/remote_dispatch_localvars.h
@@ -96,6 +96,8 @@ remote_network_lookup_by_name_ret lv_remote_network_lookup_by_name_ret;
remote_domain_memory_peek_args lv_remote_domain_memory_peek_args;
remote_domain_memory_peek_ret lv_remote_domain_memory_peek_ret;
remote_num_of_defined_domains_ret lv_remote_num_of_defined_domains_ret;
+remote_events_enable_args lv_remote_events_enable_args;
+remote_events_enable_ret lv_remote_events_enable_ret;
remote_domain_block_stats_args lv_remote_domain_block_stats_args;
remote_domain_block_stats_ret lv_remote_domain_block_stats_ret;
remote_domain_detach_device_args lv_remote_domain_detach_device_args;
@@ -112,6 +114,7 @@ remote_get_version_ret lv_remote_get_version_ret;
remote_domain_suspend_args lv_remote_domain_suspend_args;
remote_storage_pool_lookup_by_name_args lv_remote_storage_pool_lookup_by_name_args;
remote_storage_pool_lookup_by_name_ret lv_remote_storage_pool_lookup_by_name_ret;
+remote_events_domain_event_ret lv_remote_events_domain_event_ret;
remote_network_set_autostart_args lv_remote_network_set_autostart_args;
remote_network_get_autostart_args lv_remote_network_get_autostart_args;
remote_network_get_autostart_ret lv_remote_network_get_autostart_ret;
diff --git a/qemud/remote_dispatch_proc_switch.h b/qemud/remote_dispatch_proc_switch.h
index 767b142..eeeb580 100644
--- a/qemud/remote_dispatch_proc_switch.h
+++ b/qemud/remote_dispatch_proc_switch.h
@@ -335,6 +335,21 @@ case REMOTE_PROC_DOMAIN_UNDEFINE:
args = (char *) &lv_remote_domain_undefine_args;
memset (&lv_remote_domain_undefine_args, 0, sizeof lv_remote_domain_undefine_args);
break;
+case REMOTE_PROC_EVENTS_DOMAIN_EVENT:
+ fn = (dispatch_fn) remoteDispatchEventsDomainEvent;
+ ret_filter = (xdrproc_t) xdr_remote_events_domain_event_ret;
+ ret = (char *) &lv_remote_events_domain_event_ret;
+ memset (&lv_remote_events_domain_event_ret, 0, sizeof lv_remote_events_domain_event_ret);
+ break;
+case REMOTE_PROC_EVENTS_ENABLE:
+ fn = (dispatch_fn) remoteDispatchEventsEnable;
+ args_filter = (xdrproc_t) xdr_remote_events_enable_args;
+ args = (char *) &lv_remote_events_enable_args;
+ memset (&lv_remote_events_enable_args, 0, sizeof lv_remote_events_enable_args);
+ ret_filter = (xdrproc_t) xdr_remote_events_enable_ret;
+ ret = (char *) &lv_remote_events_enable_ret;
+ memset (&lv_remote_events_enable_ret, 0, sizeof lv_remote_events_enable_ret);
+ break;
case REMOTE_PROC_FIND_STORAGE_POOL_SOURCES:
fn = (dispatch_fn) remoteDispatchFindStoragePoolSources;
args_filter = (xdrproc_t) xdr_remote_find_storage_pool_sources_args;
diff --git a/qemud/remote_dispatch_prototypes.h b/qemud/remote_dispatch_prototypes.h
index 950ad05..ce345e9 100644
--- a/qemud/remote_dispatch_prototypes.h
+++ b/qemud/remote_dispatch_prototypes.h
@@ -47,6 +47,8 @@ static int remoteDispatchDomainSetVcpus (struct qemud_server *server, struct qem
static int remoteDispatchDomainShutdown (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_shutdown_args *args, void *ret);
static int remoteDispatchDomainSuspend (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_suspend_args *args, void *ret);
static int remoteDispatchDomainUndefine (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_undefine_args *args, void *ret);
+static int remoteDispatchEventsDomainEvent (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_events_domain_event_ret *ret);
+static int remoteDispatchEventsEnable (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_events_enable_args *args, remote_events_enable_ret *ret);
static int remoteDispatchFindStoragePoolSources (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_find_storage_pool_sources_args *args, remote_find_storage_pool_sources_ret *ret);
static int remoteDispatchGetCapabilities (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_get_capabilities_ret *ret);
static int remoteDispatchGetHostname (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_get_hostname_ret *ret);
diff --git a/qemud/remote_protocol.c b/qemud/remote_protocol.c
index be1d6d8..b876127 100644
--- a/qemud/remote_protocol.c
+++ b/qemud/remote_protocol.c
@@ -1943,6 +1943,37 @@ xdr_remote_storage_vol_get_path_ret (XDR *xdrs, remote_storage_vol_get_path_ret
}
bool_t
+xdr_remote_events_enable_args (XDR *xdrs, remote_events_enable_args *objp)
+{
+
+ if (!xdr_int (xdrs, &objp->event_class))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->enable))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_remote_events_enable_ret (XDR *xdrs, remote_events_enable_ret *objp)
+{
+
+ if (!xdr_int (xdrs, &objp->success))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_remote_events_domain_event_ret (XDR *xdrs, remote_events_domain_event_ret *objp)
+{
+
+ if (!xdr_remote_nonnull_domain (xdrs, &objp->dom))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->event))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
xdr_remote_procedure (XDR *xdrs, remote_procedure *objp)
{
diff --git a/qemud/remote_protocol.h b/qemud/remote_protocol.h
index bcaa219..f0b511f 100644
--- a/qemud/remote_protocol.h
+++ b/qemud/remote_protocol.h
@@ -1081,6 +1081,23 @@ struct remote_storage_vol_get_path_ret {
remote_nonnull_string name;
};
typedef struct remote_storage_vol_get_path_ret remote_storage_vol_get_path_ret;
+
+struct remote_events_enable_args {
+ int event_class;
+ int enable;
+};
+typedef struct remote_events_enable_args remote_events_enable_args;
+
+struct remote_events_enable_ret {
+ int success;
+};
+typedef struct remote_events_enable_ret remote_events_enable_ret;
+
+struct remote_events_domain_event_ret {
+ remote_nonnull_domain dom;
+ int event;
+};
+typedef struct remote_events_domain_event_ret remote_events_domain_event_ret;
#define REMOTE_PROGRAM 0x20008086
#define REMOTE_PROTOCOL_VERSION 1
@@ -1189,6 +1206,8 @@ enum remote_procedure {
REMOTE_PROC_NODE_GET_FREE_MEMORY = 102,
REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103,
REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104,
+ REMOTE_PROC_EVENTS_ENABLE = 105,
+ REMOTE_PROC_EVENTS_DOMAIN_EVENT = 106,
};
typedef enum remote_procedure remote_procedure;
@@ -1394,6 +1413,9 @@ extern bool_t xdr_remote_storage_vol_get_info_args (XDR *, remote_storage_vol_g
extern bool_t xdr_remote_storage_vol_get_info_ret (XDR *, remote_storage_vol_get_info_ret*);
extern bool_t xdr_remote_storage_vol_get_path_args (XDR *, remote_storage_vol_get_path_args*);
extern bool_t xdr_remote_storage_vol_get_path_ret (XDR *, remote_storage_vol_get_path_ret*);
+extern bool_t xdr_remote_events_enable_args (XDR *, remote_events_enable_args*);
+extern bool_t xdr_remote_events_enable_ret (XDR *, remote_events_enable_ret*);
+extern bool_t xdr_remote_events_domain_event_ret (XDR *, remote_events_domain_event_ret*);
extern bool_t xdr_remote_procedure (XDR *, remote_procedure*);
extern bool_t xdr_remote_message_direction (XDR *, remote_message_direction*);
extern bool_t xdr_remote_message_status (XDR *, remote_message_status*);
@@ -1575,6 +1597,9 @@ extern bool_t xdr_remote_storage_vol_get_info_args ();
extern bool_t xdr_remote_storage_vol_get_info_ret ();
extern bool_t xdr_remote_storage_vol_get_path_args ();
extern bool_t xdr_remote_storage_vol_get_path_ret ();
+extern bool_t xdr_remote_events_enable_args ();
+extern bool_t xdr_remote_events_enable_ret ();
+extern bool_t xdr_remote_events_domain_event_ret ();
extern bool_t xdr_remote_procedure ();
extern bool_t xdr_remote_message_direction ();
extern bool_t xdr_remote_message_status ();
diff --git a/qemud/remote_protocol.x b/qemud/remote_protocol.x
index f848ae5..09acd80 100644
--- a/qemud/remote_protocol.x
+++ b/qemud/remote_protocol.x
@@ -965,6 +965,21 @@ struct remote_storage_vol_get_path_ret {
remote_nonnull_string name;
};
+/* Events */
+struct remote_events_enable_args {
+ int event_class;
+ int enable;
+};
+
+struct remote_events_enable_ret {
+ int success;
+};
+
+struct remote_events_domain_event_ret {
+ remote_nonnull_domain dom;
+ int event;
+};
+
/*----- Protocol. -----*/
/* Define the program number, protocol version and procedure numbers here. */
@@ -1086,7 +1101,10 @@ enum remote_procedure {
REMOTE_PROC_NODE_GET_FREE_MEMORY = 102,
REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103,
- REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104
+ REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104,
+
+ REMOTE_PROC_EVENTS_ENABLE = 105,
+ REMOTE_PROC_EVENTS_DOMAIN_EVENT = 106
};
/* Custom RPC structure. */
diff --git a/src/driver.h b/src/driver.h
index 655cd05..005fe03 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -40,6 +40,13 @@ typedef enum {
VIR_DRV_OPEN_ERROR = -2,
} virDrvOpenStatus;
+
+/* Event Classes. (bitmasked value) */
+typedef enum {
+ virDomainEvent = 1,
+ virNodeEvent = 2, /* NYI */
+} virEventClass;
+
/* Feature detection. This is a libvirt-private interface for determining
* what features are supported by the driver.
*
@@ -280,6 +287,15 @@ typedef unsigned long long
(*virDrvNodeGetFreeMemory)
(virConnectPtr conn);
+typedef int
+ (*virDrvEventsEnableEventClass)
+ (virConnectPtr conn,
+ virEventClass event_class,
+ int enable);
+
+typedef int
+ (*virDrvDomainEventEmitted)
+ (virDomainEventType evt);
/**
* _virDriver:
*
@@ -296,6 +312,8 @@ struct _virDriver {
int no; /* the number virDrvNo */
const char * name; /* the name of the driver */
unsigned long ver; /* the version of the backend */
+ virConnectPtr conns; /* the list of active connections */
+
virDrvProbe probe;
virDrvOpen open;
virDrvClose close;
@@ -352,6 +370,8 @@ struct _virDriver {
virDrvDomainMemoryPeek domainMemoryPeek;
virDrvNodeGetCellsFreeMemory nodeGetCellsFreeMemory;
virDrvNodeGetFreeMemory getFreeMemory;
+ virDrvEventsEnableEventClass enableEventClass;
+ virDrvDomainEventEmitted domainEventEmitted;
};
typedef int
@@ -396,7 +416,6 @@ typedef int
(*virDrvNetworkSetAutostart) (virNetworkPtr network,
int autostart);
-
typedef struct _virNetworkDriver virNetworkDriver;
typedef virNetworkDriver *virNetworkDriverPtr;
diff --git a/src/event.c b/src/event.c
index 49a9e61..9a39ab7 100644
--- a/src/event.c
+++ b/src/event.c
@@ -70,16 +70,28 @@ int virEventRemoveTimeout(int timer) {
return removeTimeoutImpl(timer);
}
-void __virEventRegisterImpl(virEventAddHandleFunc addHandle,
- virEventUpdateHandleFunc updateHandle,
- virEventRemoveHandleFunc removeHandle,
- virEventAddTimeoutFunc addTimeout,
- virEventUpdateTimeoutFunc updateTimeout,
- virEventRemoveTimeoutFunc removeTimeout) {
+void virEventRegisterHandleImpl(virEventAddHandleFunc addHandle,
+ virEventUpdateHandleFunc updateHandle,
+ virEventRemoveHandleFunc removeHandle) {
addHandleImpl = addHandle;
updateHandleImpl = updateHandle;
removeHandleImpl = removeHandle;
+}
+
+void __virEventRegisterTimeoutImpl(virEventAddTimeoutFunc addTimeout,
+ virEventUpdateTimeoutFunc updateTimeout,
+ virEventRemoveTimeoutFunc removeTimeout) {
addTimeoutImpl = addTimeout;
updateTimeoutImpl = updateTimeout;
removeTimeoutImpl = removeTimeout;
}
+
+void __virEventRegisterImpl(virEventAddHandleFunc addHandle,
+ virEventUpdateHandleFunc updateHandle,
+ virEventRemoveHandleFunc removeHandle,
+ virEventAddTimeoutFunc addTimeout,
+ virEventUpdateTimeoutFunc updateTimeout,
+ virEventRemoveTimeoutFunc removeTimeout) {
+ virEventRegisterHandleImpl(addHandle, updateHandle, removeHandle);
+ virEventRegisterTimeoutImpl(addTimeout, updateTimeout, removeTimeout);
+}
diff --git a/src/event.h b/src/event.h
index 758573c..b3a3849 100644
--- a/src/event.h
+++ b/src/event.h
@@ -23,17 +23,7 @@
#ifndef __VIR_EVENT_H__
#define __VIR_EVENT_H__
-
-
-/**
- * virEventHandleCallback: callback for receiving file handle events
- *
- * @fd: file handle on which the event occurred
- * @events: bitset of events from POLLnnn constants
- * @opaque: user data registered with handle
- */
-typedef void (*virEventHandleCallback)(int fd, int events, void *opaque);
-
+#include "internal.h"
/**
* virEventAddHandle: register a callback for monitoring file handle events
*
@@ -110,14 +100,14 @@ void virEventUpdateTimeout(int timer, int frequency);
*/
int virEventRemoveTimeout(int timer);
-typedef int (*virEventAddHandleFunc)(int, int, virEventHandleCallback, void *);
-typedef void (*virEventUpdateHandleFunc)(int, int);
-typedef int (*virEventRemoveHandleFunc)(int);
-
typedef int (*virEventAddTimeoutFunc)(int, virEventTimeoutCallback, void *);
typedef void (*virEventUpdateTimeoutFunc)(int, int);
typedef int (*virEventRemoveTimeoutFunc)(int);
+void __virEventRegisterTimeoutImpl(virEventAddTimeoutFunc addTimeout,
+ virEventUpdateTimeoutFunc updateTimeout,
+ virEventRemoveTimeoutFunc removeTimeout);
+
void __virEventRegisterImpl(virEventAddHandleFunc addHandle,
virEventUpdateHandleFunc updateHandle,
virEventRemoveHandleFunc removeHandle,
@@ -125,6 +115,7 @@ void __virEventRegisterImpl(virEventAddHandleFunc addHandle,
virEventUpdateTimeoutFunc updateTimeout,
virEventRemoveTimeoutFunc removeTimeout);
-#define virEventRegisterImpl(ah,rh,at,rt) __virEventRegisterImpl(ah,rh,at,rt)
+#define virEventRegisterTimeoutImpl(at,ut,rt) __virEventRegisterTimeoutImpl((at),(ut),(rt))
+#define virEventRegisterImpl(ah,uh,rh,at,ut,rt) __virEventRegisterImpl((ah),(uh),(rh),(at),(ut),(rt))
#endif /* __VIR_EVENT_H__ */
diff --git a/src/internal.h b/src/internal.h
index a3d48fa..67a3e5b 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -191,6 +191,18 @@ extern int debugFlag;
#define VIR_IS_STORAGE_VOL(obj) ((obj) && (obj)->magic==VIR_STORAGE_VOL_MAGIC)
#define VIR_IS_CONNECTED_STORAGE_VOL(obj) (VIR_IS_STORAGE_VOL(obj) && VIR_IS_CONNECT((obj)->conn))
+/**
+ * Domain Event Callbacks
+ */
+struct _virDomainEventCallbackList {
+ virConnectPtr conn;
+ virConnectDomainEventCallback cb;
+ void *opaque;
+ struct _virDomainEventCallbackList *next;
+};
+
+typedef struct _virDomainEventCallbackList virDomainEventCallbackList;
+
/*
* arbitrary limitations
*/
@@ -237,6 +249,12 @@ struct _virConnect {
virHashTablePtr storagePools;/* hash table for known storage pools */
virHashTablePtr storageVols;/* hash table for known storage vols */
int refs; /* reference count */
+
+ /* Domain Callbacks */
+ virDomainEventCallbackList *domainEventCallbacks;
+
+ /* link to next conn of this driver type */
+ struct _virConnect *next;
};
/**
@@ -377,4 +395,13 @@ char *virStringListJoin(const virStringList *list, const char *pre,
const char *post, const char *sep);
void virStringListFree(virStringList *list);
+/*
+ * Domain Event Notification
+ */
+
+void virDomainEventCallbackListFree(virDomainEventCallbackList *head);
+
+void virDispatchDomainEvent(virDomainPtr dom, int event);
+void virBroadcastDomainEvent(virDomainPtr dom, int event);
+
#endif /* __VIR_INTERNAL_H__ */
diff --git a/src/libvirt.c b/src/libvirt.c
index e06e9f3..9472646 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -785,6 +785,8 @@ do_open (const char *name,
if (res == VIR_DRV_OPEN_ERROR) goto failed;
else if (res == VIR_DRV_OPEN_SUCCESS) {
ret->driver = virDriverTab[i];
+ ret->next = ret->driver->conns;
+ ret->driver->conns = ret;
break;
}
}
@@ -957,6 +959,19 @@ virConnectClose(virConnectPtr conn)
conn->networkDriver->close (conn);
if (conn->storageDriver)
conn->storageDriver->close (conn);
+ if (conn->domainEventCallbacks)
+ virDomainEventCallbackListFree(conn->domainEventCallbacks);
+
+ /* Remove the connection from the list of active connections */
+ virConnectPtr *last = &conn->driver->conns;
+ while(*last) {
+ virConnectPtr p = *last;
+ if( p == conn ) {
+ *last = p->next;
+ break;
+ }
+ last = &p->next;
+ }
conn->driver->close (conn);
if (virUnrefConnect(conn) < 0)
@@ -1427,6 +1442,7 @@ virDomainLookupByName(virConnectPtr conn, const char *name)
int
virDomainDestroy(virDomainPtr domain)
{
+ int ret;
virConnectPtr conn;
DEBUG("domain=%p", domain);
@@ -1442,8 +1458,14 @@ virDomainDestroy(virDomainPtr domain)
return (-1);
}
- if (conn->driver->domainDestroy)
- return conn->driver->domainDestroy (domain);
+ if (conn->driver->domainDestroy) {
+ ret = conn->driver->domainDestroy (domain);
+ if(!ret &&
+ conn->driver->domainEventEmitted &&
+ !conn->driver->domainEventEmitted(VIR_DOMAIN_EVENT_STOPPED))
+ virBroadcastDomainEvent(domain, VIR_DOMAIN_EVENT_STOPPED);
+ return ret;
+ }
virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
return -1;
@@ -1487,6 +1509,7 @@ virDomainFree(virDomainPtr domain)
int
virDomainSuspend(virDomainPtr domain)
{
+ int ret;
virConnectPtr conn;
DEBUG("domain=%p", domain);
@@ -1501,8 +1524,14 @@ virDomainSuspend(virDomainPtr domain)
conn = domain->conn;
- if (conn->driver->domainSuspend)
- return conn->driver->domainSuspend (domain);
+ if (conn->driver->domainSuspend) {
+ ret = conn->driver->domainSuspend (domain);
+ if(!ret &&
+ conn->driver->domainEventEmitted &&
+ !conn->driver->domainEventEmitted(VIR_DOMAIN_EVENT_SUSPENDED))
+ virBroadcastDomainEvent(domain, VIR_DOMAIN_EVENT_SUSPENDED);
+ return ret;
+ }
virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
return -1;
@@ -1521,6 +1550,7 @@ virDomainSuspend(virDomainPtr domain)
int
virDomainResume(virDomainPtr domain)
{
+ int ret;
virConnectPtr conn;
DEBUG("domain=%p", domain);
@@ -1535,8 +1565,14 @@ virDomainResume(virDomainPtr domain)
conn = domain->conn;
- if (conn->driver->domainResume)
- return conn->driver->domainResume (domain);
+ if (conn->driver->domainResume) {
+ ret = conn->driver->domainResume (domain);
+ if(!ret &&
+ conn->driver->domainEventEmitted &&
+ !conn->driver->domainEventEmitted(VIR_DOMAIN_EVENT_RESUMED))
+ virBroadcastDomainEvent(domain, VIR_DOMAIN_EVENT_RESUMED);
+ return ret;
+ }
virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
return -1;
@@ -1557,6 +1593,7 @@ virDomainResume(virDomainPtr domain)
int
virDomainSave(virDomainPtr domain, const char *to)
{
+ int ret;
char filepath[4096];
virConnectPtr conn;
DEBUG("domain=%p, to=%s", domain, to);
@@ -1595,8 +1632,14 @@ virDomainSave(virDomainPtr domain, const char *to)
}
- if (conn->driver->domainSave)
- return conn->driver->domainSave (domain, to);
+ if (conn->driver->domainSave) {
+ ret = conn->driver->domainSave (domain, to);
+ if(!ret &&
+ conn->driver->domainEventEmitted &&
+ !conn->driver->domainEventEmitted(VIR_DOMAIN_EVENT_SAVED))
+ virBroadcastDomainEvent(domain, VIR_DOMAIN_EVENT_SAVED);
+ return ret;
+ }
virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
return -1;
@@ -2805,6 +2848,7 @@ virDomainMemoryPeek (virDomainPtr dom,
*/
virDomainPtr
virDomainDefineXML(virConnectPtr conn, const char *xml) {
+ virDomainPtr ret;
DEBUG("conn=%p, xml=%s", conn, xml);
if (!VIR_IS_CONNECT(conn)) {
@@ -2820,8 +2864,14 @@ virDomainDefineXML(virConnectPtr conn, const char *xml) {
return (NULL);
}
- if (conn->driver->domainDefineXML)
- return conn->driver->domainDefineXML (conn, xml);
+ if (conn->driver->domainDefineXML) {
+ ret = conn->driver->domainDefineXML (conn, xml);
+ if(ret &&
+ conn->driver->domainEventEmitted &&
+ !conn->driver->domainEventEmitted(VIR_DOMAIN_EVENT_ADDED))
+ virBroadcastDomainEvent(ret, VIR_DOMAIN_EVENT_ADDED);
+ return ret;
+ }
virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
return NULL;
@@ -2838,6 +2888,7 @@ virDomainDefineXML(virConnectPtr conn, const char *xml) {
int
virDomainUndefine(virDomainPtr domain) {
virConnectPtr conn;
+ int ret;
DEBUG("domain=%p", domain);
if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
@@ -2850,8 +2901,14 @@ virDomainUndefine(virDomainPtr domain) {
return (-1);
}
- if (conn->driver->domainUndefine)
- return conn->driver->domainUndefine (domain);
+ if (conn->driver->domainUndefine) {
+ ret = conn->driver->domainUndefine (domain);
+ if(!ret &&
+ conn->driver->domainEventEmitted &&
+ !conn->driver->domainEventEmitted(VIR_DOMAIN_EVENT_REMOVED))
+ virBroadcastDomainEvent(domain, VIR_DOMAIN_EVENT_REMOVED);
+ return ret;
+ }
virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
return -1;
@@ -2926,6 +2983,7 @@ virConnectListDefinedDomains(virConnectPtr conn, char **const names,
*/
int
virDomainCreate(virDomainPtr domain) {
+ int ret;
virConnectPtr conn;
DEBUG("domain=%p", domain);
@@ -2943,9 +3001,14 @@ virDomainCreate(virDomainPtr domain) {
return (-1);
}
- if (conn->driver->domainCreate)
- return conn->driver->domainCreate (domain);
-
+ if (conn->driver->domainCreate) {
+ ret = conn->driver->domainCreate (domain);
+ if(!ret &&
+ conn->driver->domainEventEmitted &&
+ !conn->driver->domainEventEmitted(VIR_DOMAIN_EVENT_STARTED))
+ virBroadcastDomainEvent(domain, VIR_DOMAIN_EVENT_STARTED);
+ return ret;
+ }
virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
return -1;
}
@@ -5318,3 +5381,148 @@ void virStringListFree(virStringList *list)
list = p;
}
}
+
+/*
+ * Domain Event Notification
+ */
+
+/**
+ * virDomainEventCallbackListFree:
+ * @head: event callback list head
+ *
+ * Free the memory in the domain event callback list
+ */
+void virDomainEventCallbackListFree(virDomainEventCallbackList *head)
+{
+ while (head) {
+ virDomainEventCallbackList *p = head->next;
+ VIR_FREE(head);
+ head = p;
+ }
+}
+
+/**
+ * virConnectDomainEventRegister:
+ * @conn: pointer to the connection
+ * @cb: callback to the function handling domain events
+ * @opaque: opaque data to pass on to the callback
+ *
+ * Adds a Domain Event Callback
+ *
+ * Returns 0 on success, -1 on failure
+ */
+int virConnectDomainEventRegister(virConnectPtr conn,
+ virConnectDomainEventCallback cb,
+ void *opaque)
+{
+ int ret = 0;
+ int first = conn->domainEventCallbacks == NULL;
+ virDomainEventCallbackList *newNode;
+
+ if (VIR_ALLOC(newNode) < 0)
+ return -1;
+
+ newNode->next = conn->domainEventCallbacks;
+ newNode->conn = conn;
+ newNode->cb = cb;
+ newNode->opaque = opaque;
+ conn->domainEventCallbacks = newNode;
+
+ /* Registering for a domain callback will enable delivery by default */
+ if (conn->driver && conn->driver->enableEventClass && first)
+ ret = conn->driver->enableEventClass (conn, virDomainEvent, 1);
+
+ DEBUG0("Registered domain event callback");
+ return ret;
+}
+
+/**
+ * virConnectDomainEventDeregister:
+ * @conn: pointer to the connection
+ * @cb: callback to the function handling domain events
+ *
+ * Removes a Domain Event Callback
+ *
+ * Returns 0 on success, -1 on failure
+ */
+int virConnectDomainEventDeregister(virConnectPtr conn, virConnectDomainEventCallback cb)
+{
+ int ret = -1;
+ virDomainEventCallbackList **last = &conn->domainEventCallbacks;
+
+ while(*last) {
+ virDomainEventCallbackList *p = *last;
+ if( p->conn == conn &&
+ p->cb == cb ) {
+ *last = p->next;
+
+ VIR_FREE(p);
+ DEBUG0("Removed domain event callback");
+ ret = 0;
+ break;
+ }
+ last = &p->next;
+ }
+
+ /* De-registering for a domain callback will disable delivery of this event type*/
+ if (conn->driver &&
+ conn->driver->enableEventClass &&
+ !conn->domainEventCallbacks)
+ ret = conn->driver->enableEventClass (conn, virDomainEvent, 0);
+
+ return ret;
+}
+
+/**
+ * virDispatchDomainEvent:
+ * @dom: the domain
+ * @event: the domain event code
+ *
+ * Internal function by which drivers to dispatch domain events.
+ */
+void virDispatchDomainEvent(virDomainPtr dom,
+ int event)
+{
+ virDomainEventCallbackList *p = dom->conn->domainEventCallbacks;
+ DEBUG("Dispatching callbacks for event %d to %p", event, dom->conn);
+ while(p) {
+ DEBUG(" Calling cb %p", p->cb);
+ (p->cb)(dom->conn, dom, event, p->opaque);
+ p = p->next;
+ }
+ DEBUG("Done dispatching events to %p", dom->conn);
+}
+
+/**
+ * virDispatchDomainEvent:
+ * @dom: the domain
+ * @event: the domain event code
+ *
+ * Internal function by which drivers to broadcast domain events.
+ */
+void virBroadcastDomainEvent(virDomainPtr dom,
+ int event)
+{
+ virDomainPtr dom_bc;
+ virConnectPtr conn = dom->conn->driver->conns;
+ if(!conn) {
+ DEBUG0("Trying to dispatch to null connection list");
+ return;
+ }
+
+ while(conn) {
+ if(conn != dom->conn ) {
+ dom_bc = virDomainLookupByName(conn, dom->name);
+ } else {
+ dom_bc = dom;
+ }
+
+ if(dom_bc)
+ virDispatchDomainEvent(dom_bc, event);
+
+ if(dom_bc != dom)
+ virDomainFree(dom_bc);
+
+ conn = conn->next;
+ }
+}
diff --git a/src/libvirt_sym.version b/src/libvirt_sym.version
index b8c470c..243d4a7 100644
--- a/src/libvirt_sym.version
+++ b/src/libvirt_sym.version
@@ -146,6 +146,10 @@
virStorageVolGetXMLDesc;
virStorageVolGetPath;
+ virEventRegisterHandleImpl;
+ virConnectDomainEventRegister;
+ virConnectDomainEventDeregister;
+
/* Symbols with __ are private only
for use by the libvirtd daemon.
They are not part of stable ABI
diff --git a/src/lxc_driver.c b/src/lxc_driver.c
index 30c3cab..ea80530 100644
--- a/src/lxc_driver.c
+++ b/src/lxc_driver.c
@@ -1238,6 +1238,7 @@ static virDriver lxcDriver = {
VIR_DRV_LXC, /* the number virDrvNo */
"LXC", /* the name of the driver */
LIBVIR_VERSION_NUMBER, /* the version of the backend */
+ NULL,/* conns */
lxcProbe, /* probe */
lxcOpen, /* open */
lxcClose, /* close */
@@ -1294,6 +1295,8 @@ static virDriver lxcDriver = {
NULL, /* domainMemoryPeek */
NULL, /* nodeGetCellsFreeMemory */
NULL, /* getFreeMemory */
+ NULL, /* enableEventClass */
+ NULL, /* domainEventSupported */
};
static virStateDriver lxcStateDriver = {
diff --git a/src/openvz_driver.c b/src/openvz_driver.c
index f68841e..a437818 100644
--- a/src/openvz_driver.c
+++ b/src/openvz_driver.c
@@ -958,6 +958,7 @@ static virDriver openvzDriver = {
VIR_DRV_OPENVZ,
"OPENVZ",
LIBVIR_VERSION_NUMBER,
+ NULL,/* conns */
openvzProbe, /* probe */
openvzOpen, /* open */
openvzClose, /* close */
@@ -1014,6 +1015,8 @@ static virDriver openvzDriver = {
NULL, /* domainMemoryPeek */
NULL, /* nodeGetCellsFreeMemory */
NULL, /* nodeGetFreeMemory */
+ NULL, /* enableEventClass */
+ NULL, /* domainEventSupported */
};
int openvzRegister(void) {
diff --git a/src/qemu_conf.h b/src/qemu_conf.h
index 88dfade..4d22119 100644
--- a/src/qemu_conf.h
+++ b/src/qemu_conf.h
@@ -68,6 +68,7 @@ struct qemud_driver {
char *vncListen;
virCapsPtr caps;
+ virDriverPtr vir_driver;
};
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index a88cb75..daabfa5 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -837,6 +837,8 @@ static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) {
return -1;
}
+static virDomainPtr qemudDomainLookupByName(virConnectPtr conn, const char *name);
+
static int qemudStartVMDaemon(virConnectPtr conn,
struct qemud_driver *driver,
virDomainObjPtr vm,
@@ -850,6 +852,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
unsigned int qemuCmdFlags;
fd_set keepfd;
const char *emulator;
+ virDomainPtr dom;
FD_ZERO(&keepfd);
@@ -998,6 +1001,11 @@ static int qemudStartVMDaemon(virConnectPtr conn,
qemudShutdownVMDaemon(conn, driver, vm);
return -1;
}
+ dom = qemudDomainLookupByName(conn,vm->def->name);
+ if(dom)
+ virBroadcastDomainEvent(dom, VIR_DOMAIN_EVENT_STARTED);
+ else
+ DEBUG0("Warning - dom is NULL at domain start");
}
return ret;
@@ -1032,11 +1040,22 @@ static int qemudVMData(struct qemud_driver *driver ATTRIBUTE_UNUSED,
static void qemudShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
struct qemud_driver *driver, virDomainObjPtr vm) {
+ virConnectPtr dconn;
if (!virDomainIsActive(vm))
return;
qemudLog(QEMUD_INFO, _("Shutting down VM '%s'\n"), vm->def->name);
+ if( driver && driver->vir_driver) {
+ dconn = driver->vir_driver->conns;
+
+ if (dconn) {
+ virDomainPtr dom = qemudDomainLookupByName(dconn, vm->def->name);
+ /* Note dom should never be NULL here. Just being paranoid ... */
+ if (dom)
+ virBroadcastDomainEvent(dom, VIR_DOMAIN_EVENT_STOPPED);
+ }
+ }
kill(vm->pid, SIGTERM);
qemudVMData(driver, vm, vm->stdout_fd);
@@ -2127,6 +2146,7 @@ static int qemudDomainSuspend(virDomainPtr dom) {
}
vm->state = VIR_DOMAIN_PAUSED;
qemudDebug("Reply %s", info);
+ virBroadcastDomainEvent(dom, VIR_DOMAIN_EVENT_SUSPENDED);
VIR_FREE(info);
return 0;
}
@@ -2155,6 +2175,7 @@ static int qemudDomainResume(virDomainPtr dom) {
}
vm->state = VIR_DOMAIN_RUNNING;
qemudDebug("Reply %s", info);
+ virBroadcastDomainEvent(dom, VIR_DOMAIN_EVENT_RESUMED);
VIR_FREE(info);
return 0;
}
@@ -2196,7 +2217,7 @@ static int qemudDomainDestroy(virDomainPtr dom) {
if (!vm->persistent)
virDomainRemoveInactive(&driver->domains,
vm);
-
+ virBroadcastDomainEvent(dom, VIR_DOMAIN_EVENT_STOPPED);
return 0;
}
@@ -2527,7 +2548,7 @@ static int qemudDomainSave(virDomainPtr dom,
if (!vm->persistent)
virDomainRemoveInactive(&driver->domains,
vm);
-
+ virBroadcastDomainEvent(dom, VIR_DOMAIN_EVENT_SAVED);
return 0;
}
@@ -2728,6 +2749,7 @@ static int qemudDomainRestore(virConnectPtr conn,
struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
virDomainDefPtr def;
virDomainObjPtr vm;
+ virDomainPtr dom;
int fd;
int ret;
char *xml;
@@ -2834,6 +2856,11 @@ static int qemudDomainRestore(virConnectPtr conn,
vm->state = VIR_DOMAIN_RUNNING;
}
+ dom = virDomainLookupByID(conn, def->id);
+ if(dom) {
+ virBroadcastDomainEvent(dom, VIR_DOMAIN_EVENT_RESTORED);
+ VIR_FREE(dom);
+ }
return 0;
}
@@ -4008,10 +4035,38 @@ static int qemudNetworkSetAutostart(virNetworkPtr net,
return 0;
}
+static int qemudDomainEventSupported(virDomainEventType evt)
+{
+ switch(evt) {
+ case VIR_DOMAIN_EVENT_STARTED:
+ case VIR_DOMAIN_EVENT_STOPPED:
+ case VIR_DOMAIN_EVENT_SUSPENDED:
+ case VIR_DOMAIN_EVENT_RESUMED:
+ case VIR_DOMAIN_EVENT_SAVED:
+ case VIR_DOMAIN_EVENT_RESTORED:
+ DEBUG("%s: %d", __FUNCTION__, (int)evt);
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
+static int qemudEnableEventClass(virConnectPtr conn,
+ virEventClass event_class ATTRIBUTE_UNUSED,
+ int enable ATTRIBUTE_UNUSED)
+{
+ struct qemud_driver *d = conn->privateData;
+ d->vir_driver = conn->driver;
+
+ return 0;
+}
+
static virDriver qemuDriver = {
VIR_DRV_QEMU,
"QEMU",
LIBVIR_VERSION_NUMBER,
+ NULL,/* conns */
qemudProbe, /* probe */
qemudOpen, /* open */
qemudClose, /* close */
@@ -4078,6 +4133,8 @@ static virDriver qemuDriver = {
NULL, /* nodeGetCellsFreeMemory */
NULL, /* getFreeMemory */
#endif
+ qemudEnableEventClass, /* enableEventClass */
+ qemudDomainEventSupported, /* domainEventSupported */
};
static virNetworkDriver qemuNetworkDriver = {
diff --git a/src/remote_internal.c b/src/remote_internal.c
index 06b0f4f..2501e1f 100644
--- a/src/remote_internal.c
+++ b/src/remote_internal.c
@@ -34,6 +34,7 @@
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/poll.h>
#include <fcntl.h>
#ifdef HAVE_SYS_WAIT_H
@@ -73,6 +74,7 @@
#include "remote_protocol.h"
#include "memory.h"
#include "util.h"
+#include "event.h"
/* Per-connection private data. */
#define MAGIC 999 /* private_data->magic if OK */
@@ -91,6 +93,7 @@ struct private_data {
int localUses; /* Ref count for private data */
char *hostname; /* Original hostname */
FILE *debugLog; /* Debug remote protocol */
+ PTHREAD_MUTEX_T (lock); /* Lock to handle async RPC calls */
#if HAVE_SASL
sasl_conn_t *saslconn; /* SASL context */
const char *saslDecoded;
@@ -156,6 +159,8 @@ static void make_nonnull_domain (remote_nonnull_domain *dom_dst, virDomainPtr do
static void make_nonnull_network (remote_nonnull_network *net_dst, virNetworkPtr net_src);
static void make_nonnull_storage_pool (remote_nonnull_storage_pool *pool_dst, virStoragePoolPtr vol_src);
static void make_nonnull_storage_vol (remote_nonnull_storage_vol *vol_dst, virStorageVolPtr vol_src);
+static void remoteDomainEventFired(int fd, int event, void *data);
+static void remoteDomainProcessEvent(virConnectPtr conn, XDR *xdr);
/*----------------------------------------------------------------------*/
@@ -680,6 +685,15 @@ doRemoteOpen (virConnectPtr conn,
(xdrproc_t) xdr_void, (char *) NULL) == -1)
goto failed;
+ pthread_mutex_init(&priv->lock, NULL);
+ DEBUG0("Adding Handler for remote events");
+ /* Set up a callback to listen on the socket data */
+ if (virEventAddHandle(priv->sock,
+ POLLIN | POLLERR | POLLHUP,
+ remoteDomainEventFired,
+ conn) < 0) {
+ DEBUG0("virEventAddHandle failed: No addHandleImpl defined. continuing without events.");
+ }
/* Successful. */
retcode = VIR_DRV_OPEN_SUCCESS;
@@ -4289,6 +4303,25 @@ remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open,
}
#endif /* HAVE_POLKIT */
+static int remoteEventsEnableEventClass (virConnectPtr conn,
+ virEventClass event_class,
+ int enable)
+{
+ remote_events_enable_args args;
+ remote_events_enable_ret ret;
+
+ args.event_class = event_class;
+ args.enable = enable;
+
+ memset (&ret, 0, sizeof ret);
+ if (call ( conn, conn->privateData, 0, REMOTE_PROC_EVENTS_ENABLE,
+ (xdrproc_t) xdr_remote_events_enable_args, (char *) &args,
+ (xdrproc_t) xdr_remote_events_enable_ret, (char *) &ret) == -1)
+ return -1;
+
+ return 0;
+}
+
/*----------------------------------------------------------------------*/
static int really_write (virConnectPtr conn, struct private_data *priv,
@@ -4362,19 +4395,30 @@ call (virConnectPtr conn, struct private_data *priv,
}
xdr_destroy (&xdr);
+ /* Lock on the connection semaphore, so we do not pull
+ * data off the wire if an async event fires while we
+ * are waiting on the response */
+ pthread_mutex_lock(&priv->lock);
+
/* Send length word followed by header+args. */
if (really_write (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer2, sizeof buffer2) == -1 ||
- really_write (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer, len-4) == -1)
+ really_write (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer, len-4) == -1) {
+ pthread_mutex_unlock(&priv->lock);
return -1;
+ }
+retry_read:
/* Read and deserialise length word. */
- if (really_read (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer2, sizeof buffer2) == -1)
+ if (really_read (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer2, sizeof buffer2) == -1) {
+ pthread_mutex_unlock(&priv->lock);
return -1;
+ }
xdrmem_create (&xdr, buffer2, sizeof buffer2, XDR_DECODE);
if (!xdr_int (&xdr, &len)) {
error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
VIR_ERR_RPC, _("xdr_int (length word, reply)"));
+ pthread_mutex_unlock(&priv->lock);
return -1;
}
xdr_destroy (&xdr);
@@ -4385,18 +4429,22 @@ call (virConnectPtr conn, struct private_data *priv,
if (len < 0 || len > REMOTE_MESSAGE_MAX) {
error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
VIR_ERR_RPC, _("packet received from server too large"));
+ pthread_mutex_unlock(&priv->lock);
return -1;
}
/* Read reply header and what follows (either a ret or an error). */
- if (really_read (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer, len) == -1)
+ if (really_read (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer, len) == -1) {
+ pthread_mutex_unlock(&priv->lock);
return -1;
+ }
/* Deserialise reply header. */
xdrmem_create (&xdr, buffer, len, XDR_DECODE);
if (!xdr_remote_message_header (&xdr, &hdr)) {
error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
VIR_ERR_RPC, _("invalid header in reply"));
+ pthread_mutex_unlock(&priv->lock);
return -1;
}
@@ -4407,6 +4455,7 @@ call (virConnectPtr conn, struct private_data *priv,
VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
_("unknown program (received %x, expected %x)"),
hdr.prog, REMOTE_PROGRAM);
+ pthread_mutex_unlock(&priv->lock);
return -1;
}
if (hdr.vers != REMOTE_PROTOCOL_VERSION) {
@@ -4415,19 +4464,30 @@ call (virConnectPtr conn, struct private_data *priv,
VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
_("unknown protocol version (received %x, expected %x)"),
hdr.vers, REMOTE_PROTOCOL_VERSION);
+ pthread_mutex_unlock(&priv->lock);
return -1;
}
- /* If we extend the server to actually send asynchronous messages, then
- * we'll need to change this so that it can recognise an asynch
- * message being received at this point.
- */
+ if (hdr.proc == REMOTE_PROC_EVENTS_DOMAIN_EVENT &&
+ hdr.direction == REMOTE_MESSAGE) {
+ /* An async message has come in while we were waiting for the
+ * response. Process it to pull it off the wire, and try again
+ */
+ DEBUG0("Encountered an event while waiting for a response");
+
+ remoteDomainProcessEvent(conn, &xdr);
+
+ DEBUG0("Retrying read");
+ xdr_destroy (&xdr);
+ goto retry_read;
+ }
if (hdr.proc != proc_nr) {
__virRaiseError (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
NULL, NULL, VIR_FROM_REMOTE,
VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
_("unknown procedure (received %x, expected %x)"),
hdr.proc, proc_nr);
+ pthread_mutex_unlock(&priv->lock);
return -1;
}
if (hdr.direction != REMOTE_REPLY) {
@@ -4436,6 +4496,7 @@ call (virConnectPtr conn, struct private_data *priv,
VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
_("unknown direction (received %x, expected %x)"),
hdr.direction, REMOTE_REPLY);
+ pthread_mutex_unlock(&priv->lock);
return -1;
}
if (hdr.serial != serial) {
@@ -4443,6 +4504,7 @@ call (virConnectPtr conn, struct private_data *priv,
VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
_("unknown serial (received %x, expected %x)"),
hdr.serial, serial);
+ pthread_mutex_unlock(&priv->lock);
return -1;
}
@@ -4458,6 +4520,7 @@ call (virConnectPtr conn, struct private_data *priv,
return -1;
}
xdr_destroy (&xdr);
+ pthread_mutex_unlock(&priv->lock);
return 0;
case REMOTE_ERROR:
@@ -4465,6 +4528,7 @@ call (virConnectPtr conn, struct private_data *priv,
if (!xdr_remote_error (&xdr, &rerror)) {
error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
VIR_ERR_RPC, _("unmarshalling remote_error"));
+ pthread_mutex_unlock(&priv->lock);
return -1;
}
xdr_destroy (&xdr);
@@ -4475,10 +4539,12 @@ call (virConnectPtr conn, struct private_data *priv,
rerror.code == VIR_ERR_RPC &&
rerror.level == VIR_ERR_ERROR &&
STRPREFIX(*rerror.message, "unknown procedure")) {
+ pthread_mutex_unlock(&priv->lock);
return -2;
}
server_error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, &rerror);
xdr_free ((xdrproc_t) xdr_remote_error, (char *) &rerror);
+ pthread_mutex_unlock(&priv->lock);
return -1;
default:
@@ -4487,6 +4553,7 @@ call (virConnectPtr conn, struct private_data *priv,
_("unknown status (received %x)"),
hdr.status);
xdr_destroy (&xdr);
+ pthread_mutex_unlock(&priv->lock);
return -1;
}
}
@@ -4872,6 +4939,7 @@ static virDriver driver = {
.domainMemoryPeek = remoteDomainMemoryPeek,
.nodeGetCellsFreeMemory = remoteNodeGetCellsFreeMemory,
.getFreeMemory = remoteNodeGetFreeMemory,
+ .enableEventClass = remoteEventsEnableEventClass
};
static virNetworkDriver network_driver = {
@@ -4957,3 +5025,99 @@ remoteRegister (void)
return 0;
}
+
+/**
+ * remoteDomainProcessEvent
+ *
+ * Read the data off the wire, and process the event
+ */
+void remoteDomainProcessEvent(virConnectPtr conn,
+ XDR *xdr)
+{
+ remote_events_domain_event_ret ret;
+ memset (&ret, 0, sizeof ret);
+
+ virDomainPtr dom;
+ /* unmarshall parameters, and process it*/
+ if (! xdr_remote_events_domain_event_ret(xdr, &ret) ) {
+ error (conn, VIR_ERR_RPC, _("remoteDomainProcessEvent: unmarshalling ret"));
+ return;
+ }
+
+ dom = get_nonnull_domain(conn,ret.dom);
+ virDispatchDomainEvent(dom, ret.event);
+}
+
+/** remoteDomainEventFired:
+ *
+ * The callback for monitoring the remote socket
+ * for event data
+ */
+void remoteDomainEventFired(int fd ATTRIBUTE_UNUSED,
+ int event ATTRIBUTE_UNUSED,
+ void *opaque)
+{
+ char buffer[REMOTE_MESSAGE_MAX];
+ char buffer2[4];
+ struct remote_message_header hdr;
+ XDR xdr;
+ int len;
+
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+
+ /* This may be a response to a command, or it
+ * may be a domain event.
+ * grab a lock on the connection so we don't stomp on
+ * command replys
+ */
+ DEBUG("%s : Event fired - grabbing lock", __FUNCTION__);
+ pthread_mutex_lock(&priv->lock);
+
+ /* Read and deserialise length word. */
+ if (really_read (conn, priv, 0, buffer2, sizeof buffer2) == -1) {
+ pthread_mutex_unlock(&priv->lock);
+ return;
+ }
+
+ xdrmem_create (&xdr, buffer2, sizeof buffer2, XDR_DECODE);
+ if (!xdr_int (&xdr, &len)) {
+ error (conn, VIR_ERR_RPC, _("xdr_int (length word, reply)"));
+ pthread_mutex_unlock(&priv->lock);
+ return;
+ }
+ xdr_destroy (&xdr);
+
+ /* Length includes length word - adjust to real length to read. */
+ len -= 4;
+
+ if (len < 0 || len > REMOTE_MESSAGE_MAX) {
+ error (conn, VIR_ERR_RPC, _("packet received from server too large"));
+ pthread_mutex_unlock(&priv->lock);
+ return;
+ }
+
+ /* Read reply header and what follows (either a ret or an error). */
+ if (really_read (conn, priv, 0, buffer, len) == -1) {
+ error (conn, VIR_ERR_RPC, _("error reading buffer from memory"));
+ return;
+ }
+
+ /* Deserialise reply header. */
+ xdrmem_create (&xdr, buffer, len, XDR_DECODE);
+ if (!xdr_remote_message_header (&xdr, &hdr)) {
+ error (conn, VIR_ERR_RPC, _("invalid header in event firing"));
+ pthread_mutex_unlock(&priv->lock);
+ return;
+ }
+
+ if (hdr.proc == REMOTE_PROC_EVENTS_DOMAIN_EVENT &&
+ hdr.direction == REMOTE_MESSAGE) {
+ DEBUG0("Encountered an async event");
+ remoteDomainProcessEvent(conn, &xdr);
+ } else {
+ DEBUG0("invalid proc in event firing");
+ error (conn, VIR_ERR_RPC, _("invalid proc in event firing"));
+ }
+ pthread_mutex_unlock(&priv->lock);
+}
\ No newline at end of file
diff --git a/src/test.c b/src/test.c
index 69c9090..ad5ea74 100644
--- a/src/test.c
+++ b/src/test.c
@@ -1539,6 +1539,7 @@ static virDriver testDriver = {
VIR_DRV_TEST,
"Test",
LIBVIR_VERSION_NUMBER,
+ NULL,/* conns */
NULL, /* probe */
testOpen, /* open */
testClose, /* close */
@@ -1595,6 +1596,8 @@ static virDriver testDriver = {
NULL, /* domainMemoryPeek */
testNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
NULL, /* getFreeMemory */
+ NULL, /* enableEventClass */
+ NULL, /* domainEventSupported */
};
static virNetworkDriver testNetworkDriver = {
[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]