Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 01 May 2013 14:40:53 +1000
From:      Lawrence Stewart <lstewart@freebsd.org>
To:        Alfred Perlstein <bright@mu.org>
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: Adding a FOREACH_CONTINUE() variant to queue(3)
Message-ID:  <51809CD5.1040509@freebsd.org>
In-Reply-To: <518095C0.30605@mu.org>
References:  <518092BF.9070105@freebsd.org> <518095C0.30605@mu.org>

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

On 05/01/13 14:10, Alfred Perlstein wrote:
> On 4/30/13 8:57 PM, Lawrence Stewart wrote:
>> [reposting from freebsd-arch@ - was probably the wrong list]
>>
>> Hi all,
>>
>> I've had use for these a few times now when wanting to restart a loop at
>> a previously found element, and wonder if there are any thoughts about
>> sticking them (and equivalents for other list types) in <sys/queue.h>?
>>
>> Cheers,
>> Lawrence
>>
>> #define TAILQ_FOREACH_CONTINUE(var, head, field)        \
>>     for ((var) = ((var) ? (var) : TAILQ_FIRST((head)));    \
>>     (var);                            \
>>     (var) = TAILQ_NEXT((var), field))
>>
>>
>> #define SLIST_FOREACH_CONTINUE(var, head, field)        \
>>     for ((var) = ((var) ? (var) : SLIST_FIRST((head)));    \
>>     (var);                            \
>>     (var) = SLIST_NEXT((var), field))
> 
> Can you show a few uses please?  If it can significantly cut down on
> extra code it seems wise.

Sure.

Here is an excerpt from the MPTCP patch at [1] related to TCP reassembly
(more uses are in the patch if you search for FOREACH_CONTINUE):

+ /*
+  * Search from segment just inserted towards end of list looking
+  * for a hole.
+  */
+ q = te;
+ TAILQ_FOREACH_CONTINUE(q, tp->t_segq, tqe_q) {
+ 	nq = TAILQ_NEXT(q, tqe_q);
+ 	if (nq != NULL &&
+ 	    q->tqe_th->th_seq + q->tqe_len != nq->tqe_th->th_seq) {
+ 		/* Found the first out of sequence segment in the reass list. */
+ 		tp->t_segq->disordered = nq;
+ 		break;
+ 	}
+ }
+ if (q == NULL)
+ 	tp->t_segq->disordered = NULL;


Here is an excerpt from some unreleased code I'm working on that writes
a full sysctl MIB path (e.g. "a.b.c.d") into a string buffer "name",
progressing through the sysctl tree one MIB path at a time each time the
function is called (oid is initialised to be the point in the sysctl
tree from the last time the function was called):

+ again:
+ 	/* Depth first traversal of tree. */
+ 	SLIST_FOREACH_CONTINUE(oid, lsp, oid_link) {
+ 		if (layer == 0 && strcmp(oid->oid_name, "sysctl") == 0)
+ 			continue;
+
+ 		namelen = strlcat(name, oid->oid_name, remain);
+ 		remain -= namelen;
+ 		layer_state[layer].layer = lsp;
+ 		layer_state[layer].branch = oid;
+
+ 		if (((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) &&
+ 		    !SLIST_EMPTY(SYSCTL_CHILDREN(oid))) {
+			layer++;
+ 			lsp = SYSCTL_CHILDREN(oid);
+ 			oid = NULL;
+ 			*(name + namelen) = '.';
+ 			namelen++;
+ 			*(name + namelen) = '\0';
+ 			remain -= 1;
+ 			goto again;
+ 		} else {
+ 			/* Leaf node. */
+ 			return (namelen);
+ 		}
+ 	}


Cheers,
Lawrence

[1]
http://caia.swin.edu.au/urp/newtcp/mptcp/tools/mptcp_v0.3_10.x.248226.patch



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