In the current domain APIs, we currently have support for getting notified of domain lifecycle transition events. THis is done using two methods int virConnectDomainEventRegister(virConnectPtr conn, virConnectDomainEventCallback cb, void *opaque, virFreeCallback freecb); int virConnectDomainEventDeregister(virConnectPtr conn, virConnectDomainEventCallback cb); This allows an app to register a callback that looks like this typedef int (*virConnectDomainEventCallback)(virConnectPtr conn, virDomainPtr dom, int event, int detail, void *opaque); Where 'event' is the lifecycle transition (suspended, stopped, started, etc) and 'detail' is the cause of he transition (pause, migration, shutdown, etc) I have outstanding feature requests to add a lot more event notifications to the libvirt API. In particular - IO Errors. Parameter 'alias' the name of the block device with the error - Reboot. No parameters You can argue whether this should be part of the lifecycle events. On the one hand it is not guest visible, because the guest does a internal machine reset without the host ever seeing a change. This is different from other cases where QEMU itself is stopping/starting. - Watchdog. Parameter 'action', saying what is going to happen to the guest due to this watchdog firing (ignored, shutdown, paused, etc) - VNC client. In fact three events, connect, authenticated and disconnect. Parameters, TCP address & port number of client, and also of the server. Optionally a SASL username and TLS certificate name of the authenticated user - Guest user. Logon/logoff events. This requires co-operation from a guest agent, so it may not actually be of scope of libvirt. - Disk 'high watermark'. Emitted when a QCow volume grows beyond a certain physical allocation. THis allows an app to enlarge the underlying storage holding the qcow volume before an 'out of space' occurs. Parameter is the disk alias name. So we can see there are events with a wide variety of parameters and we need to figure out how to represent this in the API. Option 1 -------- Follow the existing lifecycle event model. For each new event, add a virConnectXXXXXEventRegister & virConnectEventDeregister method, and typedef a new callback for them. eg typedef int (*virConnectDomainBlockIOEventCallback)(virConnectPtr conn, virDomainPtr dom, const char *diskname, const char *alias, void *opaque); int virConnectDomainBlockIOEventRegister(virConnectPtr conn, virConnectDomainBlockIOEventCallback cb, void *opaque, virFreeCallback freecb); int virConnectDomainBlockIOEventDeregister(virConnectPtr conn, virConnectDomainEventCallback cb); So we'll have 2 extra APIs for every event + a new typedef. We'll also need to add new APIs in src/conf/domain_event.h to cope with dispatch Option 2 -------- GLib/GObject take a very loosely typed approach to registering/unregistering events. The have a single pair of methods that work for any event & a generic callback signature, requiring application casts. typedef int (*virConnectEventCallback)(void *opaque); int virConnectEventRegister(virConnectPtr conn, const char *eventname, virConnectEventCallback cb, void *opaque, virFreeCallback freecb); int virCOnnectEventUnregister(virConnectPtr conn, int eventID); In this model, the register method returns a unique integer ID for the callback which can be used to unregister it. Application's using this will still need a strongly typed callback for receiving the event, but when calling virConnectEventRegister(), the would do an explicit 'bad' cast to 'virConnectEventCallback' Option 3 -------- A hybrid of both approaches. Have a new 'register' method for each type of event that takes a strongly typed callback, but have a generic 'unregister' method that just uses the 'int eventID' int virConnectDomainBlockIOEventRegister(virConnectPtr conn, virConnectDomainBlockIOEventCallback cb, void *opaque, virFreeCallback freecb); int virCOnnectEventUnregister(virConnectPtr conn, int eventID); Option 4 -------- Have one pair of register/unregister events, but instead of passing diffeerent parameters to each callback, have a generic callback that takes a single parameter. This parameter would be declared as a union. So depending on the type of event being received, you'd access different parts of the union typedef union { virConnectDomainBlockIOEvent blockio; virConnectDomainWatchdogEvent watchdog; ...other events... } virConnectEvent; Either we could include a dummy member in the union with padding to 1024 bytes in size for future expansion, or we could simply declare that apps must never allocate this data type themselves, thus allowing us to enlarge it at will. typedef int (*virConnectEventCallback)(int eventType, virConnectEvent, void *opaque); int virConnectEventRegister(virConnectPtr conn, const char *eventname, virConnectEventCallback cb, void *opaque, virFreeCallback freecb); int virConnectEventUnregister(virConnectPtr conn, int eventID); There is one final question unrelated to these 4 options. For the lifecycle events we always registered against the 'virConnectPtr' since that is needed to capture 'domain created' events where there's no virDomainPtr to register a callback against yet. Do we want to always register all events aganist the virConnectPtr, and then pass a 'virDomainPtr' as a parameter to the callbacks as needed. Or should we allow registering events against the virDomainPtr directly. The latter might make it simpler to map libvirt into GLib/GObjects event system in the future. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list