Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 3 Jul 2002 13:46:25 -0700
From:      Neal Fachan <neal@isilon.com>
To:        Julian Elischer <julian@elischer.org>
Cc:        Terry Lambert <tlambert2@mindspring.com>, Garrett Wollman <wollman@lcs.mit.edu>, Jonathan Lemon <jlemon@flugsvamp.com>, current@FreeBSD.ORG
Subject:   Re: additional queue macro
Message-ID:  <20020703134624.B95118@isilon.com>
In-Reply-To: <Pine.BSF.4.21.0207021648200.97650-100000@InterJet.elischer.org>; from julian@elischer.org on Tue, Jul 02, 2002 at 04:54:43PM -0700
References:  <Pine.BSF.4.21.0207021556300.97650-100000@InterJet.elischer.org> <Pine.BSF.4.21.0207021648200.97650-100000@InterJet.elischer.org>

next in thread | previous in thread | raw e-mail | index | archive | help

--BOKacYhQ+x31HxR3
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

We've got local changes (which I've attached) where the name is
*_FOREACH_REMOVE. We didn't add reverse removable iterators. Also, the
temp variable is the second argument. I can't think of a way of doing it
without having the externally declare the temporary variable.

On Tue, Jul 02, 2002 at 04:54:43PM -0700, Julian Elischer wrote:
> 
> 
> On Tue, 2 Jul 2002, Julian Elischer wrote:
> 
> Having just re-read my own mail
> 
> I think I agree with jonathan now..
> I think we neeed to either:
> 1/ augment the man page  giving an example of how to do
> multiple removes from a list/queue.
> 2/ Explain in detail why using XXXX_FOREACH()
> is bad for this, and showing the alternative.
> 3/ Add something to the API that makes this easy to do.
> designing the API addition is tricky. Jonathan's effort
> was quite good, though I wonder if there is any way we can get it done
> without needing the decalration of 'tmp' separatly.
> (I can't think of a way).
> 
> 
> 
> > /* 
> >  * Move any threads that should be suspended from the run queue
> >  * to the suspend queue.
> >  */
> > TAILQ_FOREACH(from run queue) {
> > 	if (something) {
> > 		TAILQ_REMOVE(element from run queue)
> > 		TAILQ_INSERT_TAIL(onto suspend queue)
> > 	}
> > }
> > 
> > Now, at first glance, the documentation suggests this should work, even
> > though we know it won't. but it doesn't crash.. it just terminates on the
> > first transfer because it reaches the end of the queue.. the suspend queue
> > that is..
> 
> TAILQ_FOREACH_REMOVABLE or TAILQ_FOREACH_SAFE
> (I prefer the first) are my suggestions for the name.)
> 
> 
> 
> 
> To Unsubscribe: send mail to majordomo@FreeBSD.org
> with "unsubscribe freebsd-current" in the body of the message

-- 
Neal Fachan
neal@isilon.com

--BOKacYhQ+x31HxR3
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="queue.diff"

Index: share/man/man3/queue.3
===================================================================
RCS file: /usr/local/ncvs/atera/src/share/man/man3/queue.3,v
retrieving revision 1.1
diff -u -p -r1.1 queue.3
--- share/man/man3/queue.3	9 Mar 2002 02:34:15 -0000	1.1
+++ share/man/man3/queue.3	3 Jul 2002 20:46:19 -0000
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1993
+tail queue Copyright (c) 1993
 .\"	The Regents of the University of California.  All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
@@ -40,6 +40,7 @@
 .Nm SLIST_ENTRY ,
 .Nm SLIST_FIRST ,
 .Nm SLIST_FOREACH ,
+.Nm SLIST_FOREACH_REMOVE ,
 .Nm SLIST_HEAD ,
 .Nm SLIST_HEAD_INITIALIZER ,
 .Nm SLIST_INIT ,
@@ -52,6 +53,7 @@
 .Nm STAILQ_ENTRY ,
 .Nm STAILQ_FIRST ,
 .Nm STAILQ_FOREACH ,
+.Nm STAILQ_FOREACH_REMOVE ,
 .Nm STAILQ_HEAD ,
 .Nm STAILQ_HEAD_INITIALIZER ,
 .Nm STAILQ_INIT ,
@@ -66,6 +68,7 @@
 .Nm LIST_ENTRY ,
 .Nm LIST_FIRST ,
 .Nm LIST_FOREACH ,
+.Nm LIST_FOREACH_REMOVE ,
 .Nm LIST_HEAD ,
 .Nm LIST_HEAD_INITIALIZER ,
 .Nm LIST_INIT ,
@@ -78,6 +81,7 @@
 .Nm TAILQ_ENTRY ,
 .Nm TAILQ_FIRST ,
 .Nm TAILQ_FOREACH ,
+.Nm TAILQ_FOREACH_REMOVE ,
 .Nm TAILQ_FOREACH_REVERSE ,
 .Nm TAILQ_HEAD ,
 .Nm TAILQ_HEAD_INITIALIZER ,
@@ -99,6 +103,7 @@ lists and tail queues
 .Fn SLIST_ENTRY "TYPE"
 .Fn SLIST_FIRST "SLIST_HEAD *head"
 .Fn SLIST_FOREACH "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME"
+.Fn SLIST_FOREACH_REMOVE "TYPE *var" "TYPE *tmpvar" "SLIST_HEAD *head" "SLIST_ENTRY NAME"
 .Fn SLIST_HEAD "HEADNAME" "TYPE"
 .Fn SLIST_HEAD_INITIALIZER "SLIST_HEAD head"
 .Fn SLIST_INIT "SLIST_HEAD *head"
@@ -112,6 +117,7 @@ lists and tail queues
 .Fn STAILQ_ENTRY "TYPE"
 .Fn STAILQ_FIRST "STAILQ_HEAD *head"
 .Fn STAILQ_FOREACH "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
+.Fn STAILQ_FOREACH_REMOVE "TYPE *var" "TYPE *tmpvar" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
 .Fn STAILQ_HEAD "HEADNAME" "TYPE"
 .Fn STAILQ_HEAD_INITIALIZER "STAILQ_HEAD head"
 .Fn STAILQ_INIT "STAILQ_HEAD *head"
@@ -127,6 +133,7 @@ lists and tail queues
 .Fn LIST_ENTRY "TYPE"
 .Fn LIST_FIRST "LIST_HEAD *head"
 .Fn LIST_FOREACH "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME"
+.Fn LIST_FOREACH_REMOVE "TYPE *var" "TYPE *tmpvar" "LIST_HEAD *head" "LIST_ENTRY NAME"
 .Fn LIST_HEAD "HEADNAME" "TYPE"
 .Fn LIST_HEAD_INITIALIZER "LIST_HEAD head"
 .Fn LIST_INIT "LIST_HEAD *head"
@@ -140,6 +147,7 @@ lists and tail queues
 .Fn TAILQ_ENTRY "TYPE"
 .Fn TAILQ_FIRST "TAILQ_HEAD *head"
 .Fn TAILQ_FOREACH "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME"
+.Fn TAILQ_FOREACH_REMOVE "TYPE *var" "TYPE *tmpvar" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME"
 .Fn TAILQ_FOREACH_REVERSE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME"
 .Fn TAILQ_HEAD "HEADNAME" "TYPE"
 .Fn TAILQ_HEAD_INITIALIZER "TAILQ_HEAD head"
@@ -316,6 +324,24 @@ turn to
 .Fa var .
 .Pp
 The macro
+.Nm SLIST_FOREACH_REMOVE
+traverses the list referenced by
+.Fa head
+in the forward direction, assigning each element in
+turn to
+.Fa var .
+Unlike
+.Nm SLIST_FOREACH ,
+.Fa var
+is never dereferenced after the body of the loop, making it legal to remove
+.Fa var
+from the list or to call
+.Nm free
+on
+.Fa var
+in the loop body.
+.Pp
+The macro
 .Nm SLIST_INIT
 initializes the list referenced by
 .Fa head .
@@ -381,12 +407,16 @@ free(n3);
 					/* Forward traversal. */
 SLIST_FOREACH(np, &head, entries)
 	np-> ...
-
-while (!SLIST_EMPTY(&head)) {		/* List Deletion. */
+					/* List Deletion. */
+while (!SLIST_EMPTY(&head)) {
 	n1 = SLIST_FIRST(&head);
 	SLIST_REMOVE_HEAD(&head, entries);
 	free(n1);
 }
+					/* Faster List Deletion. */
+SLIST_FOREACH_REMOVE(n1, n2, &head, entries)
+	free(n1);
+SLIST_INIT(&head);
 .Ed
 .Sh SINGLY-LINKED TAIL QUEUES
 A singly-linked tail queue is headed by a structure defined by the
@@ -451,6 +481,24 @@ in turn to
 .Fa var .
 .Pp
 The macro
+.Nm STAILQ_FOREACH_REMOVE
+traverses the tail queue referenced by
+.Fa head
+in the forward direction, assigning each element
+in turn to
+.Fa var .
+Unlike
+.Nm STAILQ_FOREACH ,
+.Fa var
+is never dereferenced after the body of the loop, making it legal to remove
+.Fa var
+from the tail queue or to call
+.Nm free
+on
+.Fa var
+in the loop body.
+.Pp
+The macro
 .Nm STAILQ_INIT
 initializes the tail queue referenced by
 .Fa head .
@@ -542,6 +590,10 @@ while (n1 != NULL) {
 	n1 = n2;
 }
 STAILQ_INIT(&head);
+					/* Easier Faster List Deletion. */
+STAILQ_FOREACH_REMOVE(n1, n2, &head, entries)
+	free(n1);
+STAILQ_INIT(&head);
 .Ed
 .Sh LISTS
 A list is headed by a structure defined by the
@@ -603,6 +655,23 @@ in the forward direction, assigning each
 .Fa var .
 .Pp
 The macro
+.Nm LIST_FOREACH_REMOVE
+traverses the list referenced by
+.Fa head
+in the forward direction, assigning each element in turn to
+.Fa var .
+Unlike
+.Nm LIST_FOREACH ,
+.Fa var
+is never dereferenced after the body of the loop, making it legal to remove
+.Fa var
+from the list or to call
+.Nm free
+on
+.Fa var
+in the loop body.
+.Pp
+The macro
 .Nm LIST_INIT
 initializes the list referenced by
 .Fa head .
@@ -663,19 +732,22 @@ free(n2);
 					/* Forward traversal. */
 LIST_FOREACH(np, &head, entries)
 	np-> ...
-
-while (!LIST_EMPTY(&head)) {		/* List Deletion. */
+					/* List Deletion. */
+while (!LIST_EMPTY(&head)) {
 	n1 = LIST_FIRST(&head);
 	LIST_REMOVE(n1, entries);
 	free(n1);
 }
-
-n1 = LIST_FIRST(&head);			/* Faster List Deletion. */
+					/* Faster List Deletion. */
+n1 = LIST_FIRST(&head);
 while (n1 != NULL) {
 	n2 = LIST_NEXT(n1, entries);
 	free(n1);
 	n1 = n2;
 }
+					/* Easier Faster List Deletion. */
+LIST_FOREACH_REMOVE(n1, n2, &head, entries)
+	free(n1);
 LIST_INIT(&head);
 .Ed
 .Sh TAIL QUEUES
@@ -744,6 +816,23 @@ is set to
 if the loop completes normally, or if there were no elements.
 .Pp
 The macro
+.Nm TAILQ_FOREACH_REMOVE
+traverses the tail queue referenced by
+.Fa head
+in the forward direction, assigning each element in turn to
+.Fa var .
+Unlike
+.Nm TAILQ_FOREACH ,
+.Fa var
+is never dereferenced after the body of the loop, making it legal to remove
+.Fa var
+from the tail queue or to call
+.Nm free
+on
+.Fa var
+in the loop body.
+.Pp
+The macro
 .Nm TAILQ_FOREACH_REVERSE
 traverses the tail queue referenced by
 .Fa head
@@ -847,9 +936,17 @@ while (n1 != NULL) {
 	n1 = n2;
 }
 TAILQ_INIT(&head);
+					/* Easier Faster TailQ Deletion. */
+TAILQ_FOREACH_REMOVE(n1, n2, &head, entries)
+	free(n1);
+TAILQ_INIT(&head);
 .Ed
 .Sh HISTORY
 The
 .Nm queue
 functions first appeared in
 .Bx 4.4 .
+.Pp
+Isilon Systems, Inc. added the
+.Nm *_FOREACH_REVERSE
+macros.
Index: sys/sys/queue.h
===================================================================
RCS file: /usr/local/ncvs/atera/src/sys/sys/queue.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -p -r1.1 -r1.2
--- sys/sys/queue.h	9 Mar 2002 02:34:55 -0000	1.1
+++ sys/sys/queue.h	10 Mar 2002 04:16:09 -0000	1.2
@@ -92,6 +92,7 @@
  * _PREV		-	-	-	+
  * _LAST		-	-	+	+
  * _FOREACH		+	+	+	+
+ * _FOREACH_REMOVE	+	+	+	+
  * _FOREACH_REVERSE	-	-	-	+
  * _INSERT_HEAD		+	+	+	+
  * _INSERT_BEFORE	-	+	-	+
@@ -130,6 +131,11 @@ struct {								\
 	    (var);							\
 	    (var) = SLIST_NEXT((var), field))
 
+#define	SLIST_FOREACH_REMOVE(var, tmpvar, head, field)			\
+	for ((var) = SLIST_FIRST((head));				\
+	    (var) && ((tmpvar) = SLIST_NEXT((var), field), 1);		\
+	    (var) = (tmpvar))
+
 #define	SLIST_INIT(head) do {						\
 	SLIST_FIRST((head)) = NULL;					\
 } while (0)
@@ -192,6 +198,11 @@ struct {								\
 	   (var);							\
 	   (var) = STAILQ_NEXT((var), field))
 
+#define	STAILQ_FOREACH_REMOVE(var, tmpvar, head, field)			\
+	for ((var) = STAILQ_FIRST((head));				\
+	    (var) && ((tmpvar) = STAILQ_NEXT((var), field), 1);		\
+	    (var) = (tmpvar))
+
 #define	STAILQ_INIT(head) do {						\
 	STAILQ_FIRST((head)) = NULL;					\
 	(head)->stqh_last = &STAILQ_FIRST((head));			\
@@ -278,6 +289,11 @@ struct {								\
 	    (var);							\
 	    (var) = LIST_NEXT((var), field))
 
+#define	LIST_FOREACH_REMOVE(var, tmpvar, head, field)			\
+	for ((var) = LIST_FIRST((head));				\
+	    (var) && ((tmpvar) = LIST_NEXT((var), field), 1);		\
+	    (var) = (tmpvar))
+
 #define	LIST_INIT(head) do {						\
 	LIST_FIRST((head)) = NULL;					\
 } while (0)
@@ -342,6 +358,11 @@ struct {								\
 	for ((var) = TAILQ_FIRST((head));				\
 	    (var);							\
 	    (var) = TAILQ_NEXT((var), field))
+
+#define	TAILQ_FOREACH_REMOVE(var, tmpvar, head, field)			\
+	for ((var) = TAILQ_FIRST((head));				\
+	    (var) && ((tmpvar) = TAILQ_NEXT((var), field), 1);		\
+	    (var) = (tmpvar))
 
 #define	TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
 	for ((var) = TAILQ_LAST((head), headname);			\

--BOKacYhQ+x31HxR3--

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020703134624.B95118>