tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

pserialized queue(9)



The attached patch adds _PSZ variants to all the insert, remove, and
foreach operations in <sys/queue.h> to issue the necessary store
barriers, for insert, and data-dependent load barriers, for foreach.

I made *_REMOVE*_PSZ an alias for *_REMOVE* so that if you're using
pserialize with a queue, all of the operations you perform on it after
initialization are marked with _PSZ.  That way it should be easy to
eyeball code for obvious mistakes.

There is no, e.g., LIST_NEXT_PSZ because there's no good way to
express that without expression blocks.  Most readers need to iterate
over a queue, anyway, rather than just fetch one entry's next pointer.
I omitted TAILQ_FOREACH_REVERSE_PSZ because, as Dennis observed, TAILQ
reverse traversal violates strict aliasing, so we need a new kind of
queue for that.  (It's also not clear it would be useful.)

I have only compile-tested so far -- I'm asking for review on the
concept before I spend a lot of my Copious Spare Time^TM engineering
and running stress tests.  Thoughts?
Index: share/man/man3/queue.3
===================================================================
RCS file: /cvsroot/src/share/man/man3/queue.3,v
retrieving revision 1.49
diff -p -u -r1.49 queue.3
--- share/man/man3/queue.3	18 May 2014 15:45:08 -0000	1.49
+++ share/man/man3/queue.3	21 Nov 2014 05:04:36 -0000
@@ -53,7 +53,7 @@
 .\"
 .\"	@(#)queue.3	8.1 (Berkeley) 12/13/93
 .\"
-.Dd May 17, 2014
+.Dd November 20, 2014
 .Dt QUEUE 3
 .Os
 .Sh NAME
@@ -64,13 +64,19 @@
 .Nm SLIST_EMPTY ,
 .Nm SLIST_NEXT ,
 .Nm SLIST_FOREACH ,
+.Nm SLIST_FOREACH_PSZ ,
 .Nm SLIST_FOREACH_SAFE ,
 .Nm SLIST_INIT ,
 .Nm SLIST_INSERT_AFTER ,
+.Nm SLIST_INSERT_AFTER_PSZ ,
 .Nm SLIST_INSERT_HEAD ,
+.Nm SLIST_INSERT_HEAD_PSZ ,
 .Nm SLIST_REMOVE_AFTER ,
+.Nm SLIST_REMOVE_AFTER_PSZ ,
 .Nm SLIST_REMOVE_HEAD ,
+.Nm SLIST_REMOVE_HEAD_PSZ ,
 .Nm SLIST_REMOVE ,
+.Nm SLIST_REMOVE_PSZ ,
 .Nm LIST_HEAD ,
 .Nm LIST_HEAD_INITIALIZER ,
 .Nm LIST_ENTRY ,
@@ -78,12 +84,17 @@
 .Nm LIST_EMPTY ,
 .Nm LIST_NEXT ,
 .Nm LIST_FOREACH ,
+.Nm LIST_FOREACH_PSZ ,
 .Nm LIST_FOREACH_SAFE ,
 .Nm LIST_INIT ,
 .Nm LIST_INSERT_AFTER ,
+.Nm LIST_INSERT_AFTER_PSZ ,
 .Nm LIST_INSERT_BEFORE ,
+.Nm LIST_INSERT_BEFORE_PSZ ,
 .Nm LIST_INSERT_HEAD ,
+.Nm LIST_INSERT_HEAD_PSZ ,
 .Nm LIST_REMOVE ,
+.Nm LIST_REMOVE_PSZ ,
 .Nm LIST_REPLACE ,
 .Nm LIST_MOVE ,
 .Nm SIMPLEQ_HEAD ,
@@ -94,14 +105,21 @@
 .Nm SIMPLEQ_NEXT ,
 .Nm SIMPLEQ_LAST ,
 .Nm SIMPLEQ_FOREACH ,
+.Nm SIMPLEQ_FOREACH_PSZ ,
 .Nm SIMPLEQ_FOREACH_SAFE ,
 .Nm SIMPLEQ_INIT ,
 .Nm SIMPLEQ_INSERT_AFTER ,
+.Nm SIMPLEQ_INSERT_AFTER_PSZ ,
 .Nm SIMPLEQ_INSERT_HEAD ,
+.Nm SIMPLEQ_INSERT_HEAD_PSZ ,
 .Nm SIMPLEQ_INSERT_TAIL ,
+.Nm SIMPLEQ_INSERT_TAIL_PSZ ,
 .Nm SIMPLEQ_REMOVE_AFTER ,
+.Nm SIMPLEQ_REMOVE_AFTER_PSZ ,
 .Nm SIMPLEQ_REMOVE_HEAD ,
+.Nm SIMPLEQ_REMOVE_HEAD_PSZ ,
 .Nm SIMPLEQ_REMOVE ,
+.Nm SIMPLEQ_REMOVE_PSZ ,
 .Nm SIMPLEQ_CONCAT ,
 .Nm TAILQ_HEAD ,
 .Nm TAILQ_HEAD_INITIALIZER ,
@@ -112,15 +130,21 @@
 .Nm TAILQ_PREV ,
 .Nm TAILQ_EMPTY ,
 .Nm TAILQ_FOREACH ,
+.Nm TAILQ_FOREACH_PSZ ,
 .Nm TAILQ_FOREACH_SAFE ,
 .Nm TAILQ_FOREACH_REVERSE ,
 .Nm TAILQ_FOREACH_REVERSE_SAFE ,
 .Nm TAILQ_INIT ,
 .Nm TAILQ_INSERT_AFTER ,
+.Nm TAILQ_INSERT_AFTER_PSZ ,
 .Nm TAILQ_INSERT_BEFORE ,
+.Nm TAILQ_INSERT_BEFORE_PSZ ,
 .Nm TAILQ_INSERT_HEAD ,
+.Nm TAILQ_INSERT_HEAD_PSZ ,
 .Nm TAILQ_INSERT_TAIL ,
+.Nm TAILQ_INSERT_TAIL_PSZ ,
 .Nm TAILQ_REMOVE ,
+.Nm TAILQ_REMOVE_PSZ ,
 .Nm TAILQ_REPLACE ,
 .Nm TAILQ_CONCAT ,
 .Nm STAILQ_HEAD ,
@@ -131,12 +155,17 @@
 .Nm STAILQ_NEXT ,
 .Nm STAILQ_LAST ,
 .Nm STAILQ_FOREACH ,
+.Nm STAILQ_FOREACH_PSZ ,
 .Nm STAILQ_FOREACH_SAFE ,
 .Nm STAILQ_INIT ,
 .Nm STAILQ_INSERT_AFTER ,
+.Nm STAILQ_INSERT_AFTER_PSZ ,
 .Nm STAILQ_INSERT_HEAD ,
+.Nm STAILQ_INSERT_HEAD_PSZ ,
 .Nm STAILQ_INSERT_TAIL ,
+.Nm STAILQ_INSERT_TAIL_PSZ ,
 .Nm STAILQ_REMOVE_HEAD ,
+.Nm STAILQ_REMOVE_HEAD_PSZ ,
 .Nm STAILQ_REMOVE ,
 .Nm STAILQ_CONCAT ,
 .Nd implementations of singly-linked lists, lists, simple queues, tail queues, and singly-linked tail queues
@@ -153,12 +182,17 @@
 .Ft TYPE *
 .Fn SLIST_NEXT "TYPE *elm" "SLIST_ENTRY NAME"
 .Fn SLIST_FOREACH "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME"
+.Fn SLIST_FOREACH_PSZ "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME"
 .Fn SLIST_FOREACH_SAFE "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" "TYPE *tmp"
 .Fn SLIST_INIT "SLIST_HEAD *head"
 .Fn SLIST_INSERT_HEAD "SLIST_HEAD *head" "TYPE *elm" "SLIST_ENTRY NAME"
+.Fn SLIST_INSERT_HEAD_PSZ "SLIST_HEAD *head" "TYPE *elm" "SLIST_ENTRY NAME"
 .Fn SLIST_INSERT_AFTER "TYPE *listelm" "TYPE *elm" "SLIST_ENTRY NAME"
+.Fn SLIST_INSERT_AFTER_PSZ "TYPE *listelm" "TYPE *elm" "SLIST_ENTRY NAME"
 .Fn SLIST_REMOVE "SLIST_HEAD *head" "TYPE *elm" "TYPE" "SLIST_ENTRY NAME"
+.Fn SLIST_REMOVE_PSZ "SLIST_HEAD *head" "TYPE *elm" "TYPE" "SLIST_ENTRY NAME"
 .Fn SLIST_REMOVE_HEAD "SLIST_HEAD *head" "SLIST_ENTRY NAME"
+.Fn SLIST_REMOVE_HEAD_PSZ "SLIST_HEAD *head" "SLIST_ENTRY NAME"
 .Pp
 .Fn LIST_HEAD "HEADNAME" "TYPE"
 .Fn LIST_HEAD_INITIALIZER "head"
@@ -170,12 +204,17 @@
 .Ft int
 .Fn LIST_EMPTY "LIST_HEAD *head"
 .Fn LIST_FOREACH "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME"
+.Fn LIST_FOREACH_PSZ "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME"
 .Fn LIST_FOREACH_SAFE "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" "TYPE *tmp"
 .Fn LIST_INIT "LIST_HEAD *head"
 .Fn LIST_INSERT_AFTER "TYPE *listelm" "TYPE *elm" "LIST_ENTRY NAME"
+.Fn LIST_INSERT_AFTER_PSZ "TYPE *listelm" "TYPE *elm" "LIST_ENTRY NAME"
 .Fn LIST_INSERT_BEFORE "TYPE *listelm" "TYPE *elm" "LIST_ENTRY NAME"
+.Fn LIST_INSERT_BEFORE_PSZ "TYPE *listelm" "TYPE *elm" "LIST_ENTRY NAME"
 .Fn LIST_INSERT_HEAD "LIST_HEAD *head" "TYPE *elm" "LIST_ENTRY NAME"
+.Fn LIST_INSERT_HEAD_PSZ "LIST_HEAD *head" "TYPE *elm" "LIST_ENTRY NAME"
 .Fn LIST_REMOVE "TYPE *elm" "LIST_ENTRY NAME"
+.Fn LIST_REMOVE_PSZ "TYPE *elm" "LIST_ENTRY NAME"
 .Fn LIST_REPLACE "TYPE *elm" "TYPE *new" "LIST_ENTRY NAME"
 .Fn LIST_MOVE "LIST_HEAD *head1" "LIST_HEAD *head2"
 .Pp
@@ -191,14 +230,21 @@
 .Ft TYPE *
 .Fn SIMPLEQ_LAST "SIMPLEQ_HEAD *head" "TYPE *elm" "SIMPLEQ_ENTRY NAME"
 .Fn SIMPLEQ_FOREACH "TYPE *var" "SIMPLEQ_HEAD *head" "SIMPLEQ_ENTRY NAME"
+.Fn SIMPLEQ_FOREACH_PSZ "TYPE *var" "SIMPLEQ_HEAD *head" "SIMPLEQ_ENTRY NAME"
 .Fn SIMPLEQ_FOREACH_SAFE "TYPE *var" "SIMPLEQ_HEAD *head" "SIMPLEQ_ENTRY NAME" "TYPE *tmp"
 .Fn SIMPLEQ_INIT "SIMPLEQ_HEAD *head"
 .Fn SIMPLEQ_INSERT_HEAD "SIMPLEQ_HEAD *head" "TYPE *elm" "SIMPLEQ_ENTRY NAME"
+.Fn SIMPLEQ_INSERT_HEAD_PSZ "SIMPLEQ_HEAD *head" "TYPE *elm" "SIMPLEQ_ENTRY NAME"
 .Fn SIMPLEQ_INSERT_TAIL "SIMPLEQ_HEAD *head" "TYPE *elm" "SIMPLEQ_ENTRY NAME"
+.Fn SIMPLEQ_INSERT_TAIL_PSZ "SIMPLEQ_HEAD *head" "TYPE *elm" "SIMPLEQ_ENTRY NAME"
 .Fn SIMPLEQ_INSERT_AFTER "SIMPLEQ_HEAD *head" "TYPE *listelm" "TYPE *elm" "SIMPLEQ_ENTRY NAME"
+.Fn SIMPLEQ_INSERT_AFTER_PSZ "SIMPLEQ_HEAD *head" "TYPE *listelm" "TYPE *elm" "SIMPLEQ_ENTRY NAME"
 .Fn SIMPLEQ_REMOVE_HEAD "SIMPLEQ_HEAD *head" "SIMPLEQ_ENTRY NAME"
+.Fn SIMPLEQ_REMOVE_HEAD_PSZ "SIMPLEQ_HEAD *head" "SIMPLEQ_ENTRY NAME"
 .Fn SIMPLEQ_REMOVE_AFTER "SIMPLEQ_HEAD *head" "TYPE *elm" "SIMPLEQ_ENTRY NAME"
+.Fn SIMPLEQ_REMOVE_AFTER_PSZ "SIMPLEQ_HEAD *head" "TYPE *elm" "SIMPLEQ_ENTRY NAME"
 .Fn SIMPLEQ_REMOVE "SIMPLEQ_HEAD *head" "TYPE *elm" "TYPE" "SIMPLEQ_ENTRY NAME"
+.Fn SIMPLEQ_REMOVE_PSZ "SIMPLEQ_HEAD *head" "TYPE *elm" "TYPE" "SIMPLEQ_ENTRY NAME"
 .Fn SIMPLEQ_CONCAT "SIMPLEQ_HEAD *head1" "SIMPLEQ_HEAD *head2"
 .Pp
 .Fn TAILQ_HEAD "HEADNAME" "TYPE"
@@ -215,15 +261,21 @@
 .Ft int
 .Fn TAILQ_EMPTY "TAILQ_HEAD *head"
 .Fn TAILQ_FOREACH "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME"
+.Fn TAILQ_FOREACH_PSZ "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME"
 .Fn TAILQ_FOREACH_SAFE "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" "TYPE *tmp"
 .Fn TAILQ_FOREACH_REVERSE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME"
 .Fn TAILQ_FOREACH_REVERSE_SAFE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" "TYPE *tmp"
 .Fn TAILQ_INIT "TAILQ_HEAD *head"
 .Fn TAILQ_INSERT_HEAD "TAILQ_HEAD *head" "TYPE *elm" "TAILQ_ENTRY NAME"
+.Fn TAILQ_INSERT_HEAD_PSZ "TAILQ_HEAD *head" "TYPE *elm" "TAILQ_ENTRY NAME"
 .Fn TAILQ_INSERT_TAIL "TAILQ_HEAD *head" "TYPE *elm" "TAILQ_ENTRY NAME"
+.Fn TAILQ_INSERT_TAIL_PSZ "TAILQ_HEAD *head" "TYPE *elm" "TAILQ_ENTRY NAME"
 .Fn TAILQ_INSERT_AFTER "TAILQ_HEAD *head" "TYPE *listelm" "TYPE *elm" "TAILQ_ENTRY NAME"
+.Fn TAILQ_INSERT_AFTER_PSZ "TAILQ_HEAD *head" "TYPE *listelm" "TYPE *elm" "TAILQ_ENTRY NAME"
 .Fn TAILQ_INSERT_BEFORE "TYPE *listelm" "TYPE *elm" "TAILQ_ENTRY NAME"
+.Fn TAILQ_INSERT_BEFORE_PSZ "TYPE *listelm" "TYPE *elm" "TAILQ_ENTRY NAME"
 .Fn TAILQ_REMOVE "TAILQ_HEAD *head" "TYPE *elm" "TAILQ_ENTRY NAME"
+.Fn TAILQ_REMOVE_PSZ "TAILQ_HEAD *head" "TYPE *elm" "TAILQ_ENTRY NAME"
 .Fn TAILQ_REPLACE "TAILQ_HEAD *head" "TYPE *elm" "TYPE *new" "TAILQ_ENTRY NAME"
 .Fn TAILQ_CONCAT "TAILQ_HEAD *head1" "TAILQ_HEAD *head2" "TAILQ_ENTRY NAME"
 .Pp
@@ -239,13 +291,19 @@
 .Ft TYPE *
 .Fn STAILQ_LAST "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
 .Fn STAILQ_FOREACH "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
+.Fn STAILQ_FOREACH_PSZ "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
 .Fn STAILQ_FOREACH_SAFE "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" "TYPE *tmp"
 .Fn STAILQ_INIT "STAILQ_HEAD *head"
 .Fn STAILQ_INSERT_HEAD "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
+.Fn STAILQ_INSERT_HEAD_PSZ "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
 .Fn STAILQ_INSERT_TAIL "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
+.Fn STAILQ_INSERT_TAIL_PSZ "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
 .Fn STAILQ_INSERT_AFTER "STAILQ_HEAD *head" "TYPE *listelm" "TYPE *elm" "STAILQ_ENTRY NAME"
+.Fn STAILQ_INSERT_AFTER_PSZ "STAILQ_HEAD *head" "TYPE *listelm" "TYPE *elm" "STAILQ_ENTRY NAME"
 .Fn STAILQ_REMOVE_HEAD "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
+.Fn STAILQ_REMOVE_HEAD_PSZ "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
 .Fn STAILQ_REMOVE "STAILQ_HEAD *head" "TYPE *elm" "TYPE" "STAILQ_ENTRY NAME"
+.Fn STAILQ_REMOVE_PSZ "STAILQ_HEAD *head" "TYPE *elm" "TYPE" "STAILQ_ENTRY NAME"
 .Fn STAILQ_CONCAT "STAILQ_HEAD *head1" "STAILQ_HEAD *head2"
 .Sh DESCRIPTION
 These macros define and operate on five types of data structures:
@@ -263,6 +321,14 @@ Removal of any entry in the list.
 Forward traversal through the list.
 .El
 .Pp
+All five structures additionally support variants of the above
+operations that issue the necessary memory barriers for passive
+serialization,
+.Xr pserialize 9 .
+See
+.Sx PASSIVE SERIALIZATION
+for details.
+.Pp
 Singly-linked lists are the simplest of the four data structures and
 support only the above functionality.
 Singly-linked lists are ideal for applications with large datasets and
@@ -1072,6 +1138,60 @@ and
 are functionally identical to these simple queue functions,
 and are provided for compatibility with
 .Fx .
+.Sh PASSIVE SERIALIZATION
+All queue structures support operations that issue the necessary memory
+barriers for passive serialization,
+.Xr pserialize 9 ,
+named with the suffix
+.Li _PSZ .
+Specifically:
+.Bl -bullet -offset indent
+.It
+A writer may publish an entry with
+.Fn *_INSERT_*_PSZ
+(e.g.,
+.Fn TAILQ_INSERT_TAIL_PSZ ) Ns .
+.Pp
+The
+.Fn *_INSERT_*_PSZ
+operations will issue any necessary store barrier before publishing the
+entry to other CPUs.
+.It
+A writer may remove an entry with
+.Fn *_REMOVE*_PSZ
+(e.g.,
+.Fn TAILQ_REMOVE_PSZ )
+and then issue
+.Fn pserialize_perform
+to make sure no more readers have access to it before freeing or
+reusing the memory allocated for it.
+.Pp
+The
+.Fn *_REMOVE*_PSZ
+operations are identical to the non-pserialized versions, but are
+provided nevertheless to make it clearer when passive serialization is
+involved.
+.It
+A reader may iterate over a queue forward (but not backward) with
+.Fn *_FOREACH_PSZ
+(e.g.,
+.Fn TAILQ_FOREACH_PSZ ) Ns .
+.Pp
+The
+.Fn *_FOREACH_PSZ
+macros issue any necessary data-dependent load barrier after fetching
+the pointer to the current entry and before entering the body of the
+loop.
+.Pp
+Writers may use
+.Fn *_FOREACH ;
+they need not use
+.Fn *_FOREACH_PSZ
+(although it would not hurt to do so).
+There are no
+.Fn *_FOREACH_SAFE_PSZ
+macros because readers have no need for it.
+.El
 .Sh NOTES
 Some of these macros or functions perform no error checking,
 and invalid usage leads to undefined behaviour.
Index: sys/sys/queue.h
===================================================================
RCS file: /cvsroot/src/sys/sys/queue.h,v
retrieving revision 1.67
diff -p -u -r1.67 queue.h
--- sys/sys/queue.h	17 May 2014 21:22:56 -0000	1.67
+++ sys/sys/queue.h	21 Nov 2014 05:04:36 -0000
@@ -77,6 +77,17 @@
  * A circle queue may be traversed in either direction, but has a more
  * complex end of list detection.
  *
+ * The *_PSZ variants of the macros here are safe to use with passive
+ * serialization, pserialize(9).  Specifically:
+ *
+ * - A writer may publish a new entry with *_INSERT*_PSZ.
+ *
+ * - A writer may remove an entry with *_REMOVE*_PSZ and then issue
+ *   pserialize_perform to make sure no more readers have it before
+ *   freeing it.
+ *
+ * - A reader may iterate forward over a queue with *_FOREACH_PSZ.
+ *
  * For details on the use of these macros, see the queue(3) manual page.
  */
 
@@ -86,8 +97,15 @@
  * portable and it can simply be dropped verbatim into any system.
  * The caveat is that on other systems some other header
  * must provide NULL before the macros can be used.
+ *
+ * Likewise <sys/atomic.h> -- you will need to redefine the *_PSZ
+ * macros for passive serialization if you want to use other systems'
+ * atomic operations.
+ *
+ * WARNING: QUEUEDEBUG is incompatible with passive serialization.
  */
 #ifdef __NetBSD__
+#include <sys/atomic.h>
 #include <sys/null.h>
 #endif
 
@@ -124,11 +142,15 @@ struct {								\
 #define	SLIST_EMPTY(head)	((head)->slh_first == NULL)
 #define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
 
-#define	SLIST_FOREACH(var, head, field)					\
-	for((var) = (head)->slh_first;					\
-	    (var) != SLIST_END(head);					\
+#define	_SLIST_FOREACH(var, head, field, barrier)			\
+	for ((var) = (head)->slh_first;					\
+	    ((var) != SLIST_END(head) && (barrier, 1));			\
 	    (var) = (var)->field.sle_next)
 
+#define	SLIST_FOREACH(v,h,f)		_SLIST_FOREACH(v,h,f,((void)0))
+#define	SLIST_FOREACH_PSZ(v,h,f)	\
+	_SLIST_FOREACH(v,h,f,membar_datadep_consumer())
+
 #define	SLIST_FOREACH_SAFE(var, head, field, tvar)			\
 	for ((var) = SLIST_FIRST((head));				\
 	    (var) != SLIST_END(head) &&					\
@@ -142,25 +164,39 @@ struct {								\
 	(head)->slh_first = SLIST_END(head);				\
 } while (/*CONSTCOND*/0)
 
-#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
+#define	_SLIST_INSERT_AFTER(slistelm, elm, field, barrier) do {		\
 	(elm)->field.sle_next = (slistelm)->field.sle_next;		\
+	barrier;							\
 	(slistelm)->field.sle_next = (elm);				\
 } while (/*CONSTCOND*/0)
 
-#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
+#define	SLIST_INSERT_AFTER(s,e,f)	_SLIST_INSERT_AFTER(s,e,f,((void)0))
+#define	SLIST_INSERT_AFTER_PSZ(s,e,f)	\
+	_SLIST_INSERT_AFTER(s,e,f,membar_producer())
+
+#define	_SLIST_INSERT_HEAD(head, elm, field, barrier) do {		\
 	(elm)->field.sle_next = (head)->slh_first;			\
+	barrier;							\
 	(head)->slh_first = (elm);					\
 } while (/*CONSTCOND*/0)
 
+#define	SLIST_INSERT_HEAD(h,e,f)	_SLIST_INSERT_HEAD(h,e,f,((void)0))
+#define	SLIST_INSERT_HEAD_PSZ(h,e,f)	\
+	_SLIST_INSERT_HEAD(s,e,f,membar_producer())
+
 #define	SLIST_REMOVE_AFTER(slistelm, field) do {			\
 	(slistelm)->field.sle_next =					\
 	    SLIST_NEXT(SLIST_NEXT((slistelm), field), field);		\
 } while (/*CONSTCOND*/0)
 
+#define	SLIST_REMOVE_AFTER_PSZ	SLIST_REMOVE_AFTER
+
 #define	SLIST_REMOVE_HEAD(head, field) do {				\
 	(head)->slh_first = (head)->slh_first->field.sle_next;		\
 } while (/*CONSTCOND*/0)
 
+#define	SLIST_REMOVE_HEAD_PSZ	SLIST_REMOVE_HEAD
+
 #define	SLIST_REMOVE(head, elm, type, field) do {			\
 	if ((head)->slh_first == (elm)) {				\
 		SLIST_REMOVE_HEAD((head), field);			\
@@ -174,6 +210,7 @@ struct {								\
 	}								\
 } while (/*CONSTCOND*/0)
 
+#define	SLIST_REMOVE_PSZ	SLIST_REMOVE
 
 /*
  * List definitions.
@@ -200,11 +237,15 @@ struct {								\
 #define	LIST_EMPTY(head)		((head)->lh_first == LIST_END(head))
 #define	LIST_NEXT(elm, field)		((elm)->field.le_next)
 
-#define	LIST_FOREACH(var, head, field)					\
+#define	_LIST_FOREACH(var, head, field, barrier)			\
 	for ((var) = ((head)->lh_first);				\
-	    (var) != LIST_END(head);					\
+	    ((var) != LIST_END(head) && (barrier, 1));			\
 	    (var) = ((var)->field.le_next))
 
+#define	LIST_FOREACH(v,h,f)		_LIST_FOREACH(v,h,f,((void)0))
+#define	LIST_FOREACH_PSZ(v,h,f)		\
+	_LIST_FOREACH(v,h,f,membar_datadep_consumer())
+
 #define	LIST_FOREACH_SAFE(var, head, field, tvar)			\
 	for ((var) = LIST_FIRST((head));				\
 	    (var) != LIST_END(head) &&					\
@@ -250,32 +291,48 @@ struct {								\
 	(head)->lh_first = LIST_END(head);				\
 } while (/*CONSTCOND*/0)
 
-#define	LIST_INSERT_AFTER(listelm, elm, field) do {			\
+#define	_LIST_INSERT_AFTER(listelm, elm, field, barrier) do {		\
 	QUEUEDEBUG_LIST_OP((listelm), field)				\
-	if (((elm)->field.le_next = (listelm)->field.le_next) != 	\
-	    LIST_END(head))						\
+	(elm)->field.le_next = (listelm)->field.le_next;		\
+	(elm)->field.le_prev = &(listelm)->field.le_next;		\
+	barrier;							\
+	if ((elm)->field.le_next != LIST_END(head))			\
 		(listelm)->field.le_next->field.le_prev =		\
 		    &(elm)->field.le_next;				\
 	(listelm)->field.le_next = (elm);				\
-	(elm)->field.le_prev = &(listelm)->field.le_next;		\
 } while (/*CONSTCOND*/0)
 
-#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
+#define	LIST_INSERT_AFTER(l,e,f)	_LIST_INSERT_AFTER(l,e,f,((void)0))
+#define	LIST_INSERT_AFTER_PSZ(l,e,f)	\
+	_LIST_INSERT_AFTER(l,e,f,membar_producer())
+
+#define	_LIST_INSERT_BEFORE(listelm, elm, field, barrier) do {		\
 	QUEUEDEBUG_LIST_OP((listelm), field)				\
 	(elm)->field.le_prev = (listelm)->field.le_prev;		\
 	(elm)->field.le_next = (listelm);				\
+	barrier;							\
 	*(listelm)->field.le_prev = (elm);				\
 	(listelm)->field.le_prev = &(elm)->field.le_next;		\
 } while (/*CONSTCOND*/0)
 
-#define	LIST_INSERT_HEAD(head, elm, field) do {				\
+#define	LIST_INSERT_BEFORE(l,e,f)	_LIST_INSERT_BEFORE(l,e,f,((void)0))
+#define	LIST_INSERT_BEFORE_PSZ(l,e,f)	\
+	_LIST_INSERT_BEFORE(l,e,f,membar_producer())
+
+#define	_LIST_INSERT_HEAD(head, elm, field, barrier) do {		\
 	QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field)		\
-	if (((elm)->field.le_next = (head)->lh_first) != LIST_END(head))\
+	(elm)->field.le_next = (head)->lh_first;			\
+	(elm)->field.le_prev = &(head)->lh_first;			\
+	barrier;							\
+	if ((elm)->field.le_next != LIST_END(head))			\
 		(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
 	(head)->lh_first = (elm);					\
-	(elm)->field.le_prev = &(head)->lh_first;			\
 } while (/*CONSTCOND*/0)
 
+#define	LIST_INSERT_HEAD(h,e,f)		_LIST_INSERT_HEAD(h,e,f,((void)0))
+#define	LIST_INSERT_HEAD_PSZ(h,e,f)	\
+	_LIST_INSERT_HEAD(h,e,f,membar_producer())
+
 #define	LIST_REMOVE(elm, field) do {					\
 	QUEUEDEBUG_LIST_OP((elm), field)				\
 	if ((elm)->field.le_next != NULL)				\
@@ -285,6 +342,8 @@ struct {								\
 	QUEUEDEBUG_LIST_POSTREMOVE((elm), field)			\
 } while (/*CONSTCOND*/0)
 
+#define	LIST_REMOVE_PSZ	LIST_REMOVE
+
 #define LIST_REPLACE(elm, elm2, field) do {				\
 	if (((elm2)->field.le_next = (elm)->field.le_next) != NULL)	\
 		(elm2)->field.le_next->field.le_prev =			\
@@ -319,11 +378,15 @@ struct {								\
 #define	SIMPLEQ_EMPTY(head)		((head)->sqh_first == SIMPLEQ_END(head))
 #define	SIMPLEQ_NEXT(elm, field)	((elm)->field.sqe_next)
 
-#define	SIMPLEQ_FOREACH(var, head, field)				\
+#define	_SIMPLEQ_FOREACH(var, head, field, barrier)			\
 	for ((var) = ((head)->sqh_first);				\
-	    (var) != SIMPLEQ_END(head);					\
+	    (var) != SIMPLEQ_END(head) && (barrier, 1);			\
 	    (var) = ((var)->field.sqe_next))
 
+#define	SIMPLEQ_FOREACH(v,h,f)		_SIMPLEQ_FOREACH(v,h,f,((void)0))
+#define	SIMPLEQ_FOREACH_PSZ(v,h,f)	\
+	_SIMPLEQ_FOREACH(v,h,f,membar_datadep_consumer())
+
 #define	SIMPLEQ_FOREACH_SAFE(var, head, field, next)			\
 	for ((var) = ((head)->sqh_first);				\
 	    (var) != SIMPLEQ_END(head) &&				\
@@ -338,35 +401,56 @@ struct {								\
 	(head)->sqh_last = &(head)->sqh_first;				\
 } while (/*CONSTCOND*/0)
 
-#define	SIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
-	if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)	\
+#define	_SIMPLEQ_INSERT_HEAD(head, elm, field, barrier) do {		\
+	(elm)->field.sqe_next = (head)->sqh_first;			\
+	barrier;							\
+	if ((elm)->field.sqe_next == NULL)				\
 		(head)->sqh_last = &(elm)->field.sqe_next;		\
 	(head)->sqh_first = (elm);					\
 } while (/*CONSTCOND*/0)
 
-#define	SIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
+#define	SIMPLEQ_INSERT_HEAD(h,e,f)	_SIMPLEQ_INSERT_HEAD(h,e,f,((void)0))
+#define	SIMPLEQ_INSERT_HEAD_PSZ(h,e,f)	\
+	_SIMPLEQ_INSERT_HEAD(h,e,f,membar_producer())
+
+#define	_SIMPLEQ_INSERT_TAIL(head, elm, field, barrier) do {		\
 	(elm)->field.sqe_next = NULL;					\
+	barrier;							\
 	*(head)->sqh_last = (elm);					\
 	(head)->sqh_last = &(elm)->field.sqe_next;			\
 } while (/*CONSTCOND*/0)
 
-#define	SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
-	if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+#define	SIMPLEQ_INSERT_TAIL(h,e,f)	_SIMPLEQ_INSERT_TAIL(h,e,f,((void)0))
+#define	SIMPLEQ_INSERT_TAIL_PSZ(h,e,f)	\
+	_SIMPLEQ_INSERT_TAIL(h,e,f,membar_producer())
+
+#define	_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	(elm)->field.sqe_next = (listelm)->field.sqe_next;		\
+	barrier;							\
+	if ((elm)->field.sqe_next == NULL)				\
 		(head)->sqh_last = &(elm)->field.sqe_next;		\
 	(listelm)->field.sqe_next = (elm);				\
 } while (/*CONSTCOND*/0)
 
+#define	SIMPLEQ_INSERT_AFTER(h,e,f)	_SIMPLEQ_INSERT_AFTER(h,e,f,((void)0))
+#define	SIMPLEQ_INSERT_AFTER_PSZ(h,e,f)	\
+	_SIMPLEQ_INSERT_AFTER(h,e,f,membar_producer())
+
 #define	SIMPLEQ_REMOVE_HEAD(head, field) do {				\
 	if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
 		(head)->sqh_last = &(head)->sqh_first;			\
 } while (/*CONSTCOND*/0)
 
+#define	SIMPLEQ_REMOVE_HEAD_PSZ		SIMPLEQ_REMOVE_HEAD
+
 #define SIMPLEQ_REMOVE_AFTER(head, elm, field) do {			\
 	if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
 	    == NULL)							\
 		(head)->sqh_last = &(elm)->field.sqe_next;		\
 } while (/*CONSTCOND*/0)
 
+#define	SIMPLEQ_REMOVE_AFTER_PSZ	SIMPLEQ_REMOVE_AFTER
+
 #define	SIMPLEQ_REMOVE(head, elm, type, field) do {			\
 	if ((head)->sqh_first == (elm)) {				\
 		SIMPLEQ_REMOVE_HEAD((head), field);			\
@@ -380,6 +464,8 @@ struct {								\
 	}								\
 } while (/*CONSTCOND*/0)
 
+#define	SIMPLEQ_REMOVE_PSZ		SIMPLEQ_REMOVE
+
 #define	SIMPLEQ_CONCAT(head1, head2) do {				\
 	if (!SIMPLEQ_EMPTY((head2))) {					\
 		*(head1)->sqh_last = (head2)->sqh_first;		\
@@ -427,11 +513,15 @@ struct {								\
 #define	TAILQ_EMPTY(head)		(TAILQ_FIRST(head) == TAILQ_END(head))
 
 
-#define	TAILQ_FOREACH(var, head, field)					\
+#define	_TAILQ_FOREACH(var, head, field, barrier)			\
 	for ((var) = ((head)->tqh_first);				\
-	    (var) != TAILQ_END(head);					\
+	    (var) != TAILQ_END(head) && (barrier, 1);			\
 	    (var) = ((var)->field.tqe_next))
 
+#define	TAILQ_FOREACH(v,h,f)		_TAILQ_FOREACH(v,h,f,((void)0))
+#define	TAILQ_FOREACH_PSZ(v,h,f)	\
+	_TAILQ_FOREACH(v,h,f,membar_datadep_consumer())
+
 #define	TAILQ_FOREACH_SAFE(var, head, field, next)			\
 	for ((var) = ((head)->tqh_first);				\
 	    (var) != TAILQ_END(head) &&					\
@@ -490,45 +580,66 @@ struct {								\
 	(head)->tqh_last = &(head)->tqh_first;				\
 } while (/*CONSTCOND*/0)
 
-#define	TAILQ_INSERT_HEAD(head, elm, field) do {			\
+#define	_TAILQ_INSERT_HEAD(head, elm, field, barrier) do {		\
 	QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field)		\
-	if (((elm)->field.tqe_next = (head)->tqh_first) != TAILQ_END(head))\
+	(elm)->field.tqe_prev = &(head)->tqh_first;			\
+	(elm)->field.tqe_next = (head)->tqh_first;			\
+	barrier;							\
+	if ((elm)->field.tqe_next != TAILQ_END(head))			\
 		(head)->tqh_first->field.tqe_prev =			\
 		    &(elm)->field.tqe_next;				\
 	else								\
 		(head)->tqh_last = &(elm)->field.tqe_next;		\
 	(head)->tqh_first = (elm);					\
-	(elm)->field.tqe_prev = &(head)->tqh_first;			\
 } while (/*CONSTCOND*/0)
 
-#define	TAILQ_INSERT_TAIL(head, elm, field) do {			\
+#define	TAILQ_INSERT_HEAD(h,e,f)	_TAILQ_INSERT_HEAD(h,e,f,((void)0))
+#define	TAILQ_INSERT_HEAD_PSZ(h,e,f)	\
+	_TAILQ_INSERT_HEAD(h,e,f,membar_producer())
+
+#define	_TAILQ_INSERT_TAIL(head, elm, field, barrier) do {		\
 	QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field)		\
 	(elm)->field.tqe_next = TAILQ_END(head);			\
 	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	barrier;							\
 	*(head)->tqh_last = (elm);					\
 	(head)->tqh_last = &(elm)->field.tqe_next;			\
 } while (/*CONSTCOND*/0)
 
-#define	TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+#define	TAILQ_INSERT_TAIL(h,e,f)	_TAILQ_INSERT_TAIL(h,e,f,((void)0))
+#define	TAILQ_INSERT_TAIL_PSZ(h,e,f)	\
+	_TAILQ_INSERT_TAIL(h,e,f,membar_producer())
+
+#define	_TAILQ_INSERT_AFTER(head, listelm, elm, field, barrier) do {	\
 	QUEUEDEBUG_TAILQ_OP((listelm), field)				\
-	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != 	\
-	    TAILQ_END(head))						\
+	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
+	(elm)->field.tqe_next = (listelm)->field.tqe_next;		\
+	barrier;							\
+	if ((elm)->field.tqe_next != TAILQ_END(head))			\
 		(elm)->field.tqe_next->field.tqe_prev = 		\
 		    &(elm)->field.tqe_next;				\
 	else								\
 		(head)->tqh_last = &(elm)->field.tqe_next;		\
 	(listelm)->field.tqe_next = (elm);				\
-	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
 } while (/*CONSTCOND*/0)
 
-#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
+#define	TAILQ_INSERT_AFTER(h,l,e,f)	_TAILQ_INSERT_AFTER(h,l,e,f,((void)0))
+#define	TAILQ_INSERT_AFTER_PSZ(h,l,e,f)	\
+	_TAILQ_INSERT_AFTER(h,l,e,f,membar_producer())
+
+#define	_TAILQ_INSERT_BEFORE(listelm, elm, field, barrier) do {		\
 	QUEUEDEBUG_TAILQ_OP((listelm), field)				\
 	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
 	(elm)->field.tqe_next = (listelm);				\
+	barrier;							\
 	*(listelm)->field.tqe_prev = (elm);				\
 	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
 } while (/*CONSTCOND*/0)
 
+#define	TAILQ_INSERT_BEFORE(l,e,f)	_TAILQ_INSERT_BEFORE(l,e,f,((void)0))
+#define	TAILQ_INSERT_BEFORE_PSZ(l,e,f)	\
+	_TAILQ_INSERT_BEFORE(l,e,f,membar_producer())
+
 #define	TAILQ_REMOVE(head, elm, field) do {				\
 	QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field)		\
 	QUEUEDEBUG_TAILQ_OP((elm), field)				\
@@ -541,6 +652,8 @@ struct {								\
 	QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field);			\
 } while (/*CONSTCOND*/0)
 
+#define	TAILQ_REMOVE_PSZ	TAILQ_REMOVE
+
 #define TAILQ_REPLACE(head, elm, elm2, field) do {                      \
         if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != 	\
 	    TAILQ_END(head))   						\
@@ -595,29 +708,48 @@ struct {								\
 	(head)->stqh_last = &(head)->stqh_first;				\
 } while (/*CONSTCOND*/0)
 
-#define	STAILQ_INSERT_HEAD(head, elm, field) do {			\
-	if (((elm)->field.stqe_next = (head)->stqh_first) == NULL)	\
+#define	_STAILQ_INSERT_HEAD(head, elm, field, barrier) do {		\
+	(elm)->field.stqe_next = (head)->stqh_first;			\
+	barrier;							\
+	if ((elm)->field.stqe_next == NULL)				\
 		(head)->stqh_last = &(elm)->field.stqe_next;		\
 	(head)->stqh_first = (elm);					\
 } while (/*CONSTCOND*/0)
 
-#define	STAILQ_INSERT_TAIL(head, elm, field) do {			\
+#define	STAILQ_INSERT_HEAD(h,e,f)	_STAILQ_INSERT_HEAD(h,e,f,((void)0))
+#define	STAILQ_INSERT_HEAD_PSZ(h,e,f)	\
+	_STAILQ_INSERT_HEAD(h,e,f,membar_producer())
+
+#define	_STAILQ_INSERT_TAIL(head, elm, field, barrier) do {		\
 	(elm)->field.stqe_next = NULL;					\
+	barrier;							\
 	*(head)->stqh_last = (elm);					\
 	(head)->stqh_last = &(elm)->field.stqe_next;			\
 } while (/*CONSTCOND*/0)
 
-#define	STAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
-	if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\
+#define	STAILQ_INSERT_TAIL(h,e,f)	_STAILQ_INSERT_TAIL(h,e,f,((void)0))
+#define	STAILQ_INSERT_TAIL_PSZ(h,e,f)	\
+	_STAILQ_INSERT_TAIL(h,e,f,membar_producer())
+
+#define	_STAILQ_INSERT_AFTER(head, listelm, elm, field, barrier) do {	\
+	(elm)->field.stqe_next = (listelm)->field.stqe_next;		\
+	barrier;							\
+	if ((elm)->field.stqe_next == NULL)				\
 		(head)->stqh_last = &(elm)->field.stqe_next;		\
 	(listelm)->field.stqe_next = (elm);				\
 } while (/*CONSTCOND*/0)
 
+#define	STAILQ_INSERT_AFTER(h,l,e,f)	_STAILQ_INSERT_AFTER(h,l,e,f,((void)0))
+#define	STAILQ_INSERT_AFTER_PSZ(h,l,e,f)	\
+	_STAILQ_INSERT_AFTER(h,l,e,f,membar_producer())
+
 #define	STAILQ_REMOVE_HEAD(head, field) do {				\
 	if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \
 		(head)->stqh_last = &(head)->stqh_first;			\
 } while (/*CONSTCOND*/0)
 
+#define	STAILQ_REMOVE_HEAD_PSZ	STAILQ_REMOVE_HEAD
+
 #define	STAILQ_REMOVE(head, elm, type, field) do {			\
 	if ((head)->stqh_first == (elm)) {				\
 		STAILQ_REMOVE_HEAD((head), field);			\
@@ -631,11 +763,17 @@ struct {								\
 	}								\
 } while (/*CONSTCOND*/0)
 
-#define	STAILQ_FOREACH(var, head, field)				\
+#define	STAILQ_REMOVE_PSZ	STAILQ_REMOVE
+
+#define	_STAILQ_FOREACH(var, head, field, barrier)			\
 	for ((var) = ((head)->stqh_first);				\
-		(var);							\
+		(var) && (barrier, 1);					\
 		(var) = ((var)->field.stqe_next))
 
+#define	STAILQ_FOREACH(v,h,f)		_STAILQ_FOREACH(v,h,f,((void)0))
+#define	STAILQ_FOREACH_PSZ(v,h,f)	\
+	_STAILQ_FOREACH(v,h,f,membar_datadep_consumer())
+
 #define	STAILQ_FOREACH_SAFE(var, head, field, tvar)			\
 	for ((var) = STAILQ_FIRST((head));				\
 	    (var) && ((tvar) = STAILQ_NEXT((var), field), 1);		\


Home | Main Index | Thread Index | Old Index