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 = 0; while (len > 0) { if (m == 0) { break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?