]> git.ipfire.org Git - thirdparty/libbsd.git/commitdiff
Sync queue(3) from FreeBSD
authorGuillem Jover <guillem@hadrons.org>
Fri, 31 Oct 2014 23:22:28 +0000 (00:22 +0100)
committerGuillem Jover <guillem@hadrons.org>
Wed, 23 Sep 2015 05:59:34 +0000 (07:59 +0200)
Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=85147
include/bsd/sys/queue.h
man/queue.3bsd

index f1f35c8ce358c1959f6ccd8a5aaa112a064e1d93..55bd4945fb133cb61797bbf7e750f55b3377f647 100644 (file)
@@ -65,7 +65,7 @@
  * so that an arbitrary element can be removed without a need to
  * traverse the list. New elements can be added to the list before
  * or after an existing element or at the head of the list. A list
- * may only be traversed in the forward direction.
+ * may be traversed in either direction.
  *
  * A tail queue is headed by a pair of pointers, one to the head of the
  * list and the other to the tail of the list. The elements are doubly
  * _EMPTY                      +       +       +       +
  * _FIRST                      +       +       +       +
  * _NEXT                       +       +       +       +
- * _PREV                       -       -       -       +
+ * _PREV                       -       +       -       +
  * _LAST                       -       -       +       +
  * _FOREACH                    +       +       +       +
+ * _FOREACH_FROM               +       +       +       +
  * _FOREACH_SAFE               +       +       +       +
+ * _FOREACH_FROM_SAFE          +       +       +       +
  * _FOREACH_REVERSE            -       -       -       +
+ * _FOREACH_REVERSE_FROM       -       -       -       +
  * _FOREACH_REVERSE_SAFE       -       -       -       +
+ * _FOREACH_REVERSE_FROM_SAFE  -       -       -       +
  * _INSERT_HEAD                        +       +       +       +
  * _INSERT_BEFORE              -       +       -       +
  * _INSERT_AFTER               +       +       +       +
  * _REMOVE_AFTER               +       -       +       -
  * _REMOVE_HEAD                        +       -       +       -
  * _REMOVE                     +       +       +       +
+ * _SWAP                       +       +       +       +
  *
  */
 #ifdef QUEUE_MACRO_DEBUG
 /* Store the last 2 places the queue element or head was altered */
 struct qm_trace {
-       char * lastfile;
-       int lastline;
-       char * prevfile;
-       int prevline;
+       unsigned long    lastline;
+       unsigned long    prevline;
+       const char      *lastfile;
+       const char      *prevfile;
 };
 
 #define        TRACEBUF        struct qm_trace trace;
+#define        TRACEBUF_INITIALIZER    { __FILE__, __LINE__, NULL, 0 } ,
 #define        TRASHIT(x)      do {(x) = (void *)-1;} while (0)
+#define        QMD_SAVELINK(name, link)        void **name = (void *)&(link)
 
 #define        QMD_TRACE_HEAD(head) do {                                       \
        (head)->trace.prevline = (head)->trace.lastline;                \
@@ -130,7 +137,9 @@ struct qm_trace {
 #else
 #define        QMD_TRACE_ELEM(elem)
 #define        QMD_TRACE_HEAD(head)
+#define        QMD_SAVELINK(name, link)
 #define        TRACEBUF
+#define        TRACEBUF_INITIALIZER
 #define        TRASHIT(x)
 #endif /* QUEUE_MACRO_DEBUG */
 
@@ -162,11 +171,21 @@ struct {                                                          \
            (var);                                                      \
            (var) = SLIST_NEXT((var), field))
 
+#define        SLIST_FOREACH_FROM(var, head, field)                            \
+       for ((var) = ((var) ? (var) : SLIST_FIRST((head)));             \
+           (var);                                                      \
+           (var) = SLIST_NEXT((var), field))
+
 #define        SLIST_FOREACH_SAFE(var, head, field, tvar)                      \
        for ((var) = SLIST_FIRST((head));                               \
            (var) && ((tvar) = SLIST_NEXT((var), field), 1);            \
            (var) = (tvar))
 
+#define        SLIST_FOREACH_FROM_SAFE(var, head, field, tvar)                 \
+       for ((var) = ((var) ? (var) : SLIST_FIRST((head)));             \
+           (var) && ((tvar) = SLIST_NEXT((var), field), 1);            \
+           (var) = (tvar))
+
 #define        SLIST_FOREACH_PREVPTR(var, varp, head, field)                   \
        for ((varp) = &SLIST_FIRST((head));                             \
            ((var) = *(varp)) != NULL;                                  \
@@ -189,6 +208,7 @@ struct {                                                            \
 #define        SLIST_NEXT(elm, field)  ((elm)->field.sle_next)
 
 #define        SLIST_REMOVE(head, elm, type, field) do {                       \
+       QMD_SAVELINK(oldnext, (elm)->field.sle_next);                   \
        if (SLIST_FIRST((head)) == (elm)) {                             \
                SLIST_REMOVE_HEAD((head), field);                       \
        }                                                               \
@@ -198,7 +218,7 @@ struct {                                                            \
                        curelm = SLIST_NEXT(curelm, field);             \
                SLIST_REMOVE_AFTER(curelm, field);                      \
        }                                                               \
-       TRASHIT((elm)->field.sle_next);                                 \
+       TRASHIT(*oldnext);                                              \
 } while (0)
 
 #define SLIST_REMOVE_AFTER(elm, field) do {                            \
@@ -210,6 +230,12 @@ struct {                                                           \
        SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);   \
 } while (0)
 
+#define SLIST_SWAP(head1, head2, type) do {                            \
+       struct type *swap_first = SLIST_FIRST(head1);                   \
+       SLIST_FIRST(head1) = SLIST_FIRST(head2);                        \
+       SLIST_FIRST(head2) = swap_first;                                \
+} while (0)
+
 /*
  * Singly-linked Tail queue declarations.
  */
@@ -247,12 +273,21 @@ struct {                                                          \
           (var);                                                       \
           (var) = STAILQ_NEXT((var), field))
 
+#define        STAILQ_FOREACH_FROM(var, head, field)                           \
+       for ((var) = ((var) ? (var) : STAILQ_FIRST((head)));            \
+          (var);                                                       \
+          (var) = STAILQ_NEXT((var), field))
 
 #define        STAILQ_FOREACH_SAFE(var, head, field, tvar)                     \
        for ((var) = STAILQ_FIRST((head));                              \
            (var) && ((tvar) = STAILQ_NEXT((var), field), 1);           \
            (var) = (tvar))
 
+#define        STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar)                \
+       for ((var) = ((var) ? (var) : STAILQ_FIRST((head)));            \
+           (var) && ((tvar) = STAILQ_NEXT((var), field), 1);           \
+           (var) = (tvar))
+
 #define        STAILQ_INIT(head) do {                                          \
        STAILQ_FIRST((head)) = NULL;                                    \
        (head)->stqh_last = &STAILQ_FIRST((head));                      \
@@ -277,14 +312,13 @@ struct {                                                          \
 } while (0)
 
 #define        STAILQ_LAST(head, type, field)                                  \
-       (STAILQ_EMPTY((head)) ?                                         \
-               NULL :                                                  \
-               ((struct type *)(void *)                                \
-               ((char *)((head)->stqh_last) - __offsetof(struct type, field))))
+       (STAILQ_EMPTY((head)) ? NULL :                                  \
+           __containerof((head)->stqh_last, struct type, field.stqe_next))
 
 #define        STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
 
 #define        STAILQ_REMOVE(head, elm, type, field) do {                      \
+       QMD_SAVELINK(oldnext, (elm)->field.stqe_next);                  \
        if (STAILQ_FIRST((head)) == (elm)) {                            \
                STAILQ_REMOVE_HEAD((head), field);                      \
        }                                                               \
@@ -294,13 +328,7 @@ struct {                                                           \
                        curelm = STAILQ_NEXT(curelm, field);            \
                STAILQ_REMOVE_AFTER(head, curelm, field);               \
        }                                                               \
-       TRASHIT((elm)->field.stqe_next);                                \
-} while (0)
-
-#define        STAILQ_REMOVE_HEAD(head, field) do {                            \
-       if ((STAILQ_FIRST((head)) =                                     \
-            STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)         \
-               (head)->stqh_last = &STAILQ_FIRST((head));              \
+       TRASHIT(*oldnext);                                              \
 } while (0)
 
 #define STAILQ_REMOVE_AFTER(head, elm, field) do {                     \
@@ -309,6 +337,12 @@ struct {                                                           \
                (head)->stqh_last = &STAILQ_NEXT((elm), field);         \
 } while (0)
 
+#define        STAILQ_REMOVE_HEAD(head, field) do {                            \
+       if ((STAILQ_FIRST((head)) =                                     \
+            STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)         \
+               (head)->stqh_last = &STAILQ_FIRST((head));              \
+} while (0)
+
 #define STAILQ_SWAP(head1, head2, type) do {                           \
        struct type *swap_first = STAILQ_FIRST(head1);                  \
        struct type **swap_last = (head1)->stqh_last;                   \
@@ -378,11 +412,21 @@ struct {                                                          \
            (var);                                                      \
            (var) = LIST_NEXT((var), field))
 
+#define        LIST_FOREACH_FROM(var, head, field)                             \
+       for ((var) = ((var) ? (var) : LIST_FIRST((head)));              \
+           (var);                                                      \
+           (var) = LIST_NEXT((var), field))
+
 #define        LIST_FOREACH_SAFE(var, head, field, tvar)                       \
        for ((var) = LIST_FIRST((head));                                \
            (var) && ((tvar) = LIST_NEXT((var), field), 1);             \
            (var) = (tvar))
 
+#define        LIST_FOREACH_FROM_SAFE(var, head, field, tvar)                  \
+       for ((var) = ((var) ? (var) : LIST_FIRST((head)));              \
+           (var) && ((tvar) = LIST_NEXT((var), field), 1);             \
+           (var) = (tvar))
+
 #define        LIST_INIT(head) do {                                            \
        LIST_FIRST((head)) = NULL;                                      \
 } while (0)
@@ -414,15 +458,21 @@ struct {                                                          \
 
 #define        LIST_NEXT(elm, field)   ((elm)->field.le_next)
 
+#define        LIST_PREV(elm, head, type, field)                               \
+       ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL :           \
+           __containerof((elm)->field.le_prev, struct type, field.le_next))
+
 #define        LIST_REMOVE(elm, field) do {                                    \
+       QMD_SAVELINK(oldnext, (elm)->field.le_next);                    \
+       QMD_SAVELINK(oldprev, (elm)->field.le_prev);                    \
        QMD_LIST_CHECK_NEXT(elm, field);                                \
        QMD_LIST_CHECK_PREV(elm, field);                                \
        if (LIST_NEXT((elm), field) != NULL)                            \
                LIST_NEXT((elm), field)->field.le_prev =                \
                    (elm)->field.le_prev;                               \
        *(elm)->field.le_prev = LIST_NEXT((elm), field);                \
-       TRASHIT((elm)->field.le_next);                                  \
-       TRASHIT((elm)->field.le_prev);                                  \
+       TRASHIT(*oldnext);                                              \
+       TRASHIT(*oldprev);                                              \
 } while (0)
 
 #define LIST_SWAP(head1, head2, type, field) do {                      \
@@ -446,7 +496,7 @@ struct name {                                                               \
 }
 
 #define        TAILQ_HEAD_INITIALIZER(head)                                    \
-       { NULL, &(head).tqh_first }
+       { NULL, &(head).tqh_first, TRACEBUF_INITIALIZER }
 
 #define        TAILQ_ENTRY(type)                                               \
 struct {                                                               \
@@ -509,21 +559,41 @@ struct {                                                          \
            (var);                                                      \
            (var) = TAILQ_NEXT((var), field))
 
+#define        TAILQ_FOREACH_FROM(var, head, field)                            \
+       for ((var) = ((var) ? (var) : TAILQ_FIRST((head)));             \
+           (var);                                                      \
+           (var) = TAILQ_NEXT((var), field))
+
 #define        TAILQ_FOREACH_SAFE(var, head, field, tvar)                      \
        for ((var) = TAILQ_FIRST((head));                               \
            (var) && ((tvar) = TAILQ_NEXT((var), field), 1);            \
            (var) = (tvar))
 
+#define        TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar)                 \
+       for ((var) = ((var) ? (var) : TAILQ_FIRST((head)));             \
+           (var) && ((tvar) = TAILQ_NEXT((var), field), 1);            \
+           (var) = (tvar))
+
 #define        TAILQ_FOREACH_REVERSE(var, head, headname, field)               \
        for ((var) = TAILQ_LAST((head), headname);                      \
            (var);                                                      \
            (var) = TAILQ_PREV((var), headname, field))
 
+#define        TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field)          \
+       for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname));    \
+           (var);                                                      \
+           (var) = TAILQ_PREV((var), headname, field))
+
 #define        TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)    \
        for ((var) = TAILQ_LAST((head), headname);                      \
            (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1);  \
            (var) = (tvar))
 
+#define        TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \
+       for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname));    \
+           (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1);  \
+           (var) = (tvar))
+
 #define        TAILQ_INIT(head) do {                                           \
        TAILQ_FIRST((head)) = NULL;                                     \
        (head)->tqh_last = &TAILQ_FIRST((head));                        \
@@ -587,6 +657,8 @@ struct {                                                            \
        (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
 
 #define        TAILQ_REMOVE(head, elm, field) do {                             \
+       QMD_SAVELINK(oldnext, (elm)->field.tqe_next);                   \
+       QMD_SAVELINK(oldprev, (elm)->field.tqe_prev);                   \
        QMD_TAILQ_CHECK_NEXT(elm, field);                               \
        QMD_TAILQ_CHECK_PREV(elm, field);                               \
        if ((TAILQ_NEXT((elm), field)) != NULL)                         \
@@ -597,8 +669,8 @@ struct {                                                            \
                QMD_TRACE_HEAD(head);                                   \
        }                                                               \
        *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);              \
-       TRASHIT((elm)->field.tqe_next);                                 \
-       TRASHIT((elm)->field.tqe_prev);                                 \
+       TRASHIT(*oldnext);                                              \
+       TRASHIT(*oldprev);                                              \
        QMD_TRACE_ELEM(&(elm)->field);                                  \
 } while (0)
 
index fc861e7979e8df9b9e454471a385bbc11ec0a773..62623b78891031c5d9d803a4192660cd77cee7d6 100644 (file)
@@ -9,7 +9,7 @@
 .\" 2. Redistributions in binary form must reproduce the above copyright
 .\"    notice, this list of conditions and the following disclaimer in the
 .\"    documentation and/or other materials provided with the distribution.
-.\" 4. Neither the name of the University nor the names of its contributors
+.\" 3. Neither the name of the University nor the names of its contributors
 .\"    may be used to endorse or promote products derived from this software
 .\"    without specific prior written permission.
 .\"
 .\"    @(#)queue.3     8.2 (Berkeley) 1/24/94
 .\" $FreeBSD$
 .\"
-.Dd May 13, 2011
-.Dt QUEUE 3bsd
+.Dd June 17, 2013
+.Dt QUEUE 3
 .Os
 .Sh NAME
 .Nm SLIST_EMPTY ,
 .Nm SLIST_ENTRY ,
 .Nm SLIST_FIRST ,
 .Nm SLIST_FOREACH ,
+.Nm SLIST_FOREACH_FROM ,
 .Nm SLIST_FOREACH_SAFE ,
+.Nm SLIST_FOREACH_FROM_SAFE ,
 .Nm SLIST_HEAD ,
 .Nm SLIST_HEAD_INITIALIZER ,
 .Nm SLIST_INIT ,
@@ -52,7 +54,9 @@
 .Nm STAILQ_ENTRY ,
 .Nm STAILQ_FIRST ,
 .Nm STAILQ_FOREACH ,
+.Nm STAILQ_FOREACH_FROM ,
 .Nm STAILQ_FOREACH_SAFE ,
+.Nm STAILQ_FOREACH_FROM_SAFE ,
 .Nm STAILQ_HEAD ,
 .Nm STAILQ_HEAD_INITIALIZER ,
 .Nm STAILQ_INIT ,
@@ -69,7 +73,9 @@
 .Nm LIST_ENTRY ,
 .Nm LIST_FIRST ,
 .Nm LIST_FOREACH ,
+.Nm LIST_FOREACH_FROM ,
 .Nm LIST_FOREACH_SAFE ,
+.Nm LIST_FOREACH_FROM_SAFE ,
 .Nm LIST_HEAD ,
 .Nm LIST_HEAD_INITIALIZER ,
 .Nm LIST_INIT ,
@@ -77,6 +83,7 @@
 .Nm LIST_INSERT_BEFORE ,
 .Nm LIST_INSERT_HEAD ,
 .Nm LIST_NEXT ,
+.Nm LIST_PREV ,
 .Nm LIST_REMOVE ,
 .Nm LIST_SWAP ,
 .Nm TAILQ_CONCAT ,
 .Nm TAILQ_ENTRY ,
 .Nm TAILQ_FIRST ,
 .Nm TAILQ_FOREACH ,
+.Nm TAILQ_FOREACH_FROM ,
 .Nm TAILQ_FOREACH_SAFE ,
+.Nm TAILQ_FOREACH_FROM_SAFE ,
 .Nm TAILQ_FOREACH_REVERSE ,
+.Nm TAILQ_FOREACH_REVERSE_FROM ,
 .Nm TAILQ_FOREACH_REVERSE_SAFE ,
+.Nm TAILQ_FOREACH_REVERSE_FROM_SAFE ,
 .Nm TAILQ_HEAD ,
 .Nm TAILQ_HEAD_INITIALIZER ,
 .Nm TAILQ_INIT ,
@@ -108,7 +119,9 @@ lists and tail queues
 .Fn SLIST_ENTRY "TYPE"
 .Fn SLIST_FIRST "SLIST_HEAD *head"
 .Fn SLIST_FOREACH "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME"
+.Fn SLIST_FOREACH_FROM "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME"
 .Fn SLIST_FOREACH_SAFE "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" "TYPE *temp_var"
+.Fn SLIST_FOREACH_FROM_SAFE "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" "TYPE *temp_var"
 .Fn SLIST_HEAD "HEADNAME" "TYPE"
 .Fn SLIST_HEAD_INITIALIZER "SLIST_HEAD head"
 .Fn SLIST_INIT "SLIST_HEAD *head"
@@ -125,7 +138,9 @@ lists and tail queues
 .Fn STAILQ_ENTRY "TYPE"
 .Fn STAILQ_FIRST "STAILQ_HEAD *head"
 .Fn STAILQ_FOREACH "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
+.Fn STAILQ_FOREACH_FROM "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
 .Fn STAILQ_FOREACH_SAFE "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" "TYPE *temp_var"
+.Fn STAILQ_FOREACH_FROM_SAFE "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" "TYPE *temp_var"
 .Fn STAILQ_HEAD "HEADNAME" "TYPE"
 .Fn STAILQ_HEAD_INITIALIZER "STAILQ_HEAD head"
 .Fn STAILQ_INIT "STAILQ_HEAD *head"
@@ -143,7 +158,9 @@ lists and tail queues
 .Fn LIST_ENTRY "TYPE"
 .Fn LIST_FIRST "LIST_HEAD *head"
 .Fn LIST_FOREACH "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME"
+.Fn LIST_FOREACH_FROM "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME"
 .Fn LIST_FOREACH_SAFE "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" "TYPE *temp_var"
+.Fn LIST_FOREACH_FROM_SAFE "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" "TYPE *temp_var"
 .Fn LIST_HEAD "HEADNAME" "TYPE"
 .Fn LIST_HEAD_INITIALIZER "LIST_HEAD head"
 .Fn LIST_INIT "LIST_HEAD *head"
@@ -151,6 +168,7 @@ lists and tail queues
 .Fn LIST_INSERT_BEFORE "TYPE *listelm" "TYPE *elm" "LIST_ENTRY NAME"
 .Fn LIST_INSERT_HEAD "LIST_HEAD *head" "TYPE *elm" "LIST_ENTRY NAME"
 .Fn LIST_NEXT "TYPE *elm" "LIST_ENTRY NAME"
+.Fn LIST_PREV "TYPE *elm" "LIST_HEAD *head" "TYPE" "LIST_ENTRY NAME"
 .Fn LIST_REMOVE "TYPE *elm" "LIST_ENTRY NAME"
 .Fn LIST_SWAP "LIST_HEAD *head1" "LIST_HEAD *head2" "TYPE" "LIST_ENTRY NAME"
 .\"
@@ -159,9 +177,13 @@ lists and tail queues
 .Fn TAILQ_ENTRY "TYPE"
 .Fn TAILQ_FIRST "TAILQ_HEAD *head"
 .Fn TAILQ_FOREACH "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME"
+.Fn TAILQ_FOREACH_FROM "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME"
 .Fn TAILQ_FOREACH_SAFE "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" "TYPE *temp_var"
+.Fn TAILQ_FOREACH_FROM_SAFE "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" "TYPE *temp_var"
 .Fn TAILQ_FOREACH_REVERSE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME"
+.Fn TAILQ_FOREACH_REVERSE_FROM "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME"
 .Fn TAILQ_FOREACH_REVERSE_SAFE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" "TYPE *temp_var"
+.Fn TAILQ_FOREACH_REVERSE_FROM_SAFE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" "TYPE *temp_var"
 .Fn TAILQ_HEAD "HEADNAME" "TYPE"
 .Fn TAILQ_HEAD_INITIALIZER "TAILQ_HEAD head"
 .Fn TAILQ_INIT "TAILQ_HEAD *head"
@@ -244,8 +266,18 @@ Code size and execution time of operations (except for removal) is about
 twice that of the singly-linked data-structures.
 .El
 .Pp
-Linked lists are the simplest of the doubly linked data structures and support
-only the above functionality over singly-linked lists.
+Linked lists are the simplest of the doubly linked data structures.
+They add the following functionality over the above:
+.Bl -enum -compact -offset indent
+.It
+They may be traversed backwards.
+.El
+However:
+.Bl -enum -compact -offset indent
+.It
+To traverse backwards, an entry to begin the traversal and the list in
+which it is contained must be specified.
+.El
 .Pp
 Tail queues add the following functionality:
 .Bl -enum -compact -offset indent
@@ -349,6 +381,19 @@ turn to
 .Fa var .
 .Pp
 The macro
+.Nm SLIST_FOREACH_FROM
+behaves identically to
+.Nm SLIST_FOREACH
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found SLIST element and begins the loop at
+.Fa var
+instead of the first element in the SLIST referenced by
+.Fa head .
+.Pp
+The macro
 .Nm SLIST_FOREACH_SAFE
 traverses the list referenced by
 .Fa head
@@ -363,6 +408,19 @@ as well as free it from within the loop safely without interfering with the
 traversal.
 .Pp
 The macro
+.Nm SLIST_FOREACH_FROM_SAFE
+behaves identically to
+.Nm SLIST_FOREACH_SAFE
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found SLIST element and begins the loop at
+.Fa var
+instead of the first element in the SLIST referenced by
+.Fa head .
+.Pp
+The macro
 .Nm SLIST_INIT
 initializes the list referenced by
 .Fa head .
@@ -388,7 +446,8 @@ The macro
 .Nm SLIST_REMOVE_AFTER
 removes the element after
 .Fa elm
-from the list. Unlike
+from the list.
+Unlike
 .Fa SLIST_REMOVE ,
 this macro does not traverse the entire list.
 .Pp
@@ -528,6 +587,19 @@ in turn to
 .Fa var .
 .Pp
 The macro
+.Nm STAILQ_FOREACH_FROM
+behaves identically to
+.Nm STAILQ_FOREACH
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found STAILQ element and begins the loop at
+.Fa var
+instead of the first element in the STAILQ referenced by
+.Fa head .
+.Pp
+The macro
 .Nm STAILQ_FOREACH_SAFE
 traverses the tail queue referenced by
 .Fa head
@@ -542,6 +614,19 @@ as well as free it from within the loop safely without interfering with the
 traversal.
 .Pp
 The macro
+.Nm STAILQ_FOREACH_FROM_SAFE
+behaves identically to
+.Nm STAILQ_FOREACH_SAFE
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found STAILQ element and begins the loop at
+.Fa var
+instead of the first element in the STAILQ referenced by
+.Fa head .
+.Pp
+The macro
 .Nm STAILQ_INIT
 initializes the tail queue referenced by
 .Fa head .
@@ -579,7 +664,8 @@ The macro
 .Nm STAILQ_REMOVE_AFTER
 removes the element after
 .Fa elm
-from the tail queue. Unlike
+from the tail queue.
+Unlike
 .Fa STAILQ_REMOVE ,
 this macro does not traverse the entire tail queue.
 .Pp
@@ -717,6 +803,19 @@ in the forward direction, assigning each element in turn to
 .Fa var .
 .Pp
 The macro
+.Nm LIST_FOREACH_FROM
+behaves identically to
+.Nm LIST_FOREACH
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found LIST element and begins the loop at
+.Fa var
+instead of the first element in the LIST referenced by
+.Fa head .
+.Pp
+The macro
 .Nm LIST_FOREACH_SAFE
 traverses the list referenced by
 .Fa head
@@ -730,6 +829,19 @@ as well as free it from within the loop safely without interfering with the
 traversal.
 .Pp
 The macro
+.Nm LIST_FOREACH_FROM_SAFE
+behaves identically to
+.Nm LIST_FOREACH_SAFE
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found LIST element and begins the loop at
+.Fa var
+instead of the first element in the LIST referenced by
+.Fa head .
+.Pp
+The macro
 .Nm LIST_INIT
 initializes the list referenced by
 .Fa head .
@@ -759,6 +871,14 @@ The macro
 returns the next element in the list, or NULL if this is the last.
 .Pp
 The macro
+.Nm LIST_PREV
+returns the previous element in the list, or NULL if this is the first.
+List
+.Fa head
+must contain element
+.Fa elm .
+.Pp
+The macro
 .Nm LIST_REMOVE
 removes the element
 .Fa elm
@@ -894,12 +1014,38 @@ is set to
 if the loop completes normally, or if there were no elements.
 .Pp
 The macro
+.Nm TAILQ_FOREACH_FROM
+behaves identically to
+.Nm TAILQ_FOREACH
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found TAILQ element and begins the loop at
+.Fa var
+instead of the first element in the TAILQ referenced by
+.Fa head .
+.Pp
+The macro
 .Nm TAILQ_FOREACH_REVERSE
 traverses the tail queue referenced by
 .Fa head
 in the reverse direction, assigning each element in turn to
 .Fa var .
 .Pp
+The macro
+.Nm TAILQ_FOREACH_REVERSE_FROM
+behaves identically to
+.Nm TAILQ_FOREACH_REVERSE
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found TAILQ element and begins the reverse loop at
+.Fa var
+instead of the last element in the TAILQ referenced by
+.Fa head .
+.Pp
 The macros
 .Nm TAILQ_FOREACH_SAFE
 and
@@ -919,6 +1065,32 @@ as well as free it from within the loop safely without interfering with the
 traversal.
 .Pp
 The macro
+.Nm TAILQ_FOREACH_FROM_SAFE
+behaves identically to
+.Nm TAILQ_FOREACH_SAFE
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found TAILQ element and begins the loop at
+.Fa var
+instead of the first element in the TAILQ referenced by
+.Fa head .
+.Pp
+The macro
+.Nm TAILQ_FOREACH_REVERSE_FROM_SAFE
+behaves identically to
+.Nm TAILQ_FOREACH_REVERSE_SAFE
+when
+.Fa var
+is NULL, else it treats
+.Fa var
+as a previously found TAILQ element and begins the reverse loop at
+.Fa var
+instead of the last element in the TAILQ referenced by
+.Fa head .
+.Pp
+The macro
 .Nm TAILQ_INIT
 initializes the tail queue referenced by
 .Fa head .