uipc_mbuf.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,167 行 · 第 1/2 页

C
1,167
字号
//==========================================================================////      src/sys/kern/uipc_mbuf.c////==========================================================================//####BSDCOPYRIGHTBEGIN####//// -------------------------------------------//// Portions of this software may have been derived from OpenBSD, // FreeBSD or other sources, and are covered by the appropriate// copyright disclaimers included herein.//// Portions created by Red Hat are// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.//// -------------------------------------------////####BSDCOPYRIGHTEND####//==========================================================================/* * Copyright (c) 1982, 1986, 1988, 1991, 1993 *	The Regents of the University of California.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	@(#)uipc_mbuf.c	8.2 (Berkeley) 1/4/94 * $FreeBSD: src/sys/kern/uipc_mbuf.c,v 1.51.2.7 2001/07/30 23:28:00 peter Exp $ */#include <sys/param.h>#include <sys/malloc.h>#include <sys/mbuf.h>#include <sys/domain.h>#include <sys/protosw.h>static void mbinit __P((void *));SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbinit, NULL)struct mbuf *mbutl;char	*mclrefcnt;struct mbstat mbstat;u_long	mbtypes[MT_NTYPES];struct mbuf *mmbfree;union mcluster *mclfree;int	max_linkhdr;int	max_protohdr;int	max_hdr;int	max_datalen;u_int	m_mballoc_wid = 0;u_int	m_clalloc_wid = 0;int mbuf_wait = 32;  // Time in ticks to wait for mbufs to come freestatic void	m_reclaim __P((void));#ifndef NMBCLUSTERS#define NMBCLUSTERS	(512 + maxusers * 16)#endif#ifndef NMBUFS#define NMBUFS		(nmbclusters * 4)#endif/* "number of clusters of pages" */#define NCL_INIT	1#define NMB_INIT	16/* ARGSUSED*/static voidmbinit(dummy)	void *dummy;{	int s;	mmbfree = NULL; mclfree = NULL;	mbstat.m_msize = MSIZE;	mbstat.m_mclbytes = MCLBYTES;	mbstat.m_minclsize = MINCLSIZE;	mbstat.m_mlen = MLEN;	mbstat.m_mhlen = MHLEN;	s = splimp();	if (m_mballoc(NMB_INIT, M_DONTWAIT) == 0)		goto bad;#if MCLBYTES <= PAGE_SIZE	if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0)		goto bad;#else	/* It's OK to call contigmalloc in this context. */	if (m_clalloc(16, M_WAIT) == 0)		goto bad;#endif	splx(s);	return;bad:	panic("mbinit");}/* * Allocate at least nmb mbufs and place on mbuf free list. * Must be called at splimp. *//* ARGSUSED */intm_mballoc(nmb, how)	register int nmb;	int how;{	struct mbuf *p;	int i;	for (i = 0; i < nmb; i++) {            p = (struct mbuf *)cyg_net_mbuf_alloc( );            if (p != (struct mbuf *)0) {		((struct mbuf *)p)->m_next = mmbfree;		mmbfree = (struct mbuf *)p;                mbstat.m_mbufs++;                mbtypes[MT_FREE]++;            } else {                // Warn - out of mbufs?                return (0);            }	}	return (1);}/* * Once the mb_map has been exhausted and if the call to the allocation macros * (or, in some cases, functions) is with M_WAIT, then it is necessary to rely * solely on reclaimed mbufs. Here we wait for an mbuf to be freed for a  * designated (mbuf_wait) time.  */struct mbuf *m_mballoc_wait(int caller, int type){	struct mbuf *p;	int s;	s = splimp();	m_mballoc_wid++;	if ((tsleep(&m_mballoc_wid, PVM, "mballc", mbuf_wait)) == EWOULDBLOCK)		m_mballoc_wid--;	splx(s);	/*	 * Now that we (think) that we've got something, we will redo an	 * MGET, but avoid getting into another instance of m_mballoc_wait()	 * XXX: We retry to fetch _even_ if the sleep timed out. This is left	 *      this way, purposely, in the [unlikely] case that an mbuf was	 *      freed but the sleep was not awakened in time. 	 */	p = NULL;	switch (caller) {	case MGET_C:		MGET(p, M_DONTWAIT, type);		break;	case MGETHDR_C:		MGETHDR(p, M_DONTWAIT, type);		break;	default:		panic("m_mballoc_wait: invalid caller (%d)", caller);	}	s = splimp();	if (p != NULL) {		/* We waited and got something... */		mbstat.m_wait++;		/* Wake up another if we have more free. */		if (mmbfree != NULL)			MMBWAKEUP();	}	splx(s);	return (p);}#if MCLBYTES > PAGE_SIZEstatic int i_want_my_mcl;static voidkproc_mclalloc(void){	int status;	while (1) {		tsleep(&i_want_my_mcl, PVM, "mclalloc", 0);		for (; i_want_my_mcl; i_want_my_mcl--) {			if (m_clalloc(1, M_WAIT) == 0)				printf("m_clalloc failed even in process context!\n");		}	}}static struct proc *mclallocproc;static struct kproc_desc mclalloc_kp = {	"mclalloc",	kproc_mclalloc,	&mclallocproc};SYSINIT(mclallocproc, SI_SUB_KTHREAD_UPDATE, SI_ORDER_ANY, kproc_start,	   &mclalloc_kp);#endif/* * Allocate some number of mbuf clusters * and place on cluster free list. * Must be called at splimp. *//* ARGSUSED */intm_clalloc(ncl, how)	register int ncl;	int how;{	union mcluster *p;	int i;	for (i = 0; i < ncl; i++) {            p = (union mcluster *)cyg_net_cluster_alloc();            if (p != (union mcluster *)0) {		((union mcluster *)p)->mcl_next = mclfree;		mclfree = (union mcluster *)p;		mbstat.m_clfree++;                mbstat.m_clusters++;            } else {                // Warn - no more clusters?                return (0);            }	}	return (1);}/* * Once the mb_map submap has been exhausted and the allocation is called with * M_WAIT, we rely on the mclfree union pointers. If nothing is free, we will * sleep for a designated amount of time (mbuf_wait) or until we're woken up * due to sudden mcluster availability. */caddr_tm_clalloc_wait(void){	caddr_t p;	int s;	/* Sleep until something's available or until we expire. */	m_clalloc_wid++;	if ((tsleep(&m_clalloc_wid, PVM, "mclalc", mbuf_wait)) == EWOULDBLOCK)		m_clalloc_wid--;	/*	 * Now that we (think) that we've got something, we will redo and	 * MGET, but avoid getting into another instance of m_clalloc_wait()	 */	p = NULL;	MCLALLOC(p, M_DONTWAIT);	s = splimp();	if (p != NULL) {	/* We waited and got something... */		mbstat.m_wait++;		/* Wake up another if we have more free. */		if (mclfree != NULL)			MCLWAKEUP();	}	splx(s);	return (p);}/* * When MGET fails, ask protocols to free space when short of memory, * then re-attempt to allocate an mbuf. */struct mbuf *m_retry(i, t)	int i, t;{	register struct mbuf *m;	/*	 * Must only do the reclaim if not in an interrupt context.	 */	if (i == M_WAIT) {		m_reclaim();	}	/*	 * Both m_mballoc_wait and m_retry must be nulled because	 * when the MGET macro is run from here, we deffinately do _not_	 * want to enter an instance of m_mballoc_wait() or m_retry() (again!)	 */#undef m_retry#undef m_mballoc_wait#define m_mballoc_wait(caller,type)    (struct mbuf *)0#define m_retry(i, t)	(struct mbuf *)0	MGET(m, i, t);#undef m_retry#undef m_mballoc_wait#define m_retry cyg_m_retry#define m_retryhdr cyg_m_retryhdr#define m_mballoc_wait cyg_m_mballoc_wait	if (m != NULL)		mbstat.m_wait++;	else		mbstat.m_drops++;	return (m);}/* * As above; retry an MGETHDR. */struct mbuf *m_retryhdr(i, t)	int i, t;{	register struct mbuf *m;	/*	 * Must only do the reclaim if not in an interrupt context.	 */	if (i == M_WAIT) {		m_reclaim();	}#undef m_retryhdr#undef m_mballoc_wait#define m_mballoc_wait(caller,type)    (struct mbuf *)0#define m_retryhdr(i, t) (struct mbuf *)0	MGETHDR(m, i, t);#undef m_retryhdr#undef m_mballoc_wait#define m_retry cyg_m_retry#define m_retryhdr cyg_m_retryhdr#define m_mballoc_wait cyg_m_mballoc_wait	if (m != NULL)  		mbstat.m_wait++;	else    		mbstat.m_drops++;		return (m);}static voidm_reclaim(){	register struct domain *dp;	register struct protosw *pr;	int s = splimp();	for (dp = domains; dp; dp = dp->dom_next)		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)			if (pr->pr_drain)				(*pr->pr_drain)();	splx(s);	mbstat.m_drain++;}/* * Space allocation routines. * These are also available as macros * for critical paths. */struct mbuf *m_get(how, type)	int how, type;{	register struct mbuf *m;	MGET(m, how, type);	return (m);}struct mbuf *m_gethdr(how, type)	int how, type;{	register struct mbuf *m;	MGETHDR(m, how, type);	return (m);}struct mbuf *m_getclr(how, type)	int how, type;{	register struct mbuf *m;	MGET(m, how, type);	if (m == 0)		return (0);	bzero(mtod(m, caddr_t), MLEN);	return (m);}/* * struct mbuf * * m_getm(m, len, how, type) * * This will allocate len-worth of mbufs and/or mbuf clusters (whatever fits * best) and return a pointer to the top of the allocated chain. If m is * non-null, then we assume that it is a single mbuf or an mbuf chain to * which we want len bytes worth of mbufs and/or clusters attached, and so * if we succeed in allocating it, we will just return a pointer to m. * * If we happen to fail at any point during the allocation, we will free * up everything we have already allocated and return NULL. * */struct mbuf *m_getm(struct mbuf *m, int len, int how, int type){	struct mbuf *top, *tail, *mp, *mtail = NULL;	MGET(mp, how, type);	if (mp == NULL)		return (NULL);	else if (len > MINCLSIZE) {		MCLGET(mp, how);		if ((mp->m_flags & M_EXT) == 0) {			m_free(mp);			return (NULL);		}	}	mp->m_len = 0;	len -= M_TRAILINGSPACE(mp);	if (m != NULL)		for (mtail = m; mtail->m_next != NULL; mtail = mtail->m_next);	else		m = mp;	top = tail = mp;	while (len > 0) {		MGET(mp, how, type);		if (mp == NULL)			goto failed;		tail->m_next = mp;		tail = mp;		if (len > MINCLSIZE) {			MCLGET(mp, how);			if ((mp->m_flags & M_EXT) == 0)				goto failed;		}		mp->m_len = 0;		len -= M_TRAILINGSPACE(mp);	}	if (mtail != NULL)		mtail->m_next = top;	return (m);failed:	m_freem(top);	return (NULL);}struct mbuf *m_free(m)	struct mbuf *m;{	register struct mbuf *n;	MFREE(m, n);	return (n);}voidm_freem(m)	register struct mbuf *m;{	register struct mbuf *n;        struct mbuf *orig = m;	if (m == NULL)		return;	do {		MFREE(m, n);		m = n;                if (m == orig) {                    diag_printf("DEBUG: Circular MBUF %p!\n", orig);                    return;                }	} while (m);}/* * Mbuffer utility routines. *//* * Lesser-used path for M_PREPEND: * allocate new mbuf to prepend to chain, * copy junk along. */struct mbuf *m_prepend(m, len, how)	register struct mbuf *m;	int len, how;{	struct mbuf *mn;	MGET(mn, how, m->m_type);	if (mn == (struct mbuf *)NULL) {		m_freem(m);		return ((struct mbuf *)NULL);	}	if (m->m_flags & M_PKTHDR) {		M_COPY_PKTHDR(mn, m);		m->m_flags &= ~M_PKTHDR;	}	mn->m_next = m;	m = mn;	if (len < MHLEN)		MH_ALIGN(m, len);	m->m_len = len;	return (m);}/* * Make a copy of an mbuf chain starting "off0" bytes from the beginning, * continuing for "len" bytes.  If len is M_COPYALL, copy to end of mbuf. * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller. * Note that the copy is read-only, because clusters are not copied, * only their reference counts are incremented. */#define MCFail (mbstat.m_mcfail)struct mbuf *m_copym(m, off0, len, wait)	register struct mbuf *m;	int off0, wait;	register int len;{	register struct mbuf *n, **np;	register int off = off0;	struct mbuf *top;	int copyhdr = 0;	if (off == 0 && m->m_flags & M_PKTHDR)		copyhdr = 1;	while (off > 0) {		if (off < m->m_len)			break;		off -= m->m_len;		m = m->m_next;	}	np = &top;	top = 0;	while (len > 0) {		if (m == 0) {			break;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?