Subject: Re: use of LIST macros from sys/queue.h
To: Matt Thomas <>
From: David Laight <>
List: tech-kern
Date: 09/05/2002 16:37:28
> IMHO these macro perform a useful service.  They allow a common
> implementation of common list operations.

xxx_EMPTY, xxx_FIRST, xxx_NEXT are so trivial that the macros
just hide the obvious impementation.

> By defining QUEUEDEBUG the macros can validate the list operations.
Except that the only common case (removing an item from a Q type
that requires the 'head' to be specified, and giving the wrong head)
isn't checked...

> Lastly, by seeing
> the standard queue macros, you know exactly what type of list
> is being used (list, simpleq, tailq, circleq) and that's useful.

I beg to differ, on seeing the macros I have to go and dig
through queue.h (or queue(3)) to work out what they are implementing,
only then do I know the properties of the list being used.

If you can write code for these sorts of lists in your sleep,
the macros are not necessary.

My favourite list isn't [1] even there :-)


[1] double linked circular list through a null item, where
all the pointers point to the list structure (not the enclosing one).
Allows an item to be on multiple lists, and to be removed without
knowing if it is on a list.

This would need the following definitions, the presence of
'x - offsetof(..)' in DL_ITEM does make some of these macros
do some work.  However if you insist on the control structures
being at the start of the structure they aren't, and I wouldn't
even think of defining macros for other that insert and delete.
(and not necessarily even for those).

typedef struct double_list double_list_t;
struct double_list {
	double_list_t 	*dl_forw;
	double_list_t 	*dl_back;

#define DL_ITEM(dl,t,f) ((t *)((char *)(dl) - offsetof(t,f)))

#define DL_INIT(dl) ((dl)->dl_forw = (dl)->dl_back = dl)
#define DL_EMPTY(dl) ((dl)->dl_forw == (dl))
#define DL_FIRST(dl,t,f) DL_ITEM((dl)->dl_forw, t, f )
#define DL_NEXT(li,f) DL_ITEM((li)->f.dl_forw, __typeof__ (*(li)), f)
#define DL_IS_HEAD(dl,li,f) (&(li)->f == (dl))

#define DL_REMOVE(li,f) do { \
	(li)->f.dl_forw->dl_back = (li)->f.dl_back; \
	(li)->f.dl_back->dl_forw = (li)->f.dl_forw; \
	(li)->f.dl_forw = (li)->f.dl_back = 0; \
	} while (0)
#define DL_INSERT_TAIL(dl,li,f) do { \
	(li)->f.dl_back = (dl)->dl_back; \
	(dl)->dl_back->dl_forw = &(li)->f; \
	(li)->f.dl_forw = (dl); \
	(dl)->dl_back = &(li)->f; \
	} while (0)

David Laight: