Page MenuHomeFreeBSD

D49973.id154160.diff
No OneTemporary

D49973.id154160.diff

diff --git a/share/man/man3/queue.3 b/share/man/man3/queue.3
--- a/share/man/man3/queue.3
+++ b/share/man/man3/queue.3
@@ -1390,18 +1390,74 @@
TAILQ_INIT(&head);
.Ed
.Sh DIAGNOSTICS
-When debugging
-.Nm queue(3) ,
-it can be useful to trace queue changes.
+.Nm queue(3)
+provides several diagnostic and debugging facilities.
+.Pp
+Debug code that performs basic integrity and API conformance checks is
+automatically inserted when using queue macros in the kernel if compiling it
+with
+.Va INVARIANTS .
+One can request insertion or elision of debug code by respectively defining one
+of the macros
+.Va QUEUE_MACRO_DEBUG_ASSERTIONS
+or
+.Va QUEUE_MACRO_NO_DEBUG_ASSERTIONS
+before first inclusion of
+.In sys/queue.h .
+When check debug code encounters an anomaly, it panics the kernel or aborts the
+program.
+To this end, in the kernel or in
+.Va _STANDALONE
+builds, it by default calls
+.Fn panic ,
+while in userland builds it prints a diagnostic message on
+.Dv stderr
+and then calls
+.Fn abort .
+These behaviors can be overriden by defining a custom
+.Fn QMD_PANIC
+macro before first inclusion of
+.In sys/queue.h .
+.Pp
+The
+.Fn SLIST_REMOVE_PREVPTR
+macro is available to aid debugging:
+.Bl -hang -offset indent
+.It Fn SLIST_REMOVE_PREVPTR "TYPE **prev" "TYPE *elm" "SLIST_ENTRY NAME"
+.Pp
+Removes element
+.Fa elm ,
+which must directly follow the element whose
+.Va &SLIST_NEXT()
+is
+.Fa prev ,
+from the list.
+This macro may insert, under conditions detailed above, check debug code that
+validates that
+.Fa elm
+indeed follows
+.Fa prev
+in the list
+.Po
+through the
+.Fn QMD_SLIST_CHECK_PREVPTR
+macro
+.Pc .
+.El
+.Pp
+When debugging, it can be useful to trace queue changes.
To enable tracing, define the macro
-.Va QUEUE_MACRO_DEBUG_TRACE
-at compile time.
+.Va QUEUE_MACRO_DEBUG_TRACE .
+Note that, at the moment, only macros for regular tail queues have been
+instrumented.
.Pp
It can also be useful to trash pointers that have been unlinked from a queue,
to detect use after removal.
To enable pointer trashing, define the macro
.Va QUEUE_MACRO_DEBUG_TRASH
at compile time.
+Note that, at the moment, only a limited number of macros have been
+instrumented.
The macro
.Fn QMD_IS_TRASHED "void *ptr"
returns true if
@@ -1409,30 +1465,6 @@
has been trashed by the
.Va QUEUE_MACRO_DEBUG_TRASH
option.
-.Pp
-In the kernel (with
-.Va INVARIANTS
-enabled), the
-.Fn SLIST_REMOVE_PREVPTR
-macro is available to aid debugging:
-.Bl -hang -offset indent
-.It Fn SLIST_REMOVE_PREVPTR "TYPE **prev" "TYPE *elm" "SLIST_ENTRY NAME"
-.Pp
-Removes
-.Fa elm ,
-which must directly follow the element whose
-.Va &SLIST_NEXT()
-is
-.Fa prev ,
-from the SLIST.
-This macro validates that
-.Fa elm
-follows
-.Fa prev
-in
-.Va INVARIANTS
-mode.
-.El
.Sh SEE ALSO
.Xr arb 3 ,
.Xr tree 3
diff --git a/sys/sys/queue.h b/sys/sys/queue.h
--- a/sys/sys/queue.h
+++ b/sys/sys/queue.h
@@ -116,11 +116,10 @@
*
*/
#ifdef QUEUE_MACRO_DEBUG
-#warn Use QUEUE_MACRO_DEBUG_TRACE and/or QUEUE_MACRO_DEBUG_TRASH
+#warn Use QUEUE_MACRO_DEBUG_xxx instead (TRACE, TRASH and/or ASSERTIONS)
#define QUEUE_MACRO_DEBUG_TRACE
#define QUEUE_MACRO_DEBUG_TRASH
#endif
-
#ifdef QUEUE_MACRO_DEBUG_TRACE
/* Store the last 2 places the queue element or head was altered */
struct qm_trace {
@@ -164,6 +163,51 @@
#define QMD_IS_TRASHED(x) 0
#endif /* QUEUE_MACRO_DEBUG_TRASH */
+#if defined(QUEUE_MACRO_DEBUG_ASSERTIONS) && \
+ defined(QUEUE_MACRO_NO_DEBUG_ASSERTIONS)
+#error Both QUEUE_MACRO_DEBUG_ASSERTIONS and QUEUE_MACRO_NO_DEBUG_ASSERTIONS defined
+#endif
+
+/*
+ * Automatically define QUEUE_MACRO_DEBUG_ASSERTIONS when compiling the kernel
+ * with INVARIANTS, if not already defined and not prevented by presence of
+ * QUEUE_MACRO_NO_DEBUG_ASSERTIONS.
+ */
+#if !defined(QUEUE_MACRO_DEBUG_ASSERTIONS) && \
+ !defined(QUEUE_MACRO_NO_DEBUG_ASSERTIONS) && \
+ (defined(_KERNEL) && defined(INVARIANTS))
+#define QUEUE_MACRO_DEBUG_ASSERTIONS
+#endif
+
+/*
+ * If queue assertions are enabled, provide a default definition of QMD_PANIC()
+ * if not already defined.
+ */
+#if defined(QUEUE_MACRO_DEBUG_ASSERTIONS) && !defined(QMD_PANIC)
+#if defined(_KERNEL) || defined(_STANDALONE)
+/*
+ * On _STANDALONE, either <stand.h> or the headers using <sys/queue.h> provide
+ * a declaration or macro for panic().
+ */
+#ifdef _KERNEL
+#include <sys/kassert.h>
+#endif
+#define QMD_PANIC(fmt, ...) do { \
+ panic("File '%s', line %u: " fmt, \
+ __FILE__, __LINE__, ##__VA_ARGS__); \
+} while (0)
+#else /* !(_KERNEL || _STANDALONE) */
+#include <stdio.h>
+#include <stdlib.h>
+#define QMD_PANIC(fmt, ...) do { \
+ fprintf(stderr, "File '%s', line %u: " fmt "\n", \
+ __FILE__, __LINE__, ##__VA_ARGS__); \
+ abort(); \
+} while (0)
+#endif /* _KERNEL || _STANDALONE */
+#endif /* QUEUE_MACRO_DEBUG_ASSERTIONS && !QMD_PANIC */
+
+
#ifdef __cplusplus
/*
* In C++ there can be structure lists and class lists:
@@ -202,31 +246,27 @@
/*
* Singly-linked List functions.
*/
-#if (defined(_KERNEL) && defined(INVARIANTS))
-
+#ifdef QUEUE_MACRO_DEBUG_ASSERTIONS
#define QMD_SLIST_CHECK_PREVPTR(prevp, elm) do { \
if (*(prevp) != (elm)) \
- panic("Bad prevptr *(%p) == %p != %p", \
+ QMD_PANIC("Bad prevptr *(%p) == %p != %p", \
(prevp), *(prevp), (elm)); \
} while (0)
#define SLIST_ASSERT_EMPTY(head) do { \
if (!SLIST_EMPTY((head))) \
- panic("slist %p is not empty", (head)); \
+ QMD_PANIC("slist %p is not empty", (head)); \
} while (0)
#define SLIST_ASSERT_NONEMPTY(head) do { \
if (SLIST_EMPTY((head))) \
- panic("slist %p is empty", (head)); \
+ QMD_PANIC("slist %p is empty", (head)); \
} while (0)
-
#else
#define QMD_SLIST_CHECK_PREVPTR(prevp, elm)
#define SLIST_ASSERT_EMPTY(head)
#define SLIST_ASSERT_NONEMPTY(head)
#endif
-
-
#define SLIST_CONCAT(head1, head2, type, field) do { \
QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head1); \
if (curelm == NULL) { \
@@ -364,7 +404,7 @@
/*
* Singly-linked Tail queue functions.
*/
-#if (defined(_KERNEL) && defined(INVARIANTS))
+#ifdef QUEUE_MACRO_DEBUG_ASSERTIONS
/*
* QMD_STAILQ_CHECK_EMPTY(STAILQ_HEAD *head)
*
@@ -373,8 +413,9 @@
*/
#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); \
+ QMD_PANIC("Empty stailq %p->stqh_last is %p, " \
+ "not head's first field address", \
+ (head), (head)->stqh_last); \
} while (0)
/*
@@ -384,18 +425,18 @@
*/
#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); \
+ QMD_PANIC("Stailq %p last element's next pointer is " \
+ "%p, not NULL", (head), *(head)->stqh_last); \
} while (0)
#define STAILQ_ASSERT_EMPTY(head) do { \
if (!STAILQ_EMPTY((head))) \
- panic("stailq %p is not empty", (head)); \
+ QMD_PANIC("stailq %p is not empty", (head)); \
} while (0)
#define STAILQ_ASSERT_NONEMPTY(head) do { \
if (STAILQ_EMPTY((head))) \
- panic("stailq %p is empty", (head)); \
+ QMD_PANIC("stailq %p is empty", (head)); \
} while (0)
#else
@@ -403,7 +444,7 @@
#define QMD_STAILQ_CHECK_TAIL(head)
#define STAILQ_ASSERT_EMPTY(head)
#define STAILQ_ASSERT_NONEMPTY(head)
-#endif /* _KERNEL && INVARIANTS */
+#endif /* QUEUE_MACRO_DEBUG_ASSERTIONS */
#define STAILQ_CONCAT(head1, head2) do { \
if (!STAILQ_EMPTY((head2))) { \
@@ -563,7 +604,7 @@
* List functions.
*/
-#if (defined(_KERNEL) && defined(INVARIANTS))
+#ifdef QUEUE_MACRO_DEBUG_ASSERTIONS
/*
* QMD_LIST_CHECK_HEAD(LIST_HEAD *head, LIST_ENTRY NAME)
*
@@ -574,7 +615,8 @@
if (LIST_FIRST((head)) != NULL && \
LIST_FIRST((head))->field.le_prev != \
&LIST_FIRST((head))) \
- panic("Bad list head %p first->prev != head", (head)); \
+ QMD_PANIC("Bad list head %p first->prev != head", \
+ (head)); \
} while (0)
/*
@@ -587,7 +629,7 @@
if (LIST_NEXT((elm), field) != NULL && \
LIST_NEXT((elm), field)->field.le_prev != \
&((elm)->field.le_next)) \
- panic("Bad link elm %p next->prev != elm", (elm)); \
+ QMD_PANIC("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
/*
@@ -597,17 +639,17 @@
*/
#define QMD_LIST_CHECK_PREV(elm, field) do { \
if (*(elm)->field.le_prev != (elm)) \
- panic("Bad link elm %p prev->next != elm", (elm)); \
+ QMD_PANIC("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#define LIST_ASSERT_EMPTY(head) do { \
if (!LIST_EMPTY((head))) \
- panic("list %p is not empty", (head)); \
+ QMD_PANIC("list %p is not empty", (head)); \
} while (0)
#define LIST_ASSERT_NONEMPTY(head) do { \
if (LIST_EMPTY((head))) \
- panic("list %p is empty", (head)); \
+ QMD_PANIC("list %p is empty", (head)); \
} while (0)
#else
@@ -616,8 +658,7 @@
#define QMD_LIST_CHECK_PREV(elm, field)
#define LIST_ASSERT_EMPTY(head)
#define LIST_ASSERT_NONEMPTY(head)
-#endif /* (_KERNEL && INVARIANTS) */
-
+#endif /* QUEUE_MACRO_DEBUG_ASSERTIONS */
#define LIST_CONCAT(head1, head2, type, field) do { \
QUEUE_TYPEOF(type) *curelm = LIST_FIRST(head1); \
if (curelm == NULL) { \
@@ -791,7 +832,7 @@
/*
* Tail queue functions.
*/
-#if (defined(_KERNEL) && defined(INVARIANTS))
+#ifdef QUEUE_MACRO_DEBUG_ASSERTIONS
/*
* QMD_TAILQ_CHECK_HEAD(TAILQ_HEAD *head, TAILQ_ENTRY NAME)
*
@@ -802,7 +843,8 @@
if (!TAILQ_EMPTY(head) && \
TAILQ_FIRST((head))->field.tqe_prev != \
&TAILQ_FIRST((head))) \
- panic("Bad tailq head %p first->prev != head", (head)); \
+ QMD_PANIC("Bad tailq head %p first->prev != head", \
+ (head)); \
} while (0)
/*
@@ -812,7 +854,8 @@
*/
#define QMD_TAILQ_CHECK_TAIL(head, field) do { \
if (*(head)->tqh_last != NULL) \
- panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
+ QMD_PANIC("Bad tailq NEXT(%p->tqh_last) != NULL", \
+ (head)); \
} while (0)
/*
@@ -825,7 +868,7 @@
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)); \
+ QMD_PANIC("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
/*
@@ -835,17 +878,17 @@
*/
#define QMD_TAILQ_CHECK_PREV(elm, field) do { \
if (*(elm)->field.tqe_prev != (elm)) \
- panic("Bad link elm %p prev->next != elm", (elm)); \
+ QMD_PANIC("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#define TAILQ_ASSERT_EMPTY(head) do { \
if (!TAILQ_EMPTY((head))) \
- panic("tailq %p is not empty", (head)); \
+ QMD_PANIC("tailq %p is not empty", (head)); \
} while (0)
#define TAILQ_ASSERT_NONEMPTY(head) do { \
if (TAILQ_EMPTY((head))) \
- panic("tailq %p is empty", (head)); \
+ QMD_PANIC("tailq %p is empty", (head)); \
} while (0)
#else
@@ -855,7 +898,7 @@
#define QMD_TAILQ_CHECK_PREV(elm, field)
#define TAILQ_ASSERT_EMPTY(head)
#define TAILQ_ASSERT_NONEMPTY(head)
-#endif /* (_KERNEL && INVARIANTS) */
+#endif /* QUEUE_MACRO_DEBUG_ASSERTIONS */
#define TAILQ_CONCAT(head1, head2, field) do { \
if (!TAILQ_EMPTY(head2)) { \

File Metadata

Mime Type
text/plain
Expires
Thu, Apr 24, 5:12 PM (20 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17762072
Default Alt Text
D49973.id154160.diff (11 KB)

Event Timeline