queue: New debug macros for STAILQ

The new STAILQ_ASSERT_EMPTY() macro allows callers to assert that some
STAILQ is empty.  It leverages the new QMD_STAILQ_CHECK_EMPTY() internal
macro.

QMD_STAILQ_CHECK_EMPTY() is a check for empty STAILQ, where heads's
'stqh_last' field must point to the 'stqh_first' one.  Use it in
STAILQ_ASSERT_EMPTY().

QMD_STAILQ_CHECK_TAIL() checks that the tail pointed by 'head' does not
have a next element.  It is similar to the already existing
QMD_TAILQ_CHECK_TAIL(), but without the superfluous 'field' argument and
clearer documentation.  Use it in STAILQ_INSERT_TAIL().

Approved by:    markj (mentor)
MFC after:      2 weeks
Sponsored by:   The FreeBSD Foundation
Differential Revision:  https://reviews.freebsd.org/D46889

(cherry picked from commit 34740937f7a46c7475bb57e804701ba8830bf6ed)
This commit is contained in:
Olivier Certner 2024-07-08 18:15:49 +02:00
parent 2e866a1ea9
commit fa940dd2bf
No known key found for this signature in database
GPG key ID: 8CA13040971E2627

View file

@ -341,6 +341,40 @@ struct { \
/*
* Singly-linked Tail queue functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
/*
* QMD_STAILQ_CHECK_EMPTY(STAILQ_HEAD *head)
*
* Validates that the stailq head's pointer to the last element's next pointer
* actually points to the head's first element pointer field.
*/
#define QMD_STAILQ_CHECK_EMPTY(head) do { \
if ((head)->stqh_last != &(head)->stqh_first) \
panic("Empty stailq %p->stqh_last is %p, not head's " \
"first field address", (head), (head)->stqh_last); \
} while (0)
#define STAILQ_ASSERT_EMPTY(head) do { \
if (!STAILQ_EMPTY((head))) \
panic("stailq %p is not empty", (head)); \
}
/*
* QMD_STAILQ_CHECK_TAIL(STAILQ_HEAD *head)
*
* Validates that the stailq's last element's next pointer is NULL.
*/
#define QMD_STAILQ_CHECK_TAIL(head) do { \
if (*(head)->stqh_last != NULL) \
panic("Stailq %p last element's next pointer is %p, " \
"not NULL", (head), *(head)->stqh_last); \
} while (0)
#else
#define QMD_STAILQ_CHECK_EMPTY(head)
#define STAILQ_ASSERT_EMPTY(head)
#define QMD_STAILQ_CHECK_TAIL(head)
#endif /* (_KERNEL && INVARIANTS) */
#define STAILQ_CONCAT(head1, head2) do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
@ -349,7 +383,11 @@ struct { \
} \
} while (0)
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
#define STAILQ_EMPTY(head) ({ \
if (STAILQ_FIRST(head) == NULL) \
QMD_STAILQ_CHECK_EMPTY(head); \
STAILQ_FIRST(head) == NULL; \
})
#define STAILQ_FIRST(head) ((head)->stqh_first)
@ -391,6 +429,7 @@ struct { \
} while (0)
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
QMD_STAILQ_CHECK_TAIL(head); \
STAILQ_NEXT((elm), field) = NULL; \
*(head)->stqh_last = (elm); \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \