I don't know if it is useful to anyone else but it is required by lsquic, a library that implements QUIC / HTTP3.
Index: share/man/man3/queue.3 =================================================================== RCS file: /cvs/src/share/man/man3/queue.3,v retrieving revision 1.66 diff -u -p -r1.66 queue.3 --- share/man/man3/queue.3 30 Dec 2019 17:25:39 -0000 1.66 +++ share/man/man3/queue.3 23 Apr 2020 11:59:19 -0000 @@ -96,8 +96,24 @@ .Nm TAILQ_INSERT_TAIL , .Nm TAILQ_REMOVE , .Nm TAILQ_REPLACE , -.Nm TAILQ_CONCAT -.Nd intrusive singly-linked and doubly-linked lists, simple queues, and tail queues +.Nm TAILQ_CONCAT , +.Nm STAILQ_HEAD , +.Nm STAILQ_HEAD_INITIALIZER , +.Nm STAILQ_ENTRY , +.Nm STAILQ_FIRST , +.Nm STAILQ_EMPTY , +.Nm STAILQ_NEXT , +.Nm STAILQ_LAST , +.Nm STAILQ_FOREACH , +.Nm STAILQ_FOREACH_SAFE , +.Nm STAILQ_INIT , +.Nm STAILQ_INSERT_AFTER , +.Nm STAILQ_INSERT_HEAD , +.Nm STAILQ_INSERT_TAIL , +.Nm STAILQ_REMOVE_HEAD , +.Nm STAILQ_REMOVE , +.Nm STAILQ_CONCAT +.Nd intrusive singly-linked and doubly-linked lists, simple queues, tail queue, and singly-linked tail queues .Sh SYNOPSIS .In sys/queue.h .Pp @@ -206,10 +222,32 @@ .Ft void .Fn TAILQ_REPLACE "TAILQ_HEAD *head" "struct TYPE *elm" "struct TYPE *elm2" "FIELDNAME" .Fn TAILQ_CONCAT "TAILQ_HEAD *head1" "TAILQ_HEAD *head2" "FIELDNAME" +.Pp +.Fn STAILQ_ENTRY "TYPE" +.Fn STAILQ_HEAD "HEADNAME" "TYPE" +.Fn STAILQ_HEAD_INITIALIZER "STAILQ_HEAD head" +.Ft "struct TYPE *" +.Fn STAILQ_FIRST "STAILQ_HEAD *head" +.Ft int +.Fn STAILQ_EMPTY "STAILQ_HEAD *head" +.Ft "struct TYPE *" +.Fn STAILQ_NEXT "struct TYPE *listelm" "FILEDNAME" +.Ft "struct TYPE *" +.Fn STAILQ_LAST "STAILQ_HEAD *head" "struct TYPE *elm" "FIELDNAME" +.Fn STAILQ_FOREACH "VARNAME" "STAILQ_HEAD *head" "FIELDNAME" +.Fn STAILQ_FOREACH_SAFE "VARNAME" "STAILQ_HEAD *head" "FIELDNAME" "TEMP_VARNAME" +.Fn STAILQ_INIT "STAILQ_HEAD *head" +.Fn STAILQ_INSERT_HEAD "STAILQ_HEAD *head" "struct TYPE *elm" "FIELDNAME" +.Fn STAILQ_INSERT_TAIL "STAILQ_HEAD *head" "struct TYPE *elm" "FIELDNAME" +.Fn STAILQ_INSERT_AFTER "STAILQ_HEAD *head" "struct TYPE *listelm" "TYPE *elm" "FIELDNAME" +.Fn STAILQ_REMOVE_HEAD "STAILQ_HEAD *head" "FIELDNAME" +.Fn STAILQ_REMOVE "STAILQ_HEAD *head" "struct TYPE *elm" "TYPE" "FIELDNAME" +.Fn STAILQ_CONCAT "STAILQ_HEAD *head1" "STAILQ_HEAD *head2" .Sh DESCRIPTION -These macros define and operate on four types of data structures: -singly-linked lists, simple queues, lists, and tail queues. -All four structures support the following functionality: +These macros define and operate on five types of data structures: +singly-linked lists, simple queues, lists, tail queues, and singly-linked +tail queues. +All five structures support the following functionality: .Pp .Bl -enum -compact -offset indent .It @@ -303,8 +341,9 @@ defined structures containing a field of .Li SLIST_ENTRY , .Li LIST_ENTRY , .Li SIMPLEQ_ENTRY , +.Li TAILQ_ENTRY , or -.Li TAILQ_ENTRY . +.Li STAILQ_ENTRY . In the macro definitions, .Fa TYPE is the name tag of the user defined structure and @@ -324,8 +363,9 @@ using the macros .Fn SLIST_HEAD , .Fn LIST_HEAD , .Fn SIMPLEQ_HEAD , +.Fn TAILQ_HEAD , or -.Fn TAILQ_HEAD . +.Fn STAILQ_HEAD . See the examples below for further explanation of how these macros are used. .Sh SINGLY-LINKED LISTS A singly-linked list is headed by a structure defined by the @@ -927,6 +967,27 @@ while ((np = TAILQ_FIRST(&head))) { } .Ed +.Sh SINGLY LINKED TAIL QUEUES +The macros prefixed with +.Do Nm STAILQ_ Dc ( +.Fn STAILQ_HEAD , +.Fn STAILQ_HEAD_INITIALIZER , +.Fn STAILQ_ENTRY , +.Fn STAILQ_FOREACH , +.Fn STAILQ_FOREACH_SAFE , +.Fn STAILQ_FIRST , +.Fn STAILQ_EMPTY , +.Fn STAILQ_NEXT , +.Fn STAILQ_LAST , +.Fn STAILQ_INIT , +.Fn STAILQ_INSERT_HEAD , +.Fn STAILQ_INSERT_TAIL , +.Fn STAILQ_INSERT_AFTER , +.Fn STAILQ_REMOVE_HEAD , +.Fn STAILQ_REMOVE , +and +.Fn STAILQ_CONCAT ) +are functionally identical to these simple queue functions. .Sh SEE ALSO .Xr tree 3 .Sh NOTES Index: sys/sys/queue.h =================================================================== RCS file: /cvs/src/sys/sys/queue.h,v retrieving revision 1.45 diff -u -p -r1.45 queue.h --- sys/sys/queue.h 12 Jul 2018 14:22:54 -0000 1.45 +++ sys/sys/queue.h 23 Apr 2020 11:59:20 -0000 @@ -533,4 +533,101 @@ struct { \ } \ } while (0) -#endif /* !_SYS_QUEUE_H_ */ +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first; /* first element */ \ + struct type **stqh_last; /* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue access methods. + */ +#define STAILQ_FIRST(head) ((head)->stqh_first) +#define STAILQ_END(head) NULL +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) +#define STAILQ_EMPTY(head) (STAILQ_FIRST(head) == STAILQ_END(head)) + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_INIT(head) do { \ + (head)->stqh_first = NULL; \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (head)->stqh_first = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.stqe_next = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &(elm)->field.stqe_next; \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.stqe_next = \ + (listelm)->field.stqe_next) == NULL) \ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (listelm)->field.stqe_next = (elm); \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if (((head)->stqh_first = \ + (head)->stqh_first->field.stqe_next) == NULL) \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (0) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if ((head)->stqh_first == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->stqh_first; \ + while (curelm->field.stqe_next != (elm)) \ + curelm = curelm->field.stqe_next; \ + if ((curelm->field.stqe_next = \ + curelm->field.stqe_next->field.stqe_next) == NULL)\ + (head)->stqh_last = \ + &(curelm)->field.stqe_next; \ + } \ + _Q_INVALIDATE((elm)->field.stqh_next); \ +} while (0) + +#define STAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->stqh_first); \ + (var); \ + (var) = ((var)->field.stqe_next)) + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *)(void *) \ + ((char *)((head)->stqh_last) - offsetof(struct type, field)))) + +#endif /* !_SYS_QUEUE_H_ */