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_ */

Reply via email to