typedef struct BlockIOEvent {
/* contents are private */
} BlockIOEvent;
/* Connect a slot to a BlockIOEvent signal and return a handle to the
connection */
int block_io_event_connect(BlockIOEvent *event, BlockIOEventFunc *cb,
void *opaque);
/* Signal any connect slots of a BlockIOEvent */
void block_io_event_signal(BlockIOEvent *event, const char *device,
const char *action, const char *operation);
/* Disconnect a slot from a signal based on a connection handle */
void block_io_event_disconnect(BlockIOEvent *event, int handle);
In the case of BlockIOEvent, this is a global signal that is not tied
to any specific object so there would be a global BlockIOEvent object
within QEMU.
From a QMP perspective, we would have the following function in the
schema:
[ 'block-io-event', {}, {}, 'BlockIOEvent' ]
A function definition that returns an Event is a signal accessor.
Within QEMU, we implement a signal accessor like so:
BlockIOEvent *qmp_block_io_event(Error **errp)
{
return &global_block_io_event;
}
For QMP and libqmp, signal accessors are handled specially. A signal
accessor is expanded into two QMP functions:
[ 'block-io-event-connect', {}, {}, 'str' ]
[ 'block-io-event-disconnect', {'tag' : 'str'}, {}, 'none' ]
Connect returns a handle to the connection as an opaque string.
Disconnect takes that handle. Both functions will also take any
arguments that the signal accessor takes and under the cover uses the
signal accessor to access the object.
In libqmp, the following interfaces will be generated:
int libqmp_block_io_event_connect(QmpSession *sess, BlockIOEventFunc
*cb, void *opaque, Error **errp);
void libqmp_block_io_event_disconnect(QmpSession *sess, int handle,
Error **errp);
Again, if the signal accessor takes additional arguments, they will be
passed here.
All existing events will be converted to signals with signal accessors
that take no arguments. However, BlockIOEvent is a good example of a
signal that we'll add a new version of that takes a 'const char
*device' as an argument for the signal accessor. This will let
clients register for block io events on specific block devices.
Backwards Compatibility
Right now, QMP events to not have any type of context information
which means that there's no way to communicate the connection handle.
We'll solve this by adding a new 'tag' field to events that are
registered through one of the connect interfaces. Since this is only
present on events registered through this new interface, backwards
compatibility is preserved.
Upon initial connection, we'll treat all existing signals as having a
'default signal connection'. We'll introduce a new QMP command that
can be executed while in capabilities mode to disconnect default
signal connections. The effect is that new clients can use the
explicit register/unregister interface while old clients will continue
to see the old style events.
We'll deprecate the 'default signal connections' and make sure to
never add a new one post 0.15. Old clients will need to be updated to
explicitly register for events.
Another Example
Here's an example of BlockDeviceEvent, the successor to BlockIOEvent.
It makes use of signal accessor arguments and QAPI enumeration support:
# qmp-schema.json
{ 'BlockDeviceAction': [ 'report', 'stop', 'none' ] }
{ 'BlockDeviceOperation': [ 'read', 'write' ] }
{ 'BlockDeviceActionReason': [ 'nospc', 'io', 'other' ] }
{ 'BlockDeviceEvent': { 'action': 'BlockDeviceAction', 'operation':
'BlockDeviceOperation', 'reason': 'BlockDeviceActionReason' } }
[ 'block-device-event', { 'device': 'str' }, {}, 'BlockDeviceEvent' ]
# qemu/block.c (Signal Accessor)
BlockDeviceEvent *qmp_block_device_event(const char *str, Error **errp)'
# qemu/qmp-types.h (Generated QMP interfaces)
typedef enum BlockDeviceAction {
BDA_REPORT = 0,
BDA_STOP,
BDA_NONE,
} BlockDeviceAction;
typedef enum BlockDeviceOperation {
BDO_READ = 0,
BDO_WRITE,
} BlockDeviceOperation;
typedef enum BlockDeviceActionReason {
BDAR_NOSPC = 0,
BDAR_IO,
BDAR_OTHER,
} BlockDeviceActionReason;
typedef struct BlockDeviceEvent {
/* private */
} BlockDeviceEvent;
typedef void (BlockDeviceEventFunc)(BlockDeviceAction action,
BlockDeviceOperation operator, BlockDeviceActionReason reason);
int block_device_event_connect(BlockDeviceEvent *event,
BlockDeviceEventFunc *cb, void *opaque);
void block_device_event_disconnect(BlockDeviceEvent *event, int handle);
# qemu/libqmp.h (Generated libqmp interfaces)
int libqmp_block_device_event_connect(QmpSession *sess, const char
*device, BlockDeviceEventFunc *cb, void *opaque);
void libqmp_block_device_event_disconnect(QmpSession *sess, const char
*device, int handle);
Regards,
Anthony Liguori
[1] http://repo.or.cz/w/qemu/aliguori.git/shortlog/refs/heads/glib
[2] http://en.wikipedia.org/wiki/Signals_and_slots