diff mbox

[v4,REPOST,1/2] Add device listener interface

Message ID 1417604616-6289-2-git-send-email-paul.durrant@citrix.com
State New
Headers show

Commit Message

Paul Durrant Dec. 3, 2014, 11:03 a.m. UTC
The Xen ioreq-server API, introduced in Xen 4.5, requires that PCI device
models explicitly register with Xen for config space accesses. This patch
adds a listener interface into qdev-core which can be used by the Xen
interface code to monitor for arrival and departure of PCI devices.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Andreas Faerber" <afaerber@suse.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Thomas Huth <thuth@linux.vnet.ibm.com>
Cc: Christian Borntraeger <borntraeger@de.ibm.com>
---
 hw/core/qdev.c          |   54 +++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/qdev-core.h  |   10 +++++++++
 include/qemu/typedefs.h |    1 +
 3 files changed, 65 insertions(+)

Comments

Stefano Stabellini Dec. 3, 2014, 12:29 p.m. UTC | #1
The second patch is already Acked.
You just need a review on this one to move forward, right?

Andreas, Michael?

On Wed, 3 Dec 2014, Paul Durrant wrote:
> The Xen ioreq-server API, introduced in Xen 4.5, requires that PCI device
> models explicitly register with Xen for config space accesses. This patch
> adds a listener interface into qdev-core which can be used by the Xen
> interface code to monitor for arrival and departure of PCI devices.
> 
> Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Cc: Andreas Faerber" <afaerber@suse.de>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
> Cc: Igor Mammedov <imammedo@redhat.com>
> Cc: Markus Armbruster <armbru@redhat.com>
> Cc: Thomas Huth <thuth@linux.vnet.ibm.com>
> Cc: Christian Borntraeger <borntraeger@de.ibm.com>
> ---
>  hw/core/qdev.c          |   54 +++++++++++++++++++++++++++++++++++++++++++++++
>  include/hw/qdev-core.h  |   10 +++++++++
>  include/qemu/typedefs.h |    1 +
>  3 files changed, 65 insertions(+)
> 
> diff --git a/hw/core/qdev.c b/hw/core/qdev.c
> index fcb1638..4a9c1f6 100644
> --- a/hw/core/qdev.c
> +++ b/hw/core/qdev.c
> @@ -175,6 +175,56 @@ int qdev_init(DeviceState *dev)
>      return 0;
>  }
>  
> +static QTAILQ_HEAD(qdev_listeners, DeviceListener) qdev_listeners
> +    = QTAILQ_HEAD_INITIALIZER(qdev_listeners);
> +
> +enum ListenerDirection { Forward, Reverse };
> +
> +#define QDEV_LISTENER_CALL(_callback, _direction, _args...)     \
> +    do {                                                        \
> +        DeviceListener *_listener;                              \
> +                                                                \
> +        switch (_direction) {                                   \
> +        case Forward:                                           \
> +            QTAILQ_FOREACH(_listener, &qdev_listeners, link) {  \
> +                if (_listener->_callback) {                     \
> +                    _listener->_callback(_listener, ##_args);   \
> +                }                                               \
> +            }                                                   \
> +            break;                                              \
> +        case Reverse:                                           \
> +            QTAILQ_FOREACH_REVERSE(_listener, &qdev_listeners,  \
> +                                   qdev_listeners, link) {      \
> +                if (_listener->_callback) {                     \
> +                    _listener->_callback(_listener, ##_args);   \
> +                }                                               \
> +            }                                                   \
> +            break;                                              \
> +        default:                                                \
> +            abort();                                            \
> +        }                                                       \
> +    } while (0)
> +
> +static int qdev_listener_add(DeviceState *dev, void *opaque)
> +{
> +    QDEV_LISTENER_CALL(realize, Forward, dev);
> +
> +    return 0;
> +}
> +
> +void qdev_listener_register(DeviceListener *listener)
> +{
> +    QTAILQ_INSERT_TAIL(&qdev_listeners, listener, link);
> +
> +    qbus_walk_children(sysbus_get_default(), NULL, NULL, qdev_listener_add,
> +                       NULL, NULL);
> +}
> +
> +void qdev_listener_unregister(DeviceListener *listener)
> +{
> +    QTAILQ_REMOVE(&qdev_listeners, listener, link);
> +}
> +
>  static void device_realize(DeviceState *dev, Error **errp)
>  {
>      DeviceClass *dc = DEVICE_GET_CLASS(dev);
> @@ -186,12 +236,16 @@ static void device_realize(DeviceState *dev, Error **errp)
>              return;
>          }
>      }
> +
> +    QDEV_LISTENER_CALL(realize, Forward, dev);
>  }
>  
>  static void device_unrealize(DeviceState *dev, Error **errp)
>  {
>      DeviceClass *dc = DEVICE_GET_CLASS(dev);
>  
> +    QDEV_LISTENER_CALL(unrealize, Reverse, dev);
> +
>      if (dc->exit) {
>          int rc = dc->exit(dev);
>          if (rc < 0) {
> diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
> index 178fee2..f2dc267 100644
> --- a/include/hw/qdev-core.h
> +++ b/include/hw/qdev-core.h
> @@ -167,6 +167,12 @@ struct DeviceState {
>      int alias_required_for_version;
>  };
>  
> +struct DeviceListener {
> +    void (*realize)(DeviceListener *listener, DeviceState *dev);
> +    void (*unrealize)(DeviceListener *listener, DeviceState *dev);
> +    QTAILQ_ENTRY(DeviceListener) link;
> +};
> +
>  #define TYPE_BUS "bus"
>  #define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS)
>  #define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS)
> @@ -368,4 +374,8 @@ static inline void qbus_set_hotplug_handler(BusState *bus, DeviceState *handler,
>                               QDEV_HOTPLUG_HANDLER_PROPERTY, errp);
>      bus->allow_hotplug = 1;
>  }
> +
> +void qdev_listener_register(DeviceListener *listener);
> +void qdev_listener_unregister(DeviceListener *listener);
> +
>  #endif
> diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
> index 04df51b..e32bca2 100644
> --- a/include/qemu/typedefs.h
> +++ b/include/qemu/typedefs.h
> @@ -20,6 +20,7 @@ typedef struct Property Property;
>  typedef struct PropertyInfo PropertyInfo;
>  typedef struct CompatProperty CompatProperty;
>  typedef struct DeviceState DeviceState;
> +typedef struct DeviceListener DeviceListener;
>  typedef struct BusState BusState;
>  typedef struct BusClass BusClass;
>  
> -- 
> 1.7.10.4
> 
>
Michael S. Tsirkin Dec. 3, 2014, 1:40 p.m. UTC | #2
On Wed, Dec 03, 2014 at 12:29:43PM +0000, Stefano Stabellini wrote:
> The second patch is already Acked.
> You just need a review on this one to move forward, right?
> 
> Andreas, Michael?

Looks like a generic qdev thing, nothing to do with me.

> On Wed, 3 Dec 2014, Paul Durrant wrote:
> > The Xen ioreq-server API, introduced in Xen 4.5, requires that PCI device
> > models explicitly register with Xen for config space accesses. This patch
> > adds a listener interface into qdev-core which can be used by the Xen
> > interface code to monitor for arrival and departure of PCI devices.
> > 
> > Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
> > Cc: Michael S. Tsirkin <mst@redhat.com>
> > Cc: Andreas Faerber" <afaerber@suse.de>
> > Cc: Paolo Bonzini <pbonzini@redhat.com>
> > Cc: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
> > Cc: Igor Mammedov <imammedo@redhat.com>
> > Cc: Markus Armbruster <armbru@redhat.com>
> > Cc: Thomas Huth <thuth@linux.vnet.ibm.com>
> > Cc: Christian Borntraeger <borntraeger@de.ibm.com>
> > ---
> >  hw/core/qdev.c          |   54 +++++++++++++++++++++++++++++++++++++++++++++++
> >  include/hw/qdev-core.h  |   10 +++++++++
> >  include/qemu/typedefs.h |    1 +
> >  3 files changed, 65 insertions(+)
> > 
> > diff --git a/hw/core/qdev.c b/hw/core/qdev.c
> > index fcb1638..4a9c1f6 100644
> > --- a/hw/core/qdev.c
> > +++ b/hw/core/qdev.c
> > @@ -175,6 +175,56 @@ int qdev_init(DeviceState *dev)
> >      return 0;
> >  }
> >  
> > +static QTAILQ_HEAD(qdev_listeners, DeviceListener) qdev_listeners
> > +    = QTAILQ_HEAD_INITIALIZER(qdev_listeners);
> > +
> > +enum ListenerDirection { Forward, Reverse };
> > +
> > +#define QDEV_LISTENER_CALL(_callback, _direction, _args...)     \
> > +    do {                                                        \
> > +        DeviceListener *_listener;                              \
> > +                                                                \
> > +        switch (_direction) {                                   \
> > +        case Forward:                                           \
> > +            QTAILQ_FOREACH(_listener, &qdev_listeners, link) {  \
> > +                if (_listener->_callback) {                     \
> > +                    _listener->_callback(_listener, ##_args);   \
> > +                }                                               \
> > +            }                                                   \
> > +            break;                                              \
> > +        case Reverse:                                           \
> > +            QTAILQ_FOREACH_REVERSE(_listener, &qdev_listeners,  \
> > +                                   qdev_listeners, link) {      \
> > +                if (_listener->_callback) {                     \
> > +                    _listener->_callback(_listener, ##_args);   \
> > +                }                                               \
> > +            }                                                   \
> > +            break;                                              \
> > +        default:                                                \
> > +            abort();                                            \
> > +        }                                                       \
> > +    } while (0)
> > +
> > +static int qdev_listener_add(DeviceState *dev, void *opaque)
> > +{
> > +    QDEV_LISTENER_CALL(realize, Forward, dev);
> > +
> > +    return 0;
> > +}
> > +
> > +void qdev_listener_register(DeviceListener *listener)
> > +{
> > +    QTAILQ_INSERT_TAIL(&qdev_listeners, listener, link);
> > +
> > +    qbus_walk_children(sysbus_get_default(), NULL, NULL, qdev_listener_add,
> > +                       NULL, NULL);
> > +}
> > +
> > +void qdev_listener_unregister(DeviceListener *listener)
> > +{
> > +    QTAILQ_REMOVE(&qdev_listeners, listener, link);
> > +}
> > +
> >  static void device_realize(DeviceState *dev, Error **errp)
> >  {
> >      DeviceClass *dc = DEVICE_GET_CLASS(dev);
> > @@ -186,12 +236,16 @@ static void device_realize(DeviceState *dev, Error **errp)
> >              return;
> >          }
> >      }
> > +
> > +    QDEV_LISTENER_CALL(realize, Forward, dev);
> >  }
> >  
> >  static void device_unrealize(DeviceState *dev, Error **errp)
> >  {
> >      DeviceClass *dc = DEVICE_GET_CLASS(dev);
> >  
> > +    QDEV_LISTENER_CALL(unrealize, Reverse, dev);
> > +
> >      if (dc->exit) {
> >          int rc = dc->exit(dev);
> >          if (rc < 0) {
> > diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
> > index 178fee2..f2dc267 100644
> > --- a/include/hw/qdev-core.h
> > +++ b/include/hw/qdev-core.h
> > @@ -167,6 +167,12 @@ struct DeviceState {
> >      int alias_required_for_version;
> >  };
> >  
> > +struct DeviceListener {
> > +    void (*realize)(DeviceListener *listener, DeviceState *dev);
> > +    void (*unrealize)(DeviceListener *listener, DeviceState *dev);
> > +    QTAILQ_ENTRY(DeviceListener) link;
> > +};
> > +
> >  #define TYPE_BUS "bus"
> >  #define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS)
> >  #define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS)
> > @@ -368,4 +374,8 @@ static inline void qbus_set_hotplug_handler(BusState *bus, DeviceState *handler,
> >                               QDEV_HOTPLUG_HANDLER_PROPERTY, errp);
> >      bus->allow_hotplug = 1;
> >  }
> > +
> > +void qdev_listener_register(DeviceListener *listener);
> > +void qdev_listener_unregister(DeviceListener *listener);
> > +
> >  #endif
> > diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
> > index 04df51b..e32bca2 100644
> > --- a/include/qemu/typedefs.h
> > +++ b/include/qemu/typedefs.h
> > @@ -20,6 +20,7 @@ typedef struct Property Property;
> >  typedef struct PropertyInfo PropertyInfo;
> >  typedef struct CompatProperty CompatProperty;
> >  typedef struct DeviceState DeviceState;
> > +typedef struct DeviceListener DeviceListener;
> >  typedef struct BusState BusState;
> >  typedef struct BusClass BusClass;
> >  
> > -- 
> > 1.7.10.4
> > 
> >
Paolo Bonzini Dec. 3, 2014, 1:55 p.m. UTC | #3
On 03/12/2014 14:40, Michael S. Tsirkin wrote:
> On Wed, Dec 03, 2014 at 12:29:43PM +0000, Stefano Stabellini wrote:
>> The second patch is already Acked.
>> You just need a review on this one to move forward, right?
>>
>> Andreas, Michael?
> 
> Looks like a generic qdev thing, nothing to do with me.
> 
>> On Wed, 3 Dec 2014, Paul Durrant wrote:
>>> The Xen ioreq-server API, introduced in Xen 4.5, requires that PCI device
>>> models explicitly register with Xen for config space accesses. This patch
>>> adds a listener interface into qdev-core which can be used by the Xen
>>> interface code to monitor for arrival and departure of PCI devices.
>>>
>>> Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
>>> Cc: Michael S. Tsirkin <mst@redhat.com>
>>> Cc: Andreas Faerber" <afaerber@suse.de>
>>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>>> Cc: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
>>> Cc: Igor Mammedov <imammedo@redhat.com>
>>> Cc: Markus Armbruster <armbru@redhat.com>
>>> Cc: Thomas Huth <thuth@linux.vnet.ibm.com>
>>> Cc: Christian Borntraeger <borntraeger@de.ibm.com>
>>> ---
>>>  hw/core/qdev.c          |   54 +++++++++++++++++++++++++++++++++++++++++++++++
>>>  include/hw/qdev-core.h  |   10 +++++++++
>>>  include/qemu/typedefs.h |    1 +
>>>  3 files changed, 65 insertions(+)
>>>
>>> diff --git a/hw/core/qdev.c b/hw/core/qdev.c
>>> index fcb1638..4a9c1f6 100644
>>> --- a/hw/core/qdev.c
>>> +++ b/hw/core/qdev.c
>>> @@ -175,6 +175,56 @@ int qdev_init(DeviceState *dev)
>>>      return 0;
>>>  }
>>>  
>>> +static QTAILQ_HEAD(qdev_listeners, DeviceListener) qdev_listeners
>>> +    = QTAILQ_HEAD_INITIALIZER(qdev_listeners);
>>> +
>>> +enum ListenerDirection { Forward, Reverse };
>>> +
>>> +#define QDEV_LISTENER_CALL(_callback, _direction, _args...)     \
>>> +    do {                                                        \
>>> +        DeviceListener *_listener;                              \
>>> +                                                                \
>>> +        switch (_direction) {                                   \
>>> +        case Forward:                                           \
>>> +            QTAILQ_FOREACH(_listener, &qdev_listeners, link) {  \
>>> +                if (_listener->_callback) {                     \
>>> +                    _listener->_callback(_listener, ##_args);   \
>>> +                }                                               \
>>> +            }                                                   \
>>> +            break;                                              \
>>> +        case Reverse:                                           \
>>> +            QTAILQ_FOREACH_REVERSE(_listener, &qdev_listeners,  \
>>> +                                   qdev_listeners, link) {      \
>>> +                if (_listener->_callback) {                     \
>>> +                    _listener->_callback(_listener, ##_args);   \
>>> +                }                                               \
>>> +            }                                                   \
>>> +            break;                                              \
>>> +        default:                                                \
>>> +            abort();                                            \
>>> +        }                                                       \
>>> +    } while (0)
>>> +
>>> +static int qdev_listener_add(DeviceState *dev, void *opaque)
>>> +{
>>> +    QDEV_LISTENER_CALL(realize, Forward, dev);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +void qdev_listener_register(DeviceListener *listener)
>>> +{
>>> +    QTAILQ_INSERT_TAIL(&qdev_listeners, listener, link);
>>> +
>>> +    qbus_walk_children(sysbus_get_default(), NULL, NULL, qdev_listener_add,
>>> +                       NULL, NULL);
>>> +}
>>> +
>>> +void qdev_listener_unregister(DeviceListener *listener)
>>> +{
>>> +    QTAILQ_REMOVE(&qdev_listeners, listener, link);
>>> +}
>>> +
>>>  static void device_realize(DeviceState *dev, Error **errp)
>>>  {
>>>      DeviceClass *dc = DEVICE_GET_CLASS(dev);
>>> @@ -186,12 +236,16 @@ static void device_realize(DeviceState *dev, Error **errp)
>>>              return;
>>>          }
>>>      }
>>> +
>>> +    QDEV_LISTENER_CALL(realize, Forward, dev);
>>>  }
>>>  
>>>  static void device_unrealize(DeviceState *dev, Error **errp)
>>>  {
>>>      DeviceClass *dc = DEVICE_GET_CLASS(dev);
>>>  
>>> +    QDEV_LISTENER_CALL(unrealize, Reverse, dev);

These need to be in device_set_realized.  device_realize and
device_unrealize are just for backwards-compatibility to devices that
still use init/exit.

Also, this has to be call to be _after_ unrealization, i.e. after
setting dev->pending_deleted_event in device_set_realize.

Paolo

>>>      if (dc->exit) {
>>>          int rc = dc->exit(dev);
>>>          if (rc < 0) {
>>> diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
>>> index 178fee2..f2dc267 100644
>>> --- a/include/hw/qdev-core.h
>>> +++ b/include/hw/qdev-core.h
>>> @@ -167,6 +167,12 @@ struct DeviceState {
>>>      int alias_required_for_version;
>>>  };
>>>  
>>> +struct DeviceListener {
>>> +    void (*realize)(DeviceListener *listener, DeviceState *dev);
>>> +    void (*unrealize)(DeviceListener *listener, DeviceState *dev);
>>> +    QTAILQ_ENTRY(DeviceListener) link;
>>> +};
>>> +
>>>  #define TYPE_BUS "bus"
>>>  #define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS)
>>>  #define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS)
>>> @@ -368,4 +374,8 @@ static inline void qbus_set_hotplug_handler(BusState *bus, DeviceState *handler,
>>>                               QDEV_HOTPLUG_HANDLER_PROPERTY, errp);
>>>      bus->allow_hotplug = 1;
>>>  }
>>> +
>>> +void qdev_listener_register(DeviceListener *listener);
>>> +void qdev_listener_unregister(DeviceListener *listener);
>>> +
>>>  #endif
>>> diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
>>> index 04df51b..e32bca2 100644
>>> --- a/include/qemu/typedefs.h
>>> +++ b/include/qemu/typedefs.h
>>> @@ -20,6 +20,7 @@ typedef struct Property Property;
>>>  typedef struct PropertyInfo PropertyInfo;
>>>  typedef struct CompatProperty CompatProperty;
>>>  typedef struct DeviceState DeviceState;
>>> +typedef struct DeviceListener DeviceListener;
>>>  typedef struct BusState BusState;
>>>  typedef struct BusClass BusClass;
>>>  
>>> -- 
>>> 1.7.10.4
>>>
>>>
Paul Durrant Dec. 3, 2014, 2:11 p.m. UTC | #4
> -----Original Message-----
> From: Paolo Bonzini [mailto:pbonzini@redhat.com]
> Sent: 03 December 2014 13:56
> To: Michael S. Tsirkin; Stefano Stabellini
> Cc: Paul Durrant; qemu-devel@nongnu.org; Peter Crosthwaite; Thomas
> Huth; Markus Armbruster; Christian Borntraeger; Igor Mammedov; Andreas
> Faerber
> Subject: Re: [Qemu-devel] [PATCH v4 REPOST 1/2] Add device listener
> interface
> 
> 
> 
> On 03/12/2014 14:40, Michael S. Tsirkin wrote:
> > On Wed, Dec 03, 2014 at 12:29:43PM +0000, Stefano Stabellini wrote:
> >> The second patch is already Acked.
> >> You just need a review on this one to move forward, right?
> >>
> >> Andreas, Michael?
> >
> > Looks like a generic qdev thing, nothing to do with me.
> >
> >> On Wed, 3 Dec 2014, Paul Durrant wrote:
> >>> The Xen ioreq-server API, introduced in Xen 4.5, requires that PCI device
> >>> models explicitly register with Xen for config space accesses. This patch
> >>> adds a listener interface into qdev-core which can be used by the Xen
> >>> interface code to monitor for arrival and departure of PCI devices.
> >>>
> >>> Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
> >>> Cc: Michael S. Tsirkin <mst@redhat.com>
> >>> Cc: Andreas Faerber" <afaerber@suse.de>
> >>> Cc: Paolo Bonzini <pbonzini@redhat.com>
> >>> Cc: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
> >>> Cc: Igor Mammedov <imammedo@redhat.com>
> >>> Cc: Markus Armbruster <armbru@redhat.com>
> >>> Cc: Thomas Huth <thuth@linux.vnet.ibm.com>
> >>> Cc: Christian Borntraeger <borntraeger@de.ibm.com>
> >>> ---
> >>>  hw/core/qdev.c          |   54
> +++++++++++++++++++++++++++++++++++++++++++++++
> >>>  include/hw/qdev-core.h  |   10 +++++++++
> >>>  include/qemu/typedefs.h |    1 +
> >>>  3 files changed, 65 insertions(+)
> >>>
> >>> diff --git a/hw/core/qdev.c b/hw/core/qdev.c
> >>> index fcb1638..4a9c1f6 100644
> >>> --- a/hw/core/qdev.c
> >>> +++ b/hw/core/qdev.c
> >>> @@ -175,6 +175,56 @@ int qdev_init(DeviceState *dev)
> >>>      return 0;
> >>>  }
> >>>
> >>> +static QTAILQ_HEAD(qdev_listeners, DeviceListener) qdev_listeners
> >>> +    = QTAILQ_HEAD_INITIALIZER(qdev_listeners);
> >>> +
> >>> +enum ListenerDirection { Forward, Reverse };
> >>> +
> >>> +#define QDEV_LISTENER_CALL(_callback, _direction, _args...)     \
> >>> +    do {                                                        \
> >>> +        DeviceListener *_listener;                              \
> >>> +                                                                \
> >>> +        switch (_direction) {                                   \
> >>> +        case Forward:                                           \
> >>> +            QTAILQ_FOREACH(_listener, &qdev_listeners, link) {  \
> >>> +                if (_listener->_callback) {                     \
> >>> +                    _listener->_callback(_listener, ##_args);   \
> >>> +                }                                               \
> >>> +            }                                                   \
> >>> +            break;                                              \
> >>> +        case Reverse:                                           \
> >>> +            QTAILQ_FOREACH_REVERSE(_listener, &qdev_listeners,  \
> >>> +                                   qdev_listeners, link) {      \
> >>> +                if (_listener->_callback) {                     \
> >>> +                    _listener->_callback(_listener, ##_args);   \
> >>> +                }                                               \
> >>> +            }                                                   \
> >>> +            break;                                              \
> >>> +        default:                                                \
> >>> +            abort();                                            \
> >>> +        }                                                       \
> >>> +    } while (0)
> >>> +
> >>> +static int qdev_listener_add(DeviceState *dev, void *opaque)
> >>> +{
> >>> +    QDEV_LISTENER_CALL(realize, Forward, dev);
> >>> +
> >>> +    return 0;
> >>> +}
> >>> +
> >>> +void qdev_listener_register(DeviceListener *listener)
> >>> +{
> >>> +    QTAILQ_INSERT_TAIL(&qdev_listeners, listener, link);
> >>> +
> >>> +    qbus_walk_children(sysbus_get_default(), NULL, NULL,
> qdev_listener_add,
> >>> +                       NULL, NULL);
> >>> +}
> >>> +
> >>> +void qdev_listener_unregister(DeviceListener *listener)
> >>> +{
> >>> +    QTAILQ_REMOVE(&qdev_listeners, listener, link);
> >>> +}
> >>> +
> >>>  static void device_realize(DeviceState *dev, Error **errp)
> >>>  {
> >>>      DeviceClass *dc = DEVICE_GET_CLASS(dev);
> >>> @@ -186,12 +236,16 @@ static void device_realize(DeviceState *dev,
> Error **errp)
> >>>              return;
> >>>          }
> >>>      }
> >>> +
> >>> +    QDEV_LISTENER_CALL(realize, Forward, dev);
> >>>  }
> >>>
> >>>  static void device_unrealize(DeviceState *dev, Error **errp)
> >>>  {
> >>>      DeviceClass *dc = DEVICE_GET_CLASS(dev);
> >>>
> >>> +    QDEV_LISTENER_CALL(unrealize, Reverse, dev);
> 
> These need to be in device_set_realized.  device_realize and
> device_unrealize are just for backwards-compatibility to devices that
> still use init/exit.
> 
> Also, this has to be call to be _after_ unrealization, i.e. after
> setting dev->pending_deleted_event in device_set_realize.
> 

Ok. Thanks. I'll move the calls.

  Paul

> Paolo
> 
> >>>      if (dc->exit) {
> >>>          int rc = dc->exit(dev);
> >>>          if (rc < 0) {
> >>> diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
> >>> index 178fee2..f2dc267 100644
> >>> --- a/include/hw/qdev-core.h
> >>> +++ b/include/hw/qdev-core.h
> >>> @@ -167,6 +167,12 @@ struct DeviceState {
> >>>      int alias_required_for_version;
> >>>  };
> >>>
> >>> +struct DeviceListener {
> >>> +    void (*realize)(DeviceListener *listener, DeviceState *dev);
> >>> +    void (*unrealize)(DeviceListener *listener, DeviceState *dev);
> >>> +    QTAILQ_ENTRY(DeviceListener) link;
> >>> +};
> >>> +
> >>>  #define TYPE_BUS "bus"
> >>>  #define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS)
> >>>  #define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass),
> TYPE_BUS)
> >>> @@ -368,4 +374,8 @@ static inline void
> qbus_set_hotplug_handler(BusState *bus, DeviceState *handler,
> >>>                               QDEV_HOTPLUG_HANDLER_PROPERTY, errp);
> >>>      bus->allow_hotplug = 1;
> >>>  }
> >>> +
> >>> +void qdev_listener_register(DeviceListener *listener);
> >>> +void qdev_listener_unregister(DeviceListener *listener);
> >>> +
> >>>  #endif
> >>> diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
> >>> index 04df51b..e32bca2 100644
> >>> --- a/include/qemu/typedefs.h
> >>> +++ b/include/qemu/typedefs.h
> >>> @@ -20,6 +20,7 @@ typedef struct Property Property;
> >>>  typedef struct PropertyInfo PropertyInfo;
> >>>  typedef struct CompatProperty CompatProperty;
> >>>  typedef struct DeviceState DeviceState;
> >>> +typedef struct DeviceListener DeviceListener;
> >>>  typedef struct BusState BusState;
> >>>  typedef struct BusClass BusClass;
> >>>
> >>> --
> >>> 1.7.10.4
> >>>
> >>>
Andreas Färber Dec. 3, 2014, 2:26 p.m. UTC | #5
Am 03.12.2014 um 13:29 schrieb Stefano Stabellini:
> The second patch is already Acked.
> You just need a review on this one to move forward, right?
> 
> Andreas, Michael?

Once again, I would appreciate if such patches consistently used device_
/ DEVICE_ rather than qdev_ / QDEV_. In particular given that
DeviceListener is being used already and this doesn't seem to rely on
old qdev. But other than that no objections. Will be back in the office
next week.

Regards,
Andreas
Paul Durrant Dec. 5, 2014, 10:28 a.m. UTC | #6
> -----Original Message-----
> From: Andreas Färber [mailto:afaerber@suse.de]
> Sent: 03 December 2014 14:27
> To: Stefano Stabellini; Paul Durrant
> Cc: qemu-devel@nongnu.org; Peter Crosthwaite; Thomas Huth; Michael S.
> Tsirkin; Markus Armbruster; Christian Borntraeger; Igor Mammedov; Paolo
> Bonzini
> Subject: Re: [Qemu-devel] [PATCH v4 REPOST 1/2] Add device listener
> interface
> 
> Am 03.12.2014 um 13:29 schrieb Stefano Stabellini:
> > The second patch is already Acked.
> > You just need a review on this one to move forward, right?
> >
> > Andreas, Michael?
> 
> Once again, I would appreciate if such patches consistently used device_
> / DEVICE_ rather than qdev_ / QDEV_. In particular given that
> DeviceListener is being used already and this doesn't seem to rely on
> old qdev. But other than that no objections. Will be back in the office
> next week.
> 

Ok. I'll fix the naming.

  Paul

> Regards,
> Andreas
> 
> --
> SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
> GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 21284 AG Nürnberg
diff mbox

Patch

diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index fcb1638..4a9c1f6 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -175,6 +175,56 @@  int qdev_init(DeviceState *dev)
     return 0;
 }
 
+static QTAILQ_HEAD(qdev_listeners, DeviceListener) qdev_listeners
+    = QTAILQ_HEAD_INITIALIZER(qdev_listeners);
+
+enum ListenerDirection { Forward, Reverse };
+
+#define QDEV_LISTENER_CALL(_callback, _direction, _args...)     \
+    do {                                                        \
+        DeviceListener *_listener;                              \
+                                                                \
+        switch (_direction) {                                   \
+        case Forward:                                           \
+            QTAILQ_FOREACH(_listener, &qdev_listeners, link) {  \
+                if (_listener->_callback) {                     \
+                    _listener->_callback(_listener, ##_args);   \
+                }                                               \
+            }                                                   \
+            break;                                              \
+        case Reverse:                                           \
+            QTAILQ_FOREACH_REVERSE(_listener, &qdev_listeners,  \
+                                   qdev_listeners, link) {      \
+                if (_listener->_callback) {                     \
+                    _listener->_callback(_listener, ##_args);   \
+                }                                               \
+            }                                                   \
+            break;                                              \
+        default:                                                \
+            abort();                                            \
+        }                                                       \
+    } while (0)
+
+static int qdev_listener_add(DeviceState *dev, void *opaque)
+{
+    QDEV_LISTENER_CALL(realize, Forward, dev);
+
+    return 0;
+}
+
+void qdev_listener_register(DeviceListener *listener)
+{
+    QTAILQ_INSERT_TAIL(&qdev_listeners, listener, link);
+
+    qbus_walk_children(sysbus_get_default(), NULL, NULL, qdev_listener_add,
+                       NULL, NULL);
+}
+
+void qdev_listener_unregister(DeviceListener *listener)
+{
+    QTAILQ_REMOVE(&qdev_listeners, listener, link);
+}
+
 static void device_realize(DeviceState *dev, Error **errp)
 {
     DeviceClass *dc = DEVICE_GET_CLASS(dev);
@@ -186,12 +236,16 @@  static void device_realize(DeviceState *dev, Error **errp)
             return;
         }
     }
+
+    QDEV_LISTENER_CALL(realize, Forward, dev);
 }
 
 static void device_unrealize(DeviceState *dev, Error **errp)
 {
     DeviceClass *dc = DEVICE_GET_CLASS(dev);
 
+    QDEV_LISTENER_CALL(unrealize, Reverse, dev);
+
     if (dc->exit) {
         int rc = dc->exit(dev);
         if (rc < 0) {
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 178fee2..f2dc267 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -167,6 +167,12 @@  struct DeviceState {
     int alias_required_for_version;
 };
 
+struct DeviceListener {
+    void (*realize)(DeviceListener *listener, DeviceState *dev);
+    void (*unrealize)(DeviceListener *listener, DeviceState *dev);
+    QTAILQ_ENTRY(DeviceListener) link;
+};
+
 #define TYPE_BUS "bus"
 #define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS)
 #define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS)
@@ -368,4 +374,8 @@  static inline void qbus_set_hotplug_handler(BusState *bus, DeviceState *handler,
                              QDEV_HOTPLUG_HANDLER_PROPERTY, errp);
     bus->allow_hotplug = 1;
 }
+
+void qdev_listener_register(DeviceListener *listener);
+void qdev_listener_unregister(DeviceListener *listener);
+
 #endif
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 04df51b..e32bca2 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -20,6 +20,7 @@  typedef struct Property Property;
 typedef struct PropertyInfo PropertyInfo;
 typedef struct CompatProperty CompatProperty;
 typedef struct DeviceState DeviceState;
+typedef struct DeviceListener DeviceListener;
 typedef struct BusState BusState;
 typedef struct BusClass BusClass;