Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F115425380
D49973.id154160.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D49973.id154160.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Thu, Apr 24, 4:43 PM (20 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17762072
Default Alt Text
D49973.id154160.diff (11 KB)
Attached To
Mode
D49973: queue(3): Debug macros: Finer control knobs, userland support
Attached
Detach File
Event Timeline
Log In to Comment