summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoremaste <emaste@FreeBSD.org>2006-05-26 18:17:53 +0000
committeremaste <emaste@FreeBSD.org>2006-05-26 18:17:53 +0000
commit53db512ce5b60400dabc8e025e61721ea6d20479 (patch)
treed73169c0d20dfb1409c9d992deee6ca69826c18a
parente14fcb8fd5522b9ebd84644f8a0c6c38609591a0 (diff)
downloadFreeBSD-src-53db512ce5b60400dabc8e025e61721ea6d20479.zip
FreeBSD-src-53db512ce5b60400dabc8e025e61721ea6d20479.tar.gz
Add sanity checking for QUEUE(3) TAILQs under INVARIANTS (similar to
the LIST checks). Races may lead to list corruption, which can be difficult to unravel in a post-mortem analysis. These checks verify that the prev and next pointers are consistent when inserting or removing elements, thus catching any corruption earlier.
-rw-r--r--sys/sys/queue.h37
1 files changed, 37 insertions, 0 deletions
diff --git a/sys/sys/queue.h b/sys/sys/queue.h
index 3bf12d2..74b8d86 100644
--- a/sys/sys/queue.h
+++ b/sys/sys/queue.h
@@ -430,6 +430,37 @@ struct { \
/*
* Tail queue functions.
*/
+#if (defined(_KERNEL) && defined(INVARIANTS))
+#define QMD_TAILQ_CHECK_HEAD(head, field) do { \
+ if (!TAILQ_EMPTY(head) && \
+ TAILQ_FIRST((head))->field.tqe_prev != \
+ &TAILQ_FIRST((head))) \
+ panic("Bad tailq head %p first->prev != head", (head)); \
+} while (0)
+
+#define QMD_TAILQ_CHECK_TAIL(head, field) do { \
+ if (*(head)->tqh_last != NULL) \
+ panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
+} while (0)
+
+#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \
+ if (TAILQ_NEXT((elm), field) != NULL && \
+ TAILQ_NEXT((elm), field)->field.tqe_prev != \
+ &((elm)->field.tqe_next)) \
+ panic("Bad link elm %p next->prev != elm", (elm)); \
+} while (0)
+
+#define QMD_TAILQ_CHECK_PREV(elm, field) do { \
+ if (*(elm)->field.tqe_prev != (elm)) \
+ panic("Bad link elm %p prev->next != elm", (elm)); \
+} while (0)
+#else
+#define QMD_TAILQ_CHECK_HEAD(head, field)
+#define QMD_TAILQ_CHECK_TAIL(head, headname)
+#define QMD_TAILQ_CHECK_NEXT(elm, field)
+#define QMD_TAILQ_CHECK_PREV(elm, field)
+#endif /* (_KERNEL && INVARIANTS) */
+
#define TAILQ_CONCAT(head1, head2, field) do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
@@ -472,6 +503,7 @@ struct { \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ QMD_TAILQ_CHECK_NEXT(listelm, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
TAILQ_NEXT((elm), field)->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
@@ -486,6 +518,7 @@ struct { \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ QMD_TAILQ_CHECK_PREV(listelm, field); \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
@@ -495,6 +528,7 @@ struct { \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ QMD_TAILQ_CHECK_HEAD(head, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
@@ -507,6 +541,7 @@ struct { \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ QMD_TAILQ_CHECK_TAIL(head, field); \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
@@ -524,6 +559,8 @@ struct { \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_REMOVE(head, elm, field) do { \
+ QMD_TAILQ_CHECK_NEXT(elm, field); \
+ QMD_TAILQ_CHECK_PREV(elm, field); \
if ((TAILQ_NEXT((elm), field)) != NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
OpenPOWER on IntegriCloud