Add a /chardevs container object to hold the list of chardevs.
(Note: QTAILQ chardevs is going away in the following commits)
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
include/sysemu/char.h | 3 ++-
chardev/char.c | 46 ++++++++++++++++++++++++++++++++++++++--------
gdbstub.c | 2 +-
hw/bt/hci-csr.c | 2 +-
4 files changed, 42 insertions(+), 11 deletions(-)
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index a30ff3fa80..e3f3a10d17 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -490,7 +490,8 @@ typedef struct ChardevClass {
} ChardevClass;
Chardev *qemu_chardev_new(const char *id, const char *typename,
- ChardevBackend *backend, Error **errp);
+ ChardevBackend *backend, bool enlist,
+ Error **errp);
extern int term_escape_char;
diff --git a/chardev/char.c b/chardev/char.c
index 9f02c6d5f1..5a12a79c3b 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -45,6 +45,11 @@
static QTAILQ_HEAD(ChardevHead, Chardev) chardevs =
QTAILQ_HEAD_INITIALIZER(chardevs);
+static Object *get_chardevs_root(void)
+{
+ return container_get(object_get_root(), "/chardevs");
+}
+
void qemu_chr_be_event(Chardev *s, int event)
{
CharBackend *be = s->be;
@@ -804,7 +809,7 @@ static Chardev *qemu_chardev_add(const char *id, const char *typename,
return NULL;
}
- chr = qemu_chardev_new(id, typename, backend, errp);
+ chr = qemu_chardev_new(id, typename, backend, true, errp);
if (!chr) {
return NULL;
}
@@ -1061,8 +1066,14 @@ void qemu_chr_fe_disconnect(CharBackend *be)
void qemu_chr_delete(Chardev *chr)
{
- QTAILQ_REMOVE(&chardevs, chr, next);
- object_unref(OBJECT(chr));
+ if (QTAILQ_IN_USE(chr, next)) {
+ QTAILQ_REMOVE(&chardevs, chr, next);
+ }
+ if (OBJECT(chr)->parent) {
+ object_unparent(OBJECT(chr));
+ } else {
+ object_unref(OBJECT(chr));
+ }
}
ChardevInfoList *qmp_query_chardev(Error **errp)
@@ -1224,22 +1235,33 @@ void qemu_chr_set_feature(Chardev *chr,
}
Chardev *qemu_chardev_new(const char *id, const char *typename,
- ChardevBackend *backend, Error **errp)
+ ChardevBackend *backend, bool enlist,
+ Error **errp)
{
+ Object *obj;
Chardev *chr = NULL;
Error *local_err = NULL;
bool be_opened = true;
assert(g_str_has_prefix(typename, "chardev-"));
- chr = CHARDEV(object_new(typename));
+ if (enlist) {
+ obj = object_new_with_props(typename, get_chardevs_root(),
+ id, &local_err, NULL);
+ } else {
+ obj = object_new(typename);
+ }
+ if (local_err) {
+ assert(!obj);
+ goto end;
+ }
+
+ chr = CHARDEV(obj);
chr->label = g_strdup(id);
qemu_char_open(chr, backend, &be_opened, &local_err);
if (local_err) {
- error_propagate(errp, local_err);
- object_unref(OBJECT(chr));
- return NULL;
+ goto end;
}
if (!chr->filename) {
@@ -1249,6 +1271,14 @@ Chardev *qemu_chardev_new(const char *id, const char *typename,
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
}
+end:
+ if (local_err) {
+ error_propagate(errp, local_err);
+ if (chr) {
+ qemu_chr_delete(chr);
+ }
+ return NULL;
+ }
return chr;
}
diff --git a/gdbstub.c b/gdbstub.c
index 755a8e378d..613ac48fed 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1793,7 +1793,7 @@ int gdbserver_start(const char *device)
/* Initialize a monitor terminal for gdb */
mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_GDB,
- NULL, &error_abort);
+ NULL, false, &error_abort);
monitor_init(mon_chr, 0);
} else {
if (qemu_chr_fe_get_driver(&s->chr)) {
diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c
index 3c193848fc..9c211e89c4 100644
--- a/hw/bt/hci-csr.c
+++ b/hw/bt/hci-csr.c
@@ -503,7 +503,7 @@ static const TypeInfo char_hci_type_info = {
Chardev *uart_hci_init(void)
{
return qemu_chardev_new(NULL, TYPE_CHARDEV_HCI,
- NULL, &error_abort);
+ NULL, false, &error_abort);
}
static void register_types(void)
--
2.11.0.295.gd7dffce1c.dirty
On 02/02/2017 15:51, Marc-André Lureau wrote:
> + if (QTAILQ_IN_USE(chr, next)) {
> + QTAILQ_REMOVE(&chardevs, chr, next);
> + }
> + if (OBJECT(chr)->parent) {
> + object_unparent(OBJECT(chr));
> + } else {
> + object_unref(OBJECT(chr));
> + }
What's the case where the "else" is used? Probably qemu_chr_delete
callers should be changed to use object_unparent or object_unref directly.
Paolo
Hi
----- Original Message -----
>
>
> On 02/02/2017 15:51, Marc-André Lureau wrote:
> > + if (QTAILQ_IN_USE(chr, next)) {
> > + QTAILQ_REMOVE(&chardevs, chr, next);
> > + }
> > + if (OBJECT(chr)->parent) {
> > + object_unparent(OBJECT(chr));
> > + } else {
> > + object_unref(OBJECT(chr));
> > + }
>
> What's the case where the "else" is used? Probably qemu_chr_delete
> callers should be changed to use object_unparent or object_unref directly.
I thought about that, but calling object_unparent() seems weird, since callers aren't much aware of the fact that chardev are added or not to a container (useless distinction imho). I wish the last object_unref() would automatically unparent, if the object has a parent. Would that be acceptable?
On 07/02/2017 21:03, Marc-André Lureau wrote:
> Hi
>
> ----- Original Message -----
>>
>>
>> On 02/02/2017 15:51, Marc-André Lureau wrote:
>>> + if (QTAILQ_IN_USE(chr, next)) {
>>> + QTAILQ_REMOVE(&chardevs, chr, next);
>>> + }
>>> + if (OBJECT(chr)->parent) {
>>> + object_unparent(OBJECT(chr));
>>> + } else {
>>> + object_unref(OBJECT(chr));
>>> + }
>>
>> What's the case where the "else" is used? Probably qemu_chr_delete
>> callers should be changed to use object_unparent or object_unref directly.
>
> I thought about that, but calling object_unparent() seems weird,
> since callers aren't much aware of the fact that chardev are added or not to a
> container (useless distinction imho). I wish the last object_unref()
> would automatically unparent, if the object has a parent. Would that be
> acceptable?
There is a distinction between the two. The idea is that unparent
removes all persistent references in the object tree, while unref only
removes transient references. So for example unparent will detach a
device from its bus. Unparent is basically exploiting the object tree
in order to simplify the handling of reference cycles.
Once you add an object with object_property_add_child, you probably
should remove any transient references you have (such as the one you got
with object_new) and from that point on use object_unparent only.
Paolo
Hi
On Fri, Feb 10, 2017 at 4:18 AM Paolo Bonzini <pbonzini@redhat.com> wrote:
>
>
> On 07/02/2017 21:03, Marc-André Lureau wrote:
> > Hi
> >
> > ----- Original Message -----
> >>
> >>
> >> On 02/02/2017 15:51, Marc-André Lureau wrote:
> >>> + if (QTAILQ_IN_USE(chr, next)) {
> >>> + QTAILQ_REMOVE(&chardevs, chr, next);
> >>> + }
> >>> + if (OBJECT(chr)->parent) {
> >>> + object_unparent(OBJECT(chr));
> >>> + } else {
> >>> + object_unref(OBJECT(chr));
> >>> + }
> >>
> >> What's the case where the "else" is used? Probably qemu_chr_delete
> >> callers should be changed to use object_unparent or object_unref
> directly.
> >
> > I thought about that, but calling object_unparent() seems weird,
> > since callers aren't much aware of the fact that chardev are added or
> not to a
> > container (useless distinction imho). I wish the last object_unref()
> > would automatically unparent, if the object has a parent. Would that be
> > acceptable?
>
> There is a distinction between the two. The idea is that unparent
> removes all persistent references in the object tree, while unref only
> removes transient references. So for example unparent will detach a
> device from its bus. Unparent is basically exploiting the object tree
> in order to simplify the handling of reference cycles.
>
> Once you add an object with object_property_add_child, you probably
> should remove any transient references you have (such as the one you got
> with object_new) and from that point on use object_unparent only.
>
But if you unparent with the last ref, you remove the burden of knowing if
the object has been parented from the user. I don't see why that would
conflict with object_unparent(), you could still unparent(), and keep the
object referenced somewhere else. The two are not incompatible to me.
Afaik, most widget/hierarchy API work like that, the last unref will
implicitely unparent.
--
Marc-André Lureau
On 10/02/2017 13:14, Marc-André Lureau wrote:
> Hi
>
> On Fri, Feb 10, 2017 at 4:18 AM Paolo Bonzini <pbonzini@redhat.com
> <mailto:pbonzini@redhat.com>> wrote:
>
>
>
> On 07/02/2017 21:03, Marc-André Lureau wrote:
> > Hi
> >
> > ----- Original Message -----
> >>
> >>
> >> On 02/02/2017 15:51, Marc-André Lureau wrote:
> >>> + if (QTAILQ_IN_USE(chr, next)) {
> >>> + QTAILQ_REMOVE(&chardevs, chr, next);
> >>> + }
> >>> + if (OBJECT(chr)->parent) {
> >>> + object_unparent(OBJECT(chr));
> >>> + } else {
> >>> + object_unref(OBJECT(chr));
> >>> + }
> >>
> >> What's the case where the "else" is used? Probably qemu_chr_delete
> >> callers should be changed to use object_unparent or object_unref
> directly.
> >
> > I thought about that, but calling object_unparent() seems weird,
> > since callers aren't much aware of the fact that chardev are added
> or not to a
> > container (useless distinction imho). I wish the last object_unref()
> > would automatically unparent, if the object has a parent. Would
> that be
> > acceptable?
>
> There is a distinction between the two. The idea is that unparent
> removes all persistent references in the object tree, while unref only
> removes transient references. So for example unparent will detach a
> device from its bus. Unparent is basically exploiting the object tree
> in order to simplify the handling of reference cycles.
>
> Once you add an object with object_property_add_child, you probably
> should remove any transient references you have (such as the one you got
> with object_new) and from that point on use object_unparent only.
>
>
> But if you unparent with the last ref, you remove the burden of knowing
> if the object has been parented from the user. I don't see why that
> would conflict with object_unparent(), you could still unparent(), and
> keep the object referenced somewhere else.
Isn't that exactly why you want them to be different? unparent can do
much more than unref, for example in the case of a device it will also
unrealize it and destroy all buses underneath it. Because the device
and bus have a circular reference, you cannot trigger the magic unparent
behavior just by unref'ing the device.
There are just two cases:
- destruction immediately after creation, e.g. on error: new/unref
- successful creation: new/add_child/unref, unparent when deleting
and it's simpler to remember these two than to add magic behavior.
> The two are not incompatible
> to me. Afaik, most widget/hierarchy API work like that, the last unref
> will implicitely unparent.
LibreOffice's has some similarity with QOM, search for "dispose" at
https://people.gnome.org/~michael/blog/2015-08-05-under-the-hood-5-0.html
Paolo
Hi On Fri, Feb 10, 2017 at 4:26 PM Paolo Bonzini <pbonzini@redhat.com> wrote: > > > > > But if you unparent with the last ref, you remove the burden of knowing > > if the object has been parented from the user. I don't see why that > > would conflict with object_unparent(), you could still unparent(), and > > keep the object referenced somewhere else. > > Isn't that exactly why you want them to be different? unparent can do > much more than unref, for example in the case of a device it will also > unrealize it and destroy all buses underneath it. Because the device > Shouldn't the last unref also unrealize/destroy everything? > and bus have a circular reference, you cannot trigger the magic unparent > behavior just by unref'ing the device. > Whoo, we have circular references on purposes? Is this lifecycle documented somewhere? I wonder the rationale behind it. > > There are just two cases: > > - destruction immediately after creation, e.g. on error: new/unref > > - successful creation: new/add_child/unref, unparent when deleting > > and it's simpler to remember these two than to add magic behavior. > > That doesn't change the problem, the user may not know if the object is parented. So you have to pass this information along. > > The two are not incompatible > > to me. Afaik, most widget/hierarchy API work like that, the last unref > > will implicitely unparent. > > LibreOffice's has some similarity with QOM, search for "dispose" at > https://people.gnome.org/~michael/blog/2015-08-05-under-the-hood-5-0.html > > I don't see much parallel with the discussion here except that they had a complicated model and tried to simplify it. That's what I also try to do. -- Marc-André Lureau
On 10/02/2017 13:59, Marc-André Lureau wrote: > > But if you unparent with the last ref, you remove the burden of knowing > > if the object has been parented from the user. I don't see why that > > would conflict with object_unparent(), you could still unparent(), and > > keep the object referenced somewhere else. > > Isn't that exactly why you want them to be different? unparent can do > much more than unref, for example in the case of a device it will also > unrealize it and destroy all buses underneath it. Because the device > > Shouldn't the last unref also unrealize/destroy everything? How could someone say they have the "last unref"? They didn't get that reference from anywhere, the reference is owned by the parent object's child property. > and bus have a circular reference, you cannot trigger the magic unparent > behavior just by unref'ing the device. > > Whoo, we have circular references on purposes? Is this lifecycle > documented somewhere? I wonder the rationale behind it. The same as Libreoffice: we had a model with no reference counting (just "qdev_free") and we tried to adapt it to QOM's reference counting model, in our case by exploiting the object tree. > There are just two cases: > > - destruction immediately after creation, e.g. on error: new/unref > > - successful creation: new/add_child/unref, unparent when deleting > > and it's simpler to remember these two than to add magic behavior. > > That doesn't change the problem, the user may not know if the object is > parented. If the user got a reference for himself via object_ref or object_new, it must use object_unref. If the user wants to remove public knowledge of an object, then they must use object_unparent. If the object is not parented, there's a violation of QOM rules somewhere. Paolo
© 2016 - 2026 Red Hat, Inc.