uipc_mbuf.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 988 行 · 第 1/2 页

C
988
字号
/* * 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 *	$Id: uipc_mbuf.c,v 1.37.2.1 1999/04/12 10:07:14 des Exp $ */#include <sys/param.h>#include <sys/systm.h>#include <sys/malloc.h>#include <sys/mbuf.h>#include <sys/kernel.h>#include <sys/sysctl.h>#include <sys/domain.h>#include <sys/protosw.h>#include <vm/vm.h>#include <vm/vm_kern.h>#include <vm/vm_extern.h>#ifdef OSKITvoid mbinit __P((void *));#elsestatic void mbinit __P((void *));#endifSYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbinit, NULL)#ifndef OSKITstruct mbuf *mbutl;char	*mclrefcnt;#endif /* !OSKIT */struct mbstat mbstat;struct mbuf *mmbfree;#ifndef OSKITunion mcluster *mclfree;#endif /* !OSKIT */int	max_linkhdr;int	max_protohdr;int	max_hdr;int	max_datalen;SYSCTL_INT(_kern_ipc, KIPC_MAX_LINKHDR, max_linkhdr, CTLFLAG_RW,	   &max_linkhdr, 0, "");SYSCTL_INT(_kern_ipc, KIPC_MAX_PROTOHDR, max_protohdr, CTLFLAG_RW,	   &max_protohdr, 0, "");SYSCTL_INT(_kern_ipc, KIPC_MAX_HDR, max_hdr, CTLFLAG_RW, &max_hdr, 0, "");SYSCTL_INT(_kern_ipc, KIPC_MAX_DATALEN, max_datalen, CTLFLAG_RW,	   &max_datalen, 0, "");SYSCTL_STRUCT(_kern_ipc, KIPC_MBSTAT, mbstat, CTLFLAG_RW, &mbstat, mbstat, "");static void	m_reclaim __P((void));/* "number of clusters of pages" */#define NCL_INIT	1#define NMB_INIT	16/* ARGSUSED*/#ifdef OSKITvoid#elsestatic void#endifmbinit(dummy)	void *dummy;{	int s;#ifdef OSKIT	mmbfree = NULL; #else	mmbfree = NULL; mclfree = NULL;#endif	mbstat.m_msize = MSIZE;#ifndef OSKIT	mbstat.m_mclbytes = MCLBYTES;	mbstat.m_minclsize = MINCLSIZE;#endif	mbstat.m_mlen = MLEN;	mbstat.m_mhlen = MHLEN;	s = splimp();	if (m_mballoc(NMB_INIT, M_DONTWAIT) == 0)		goto bad;#ifndef OSKIT#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#endif /* !OSKIT */	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;{	register caddr_t p;	register int i;	int nbytes;	/* Once we run out of map space, it will be impossible to get	 * any more (nothing is ever freed back to the map) (XXX which	 * is dumb). (however you are not dead as m_reclaim might	 * still be able to free a substantial amount of space).	 */	if (mb_map_full)		return (0);	nbytes = round_page(nmb * MSIZE);	p = (caddr_t)kmem_malloc(mb_map, nbytes, M_NOWAIT);	if (p == 0 && how == M_WAIT) {		mbstat.m_wait++;		p = (caddr_t)kmem_malloc(mb_map, nbytes, M_WAITOK);	}	/*	 * Either the map is now full, or `how' is M_NOWAIT and there	 * are no pages left.	 */	if (p == NULL)		return (0);	nmb = nbytes / MSIZE;	for (i = 0; i < nmb; i++) {		((struct mbuf *)p)->m_next = mmbfree;		mmbfree = (struct mbuf *)p;		p += MSIZE;	}	mbstat.m_mbufs += nmb;	return (1);}#ifndef OSKIT#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_KT(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;{	register caddr_t p;	register int i;	int npg;	/*	 * Once we run out of map space, it will be impossible	 * to get any more (nothing is ever freed back to the	 * map).	 */	if (mb_map_full) {		mbstat.m_drops++;		return (0);	}#if MCLBYTES > PAGE_SIZE	if (how != M_WAIT) {		i_want_my_mcl += ncl;		wakeup(&i_want_my_mcl);		mbstat.m_wait++;		p = 0;	} else {		p = contigmalloc1(MCLBYTES * ncl, M_DEVBUF, M_WAITOK, 0ul,				  ~0ul, PAGE_SIZE, 0, mb_map);	}#else	npg = ncl;	p = (caddr_t)kmem_malloc(mb_map, ctob(npg),				 how != M_WAIT ? M_NOWAIT : M_WAITOK);	ncl = ncl * PAGE_SIZE / MCLBYTES;#endif	/*	 * Either the map is now full, or `how' is M_NOWAIT and there	 * are no pages left.	 */	if (p == NULL) {		mbstat.m_drops++;		return (0);	}	for (i = 0; i < ncl; i++) {		((union mcluster *)p)->mcl_next = mclfree;		mclfree = (union mcluster *)p;		p += MCLBYTES;		mbstat.m_clfree++;	}	mbstat.m_clusters += ncl;	return (1);}#endif /* !OSKIT *//* * 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();#define m_retry(i, t)	(struct mbuf *)0	MGET(m, i, t);#undef m_retry	if (m != NULL) {		mbstat.m_wait++;	} else {		if (i == M_DONTWAIT)			mbstat.m_drops++;		else			panic("Out of mbuf clusters");	}	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();#define m_retryhdr(i, t) (struct mbuf *)0	MGETHDR(m, i, t);#undef m_retryhdr	if (m != NULL) {		mbstat.m_wait++;	} else {		if (i == M_DONTWAIT)			mbstat.m_drops++;		else			panic("Out of mbuf clusters");	}	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_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;	if (m == NULL)		return;	do {		MFREE(m, n);		m = n;	} 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. */#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 || len < 0)		panic("m_copym");	if (off == 0 && m->m_flags & M_PKTHDR)		copyhdr = 1;	while (off > 0) {		if (m == 0)			panic("m_copym");		if (off < m->m_len)			break;		off -= m->m_len;		m = m->m_next;	}	np = &top;	top = 0;	while (len > 0) {		if (m == 0) {			if (len != M_COPYALL)				panic("m_copym");			break;		}		MGET(n, wait, m->m_type);		*np = n;		if (n == 0)			goto nospace;		if (copyhdr) {			M_COPY_PKTHDR(n, m);			if (len == M_COPYALL)				n->m_pkthdr.len -= off0;			else				n->m_pkthdr.len = len;			copyhdr = 0;		}		n->m_len = min(len, m->m_len - off);		if (m->m_flags & M_EXT) {			n->m_data = m->m_data + off;#ifdef OSKIT			oskit_bufio_addref(m->m_ext.ext_bufio);#else /* !OSKIT */			if(!m->m_ext.ext_ref)				mclrefcnt[mtocl(m->m_ext.ext_buf)]++;			else				(*(m->m_ext.ext_ref))(m->m_ext.ext_buf,							m->m_ext.ext_size);#endif /* !OSKIT */

⌨️ 快捷键说明

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