queue(3): Enhance queue debugging macros
Split the QUEUE_MACRO_DEBUG into QUEUE_MACRO_DEBUG_TRACE and QUEUE_MACRO_DEBUG_TRASH. Add the debug macrso QMD_IS_TRASHED() and QMD_SLIST_CHECK_PREVPTR(). Document these in queue.3. Reviewed by: emaste Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D3984
This commit is contained in:
parent
d3bfc7250f
commit
06b9366795
6
UPDATING
6
UPDATING
@ -31,6 +31,12 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 12.x IS SLOW:
|
||||
disable the most expensive debugging functionality run
|
||||
"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
|
||||
|
||||
20160908:
|
||||
The queue(3) debugging macro, QUEUE_MACRO_DEBUG, has been split into
|
||||
two separate components, QUEUE_MACRO_DEBUG_TRACE and
|
||||
QUEUE_MACRO_DEBUG_TRASH. Define both for the original
|
||||
QUEUE_MACRO_DEBUG behavior.
|
||||
|
||||
20160824:
|
||||
r304787 changed some ioctl interfaces between the iSCSI userspace
|
||||
programs and the kernel. ctladm, ctld, iscsictl, and iscsid must be
|
||||
|
@ -106,6 +106,7 @@ MLINKS+= queue.3 LIST_CLASS_ENTRY.3 \
|
||||
queue.3 SLIST_REMOVE.3 \
|
||||
queue.3 SLIST_REMOVE_AFTER.3 \
|
||||
queue.3 SLIST_REMOVE_HEAD.3 \
|
||||
queue.3 SLIST_REMOVE_PREVPTR.3 \
|
||||
queue.3 SLIST_SWAP.3 \
|
||||
queue.3 STAILQ_CLASS_ENTRY.3 \
|
||||
queue.3 STAILQ_CLASS_HEAD.3 \
|
||||
|
@ -28,7 +28,7 @@
|
||||
.\" @(#)queue.3 8.2 (Berkeley) 1/24/94
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd August 15, 2016
|
||||
.Dd September 8, 2016
|
||||
.Dt QUEUE 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -1284,6 +1284,50 @@ while (n1 != NULL) {
|
||||
}
|
||||
TAILQ_INIT(&head);
|
||||
.Ed
|
||||
.Sh DIAGNOSTICS
|
||||
When debugging
|
||||
.Nm queue(3) ,
|
||||
it can be useful to trace queue changes.
|
||||
To enable tracing, define the macro
|
||||
.Va QUEUE_MACRO_DEBUG_TRACE
|
||||
at compile time.
|
||||
.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.
|
||||
The macro
|
||||
.Fn QMD_IS_TRASHED "void *ptr"
|
||||
returns true if
|
||||
.Fa ptr
|
||||
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 tree 3
|
||||
.Sh HISTORY
|
||||
|
@ -113,6 +113,12 @@
|
||||
*
|
||||
*/
|
||||
#ifdef QUEUE_MACRO_DEBUG
|
||||
#warn Use QUEUE_MACRO_DEBUG_TRACE and/or QUEUE_MACRO_DEBUG_TRASH
|
||||
#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 {
|
||||
unsigned long lastline;
|
||||
@ -123,8 +129,6 @@ struct qm_trace {
|
||||
|
||||
#define TRACEBUF struct qm_trace trace;
|
||||
#define TRACEBUF_INITIALIZER { __LINE__, 0, __FILE__, NULL } ,
|
||||
#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; \
|
||||
@ -140,14 +144,26 @@ struct qm_trace {
|
||||
(elem)->trace.lastfile = __FILE__; \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
#else /* !QUEUE_MACRO_DEBUG_TRACE */
|
||||
#define QMD_TRACE_ELEM(elem)
|
||||
#define QMD_TRACE_HEAD(head)
|
||||
#define QMD_SAVELINK(name, link)
|
||||
#define TRACEBUF
|
||||
#define TRACEBUF_INITIALIZER
|
||||
#endif /* QUEUE_MACRO_DEBUG_TRACE */
|
||||
|
||||
#ifdef QUEUE_MACRO_DEBUG_TRASH
|
||||
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
|
||||
#define QMD_IS_TRASHED(x) ((x) == (void *)(intptr_t)-1)
|
||||
#else /* !QUEUE_MACRO_DEBUG_TRASH */
|
||||
#define TRASHIT(x)
|
||||
#endif /* QUEUE_MACRO_DEBUG */
|
||||
#define QMD_IS_TRASHED(x) 0
|
||||
#endif /* QUEUE_MACRO_DEBUG_TRASH */
|
||||
|
||||
#if defined(QUEUE_MACRO_DEBUG_TRACE) || defined(QUEUE_MACRO_DEBUG_TRASH)
|
||||
#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
|
||||
#else /* !QUEUE_MACRO_DEBUG_TRACE && !QUEUE_MACRO_DEBUG_TRASH */
|
||||
#define QMD_SAVELINK(name, link)
|
||||
#endif /* QUEUE_MACRO_DEBUG_TRACE || QUEUE_MACRO_DEBUG_TRASH */
|
||||
|
||||
#ifdef __cplusplus
|
||||
/*
|
||||
@ -187,6 +203,16 @@ struct { \
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#if (defined(_KERNEL) && defined(INVARIANTS))
|
||||
#define QMD_SLIST_CHECK_PREVPTR(prevp, elm) do { \
|
||||
if (*(prevp) != (elm)) \
|
||||
panic("Bad prevptr *(%p) == %p != %p", \
|
||||
(prevp), *(prevp), (elm)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define QMD_SLIST_CHECK_PREVPTR(prevp, elm)
|
||||
#endif
|
||||
|
||||
#define SLIST_CONCAT(head1, head2, type, field) do { \
|
||||
QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head1); \
|
||||
if (curelm == NULL) { \
|
||||
@ -268,6 +294,12 @@ struct { \
|
||||
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_PREVPTR(prevp, elm, field) do { \
|
||||
QMD_SLIST_CHECK_PREVPTR(prevp, elm); \
|
||||
*(prevp) = SLIST_NEXT(elm, field); \
|
||||
TRASHIT((elm)->field.sle_next); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_SWAP(head1, head2, type) do { \
|
||||
QUEUE_TYPEOF(type) *swap_first = SLIST_FIRST(head1); \
|
||||
SLIST_FIRST(head1) = SLIST_FIRST(head2); \
|
||||
|
Loading…
Reference in New Issue
Block a user