From owner-freebsd-net Mon Feb 12 6: 9:41 2001 Delivered-To: freebsd-net@freebsd.org Received: from salmon.maths.tcd.ie (salmon.maths.tcd.ie [134.226.81.11]) by hub.freebsd.org (Postfix) with SMTP id 1CF9E37B491; Mon, 12 Feb 2001 06:09:32 -0800 (PST) Received: from walton.maths.tcd.ie by salmon.maths.tcd.ie with SMTP id ; 12 Feb 2001 14:09:31 +0000 (GMT) To: Boris Popov Cc: freebsd-arch@freebsd.org, freebsd-net@freebsd.org, iedowse@maths.tcd.ie Subject: Re: CFR: Sequential mbuf read/write extensions In-Reply-To: Your message of "Fri, 09 Feb 2001 08:30:48 +0600." Date: Mon, 12 Feb 2001 14:09:30 +0000 From: Ian Dowse Message-ID: <200102121409.aa34378@salmon.maths.tcd.ie> Sender: owner-freebsd-net@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org In message , Boris Popo v writes: > No, in the current implementation mb_get* functions will work >properly. But mb_put* will fail. This can be avoided by implementing >alignment-safe set* macros (which can be written in two variants - first >form is for aligned objects and second for bad aligned ones). Ah, I missed the details of how the mb_get functions work - you just perform a byte-by-byte copy into the destination. Great! I wonder if it makes sense to do something similar for the mb_put functions too? BTW, I'd recommend making MB_PUT() a more 'normal' macro, or even calling mb_fit directly from the mb_put functions - the implicit declaration of 'p' and use of 'mbp' is confusing. If mb_fit was changed to return a void *, the code wouldn't look too bad, and would be less magic. e.g.: int mb_put_byte(struct mbdata *mbp, u_int8_t x) { u_int8_t *p; if ((p = mb_fit(mbp, sizeof(*p))) == NULL) return (ENUBUFS); *p = x; return (0); } > Hmm, since so_send() can fail and some erros can be recovered by >another call to so_send(), I'm just called m_copym() to duplicate the mbuf >chain and give it to so_send(). This is reasonable for a client of an RPC-type protocol, but the server side may wish to give the reply to the sosend function and ignore errors - NFS does this for example. It seems natural to call the _init function to clobber any state, though the semantics aren't that important. There just needs to be a defined way of disassociating the chain from the mbdata struct so that mb_done will not free it. If you are going to split struct mbdata into two structs, you can probably optimise operations a bit by storing the right information for each case. For the build case, maybe: struct mbuf *mb_top; /* head of chain */ struct mbuf *mb_cur; /* current (last) mbuf in chain */ int mb_mleft; /* bytes remaining in mb_cur */ int mb_count; /* total bytes in chain */ Storing the number of bytes remaining in the current mbuf as 'mb_mleft' avoids using M_TRAILINGSPACE() which expands to quite a complex expression. The current offset is not explicitly stored in mbdata, but evaluating 'mtod(m, char *) + m->m_len' is cheap. An optimised case at the start of mb_fit could look like m = mbp->mb_cur; if (mbp->mb_top != NULL && size <= mbp->mb_mleft) { mbp->mb_mleft -= size; mbp->mb_count += size; bpos = mtod(m, char *) + m->m_len; m->m_len += size; return (bpos); } but I guess worrying about minor optimisations like these probably isn't too important now :-) For the breakdown, you probably only need: struct mbuf *mb_top; /* head of chain */ struct mbuf *mb_cur; /* current mbuf in chain */ u_char *mb_pos; /* current position in mb_cur */ Ian To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-net" in the body of the message