qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [RFC v2 07/38] queue: add QTAILQ_REMOVE_SEVERAL


From: Emilio G. Cota
Subject: Re: [Qemu-devel] [RFC v2 07/38] queue: add QTAILQ_REMOVE_SEVERAL
Date: Mon, 25 Feb 2019 13:02:17 -0500
User-agent: Mutt/1.9.4 (2018-02-28)

On Mon, Feb 25, 2019 at 16:22:52 +0000, Alex Bennée wrote:
> Emilio G. Cota <address@hidden> writes:
> > +/* remove @left, @right and all elements in between from @head */
> > +#define QTAILQ_REMOVE_SEVERAL(head, left, right, field) do {    \
> > +        if (((right)->field.tqe_next) != NULL)                  \
> > +            (right)->field.tqe_next->field.tqe_prev =           \
> > +                (left)->field.tqe_prev;                         \
> > +        else                                                    \
> > +            (head)->tqh_last = (left)->field.tqe_prev;          \
> > +        *(left)->field.tqe_prev = (right)->field.tqe_next;      \
> 
> This seems wrong, shouldn't it be:
> 
>   (left)->field.tqe_prev->field.tqe_next = (right)->field.tqe_next;

That would make too much sense, wouldn't it!

Looking at QTAILQ_REMOVE is the easiest way to reason about this:

#define QTAILQ_REMOVE(head, elm, field) do {                            \
        if (((elm)->field.tqe_next) != NULL)                            \
                (elm)->field.tqe_next->field.tqe_prev =                 \
                    (elm)->field.tqe_prev;                              \
        else                                                            \
                (head)->tqh_last = (elm)->field.tqe_prev;               \
        *(elm)->field.tqe_prev = (elm)->field.tqe_next;                 \
        (elm)->field.tqe_prev = NULL;                                   \
} while (/*CONSTCOND*/0)

Imagine we're removing the only element in the list. Thus,
*(elm)->field.tqe_prev will be setting (head)->tqh_first (to NULL).
IOW, we can't assume that the previous "element" (whether true element
or head) has a .tqe_next field (the head has .thq_first); note that
tqe_prev is a **, not a *.

> Although to be honest every time I read the QUEUE macros I end up with a 
> headache...

You're not alone.

BTW, this code had to change for v3 because of 7274f01bb8 ("qemu/queue.h:
reimplement QTAILQ without pointer-to-pointers", 2019-01-11)

I think you might like that implementation better, since it is a little
closer to sanity, i.e. kernel-style lists :-)
It uses a more predictable structure (*prev,*next) that is shoehorned
with a union to avoid changing the memory layout.

Thanks,

                Emilio



reply via email to

[Prev in Thread] Current Thread [Next in Thread]