[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lwip-users] Re: [lwip] Major critical region issues in pbuf.c
From: |
David Haas |
Subject: |
[lwip-users] Re: [lwip] Major critical region issues in pbuf.c |
Date: |
Thu, 09 Jan 2003 01:56:41 -0000 |
This is a multi-part message in MIME format.
------=_NextPart_000_00B0_01C29D3D.34FDA840
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Kieran,
I have given this quite a bit a thought and stared at the code for a while.
My conclusion is that I have an embedded system here where using an ISR
which essentially just takes a pointer to a buffer off the DMA ring and
upcalls tcpip_input to queue the buffer. This is totally suitable for an ISR
and is a good implementation for an embedded system. I have even tried using
a flood ping of large and small packets and things are working pretty well
(with my UI slow, but still responsive) on a Fast Ethernet.
I have implemented this using a conditional compile and have had to make
changes in both pbuf.c and memp.c. In the case of pbuf.c I have added
protection in some areas where it did not exist and removed the "light"
locks which were there before. I actually feel that those light locks could
cause problems. Sometimes, even though you would think the stastical chances
are slim, software runs in a cycle where every time a thread wants memory it
gets hit by one of those locks and does'nt get it. You could end up with a
lot of dropped frames, even though you're data rate is low.
Of course, I would like this to be ported back into lwip and I attach
several files which hopefully you will find useful. If you don't want to
port it back as-is, maybe you will see what I am trying to do and this might
give you some other ideas.
I also have a driver for the MCF5272 fec (Coldfire on-board fast ethernet
controller) which has been at least somewhat checked out. If you are
interested in this, I can provide this as well, but I am not in a position
to host it myself as some other people have done with their ports.
Thanks,
David.
----- Original Message -----
From: "Kieran Mansley" <address@hidden>
To: <address@hidden>
Sent: Wednesday, December 04, 2002 4:40 PM
Subject: Re: [lwip] Major critical region issues in pbuf.c
> Hi David,
>
> Related issues to this have been brought up before and the
> discussion should still be in the archives I think. See (for example)
>
> http://www.sics.se/mailing-lists/lwip.html/msg00717.html
>
> (and the rest of the thread).
>
> If I remember rightly Adam concluded by pointing out that as these are
> high frequency operations adding proper locks around them would be a
> massive overhead. They are also only called from within the core of the
> stack itself, and this is not designed (in the normal case) to be
> multi-threaded anyway. As it happens, there are a few problems with the
> pbuf code, and it is on my list of things to take a look at. I've also
> added a lightweight lock to sys_arch, so I might try seeing if this helps
> out in this case.
>
> Does anyone else have any particular thoughts on this?
>
> Kieran
>
> [This message was sent through the lwip discussion list.]
------=_NextPart_000_00B0_01C29D3D.34FDA840
Content-Type: application/octet-stream;
name="pbuf.c"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="pbuf.c"
/*
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
* All rights reserved.=20
*=20
* Redistribution and use in source and binary forms, with or without =
modification,=20
* 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. The name of the author may not be used to endorse or promote =
products
* derived from this software without specific prior written =
permission.=20
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR =
IMPLIED=20
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF=20
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. =
IN NO EVENT=20
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, =
SPECIAL,=20
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, =
PROCUREMENT=20
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR =
BUSINESS=20
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER =
IN=20
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR =
OTHERWISE) ARISING=20
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE =
POSSIBILITY=20
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*=20
* Author: Adam Dunkels <address@hidden>
*
*/
/*-----------------------------------------------------------------------=
------------*/
/* pbuf.c
*
* Functions for the manipulation of pbufs. The pbufs holds all packets =
in the
* system.
*
*/
/*-----------------------------------------------------------------------=
------------*/
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "arch/perf.h"
static u8_t pbuf_pool_memory[(PBUF_POOL_SIZE * =
MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE + sizeof(struct pbuf)))];
#ifndef SYS_ISR_PROT
static volatile u8_t pbuf_pool_free_lock, pbuf_pool_alloc_lock;
static sys_sem_t pbuf_pool_free_sem;
#endif
static struct pbuf *pbuf_pool =3D NULL;
static struct pbuf *pbuf_pool_alloc_cache =3D NULL;
static struct pbuf *pbuf_pool_free_cache =3D NULL;
/*-----------------------------------------------------------------------=
------------*/
/* pbuf_init():
*
* Initializes the pbuf module. A large part of memory is allocated
* for holding the pool of pbufs. The size of the individual pbufs in
* the pool is given by the size parameter, and the number of pbufs in
* the pool by the num parameter.
*
* After the memory has been allocated, the pbufs are set up. The
* ->next pointer in each pbuf is set up to point to the next pbuf in
* the pool.
*/
/*-----------------------------------------------------------------------=
------------*/
void
pbuf_init(void)
{
struct pbuf *p, *q =3D 0;
u16_t i;
pbuf_pool =3D (struct pbuf *)&pbuf_pool_memory[0];
ASSERT("pbuf_init: pool aligned", (long)pbuf_pool % MEM_ALIGNMENT =
=3D=3D 0);
=20
#ifdef PBUF_STATS
lwip_stats.pbuf.avail =3D PBUF_POOL_SIZE;
#endif /* PBUF_STATS */
=20
/* Set up ->next pointers to link the pbufs of the pool together. */
p =3D pbuf_pool;
=20
for(i =3D 0; i < PBUF_POOL_SIZE; ++i) {
p->next =3D (struct pbuf *)((u8_t *)p + PBUF_POOL_BUFSIZE + =
sizeof(struct pbuf));
p->len =3D p->tot_len =3D PBUF_POOL_BUFSIZE;
p->payload =3D MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf)));
q =3D p;
p =3D p->next;
}
=20
/* The ->next pointer of last pbuf is NULL to indicate that there
are no more pbufs in the pool. */
q->next =3D NULL;
#ifndef SYS_ISR_PROT =20
pbuf_pool_alloc_lock =3D 0;
pbuf_pool_free_lock =3D 0;
pbuf_pool_free_sem =3D sys_sem_new(1);
#endif =20
}
/*-----------------------------------------------------------------------=
------------*/
/* The following two functions are only called from pbuf_alloc(). */
/*-----------------------------------------------------------------------=
------------*/
static struct pbuf *
pbuf_pool_alloc(void)
{
struct pbuf *p =3D NULL;
#ifdef SYS_ISR_PROT
u32_t old_level;
old_level =3D sys_disable_interrupts();
#endif /* SYS_ISR_PROT */
=20
/* First, see if there are pbufs in the cache. */
if(pbuf_pool_alloc_cache) {
p =3D pbuf_pool_alloc_cache;
if(p) {
pbuf_pool_alloc_cache =3D p->next;=20
}
} else {
#ifndef SYS_ISR_PROT =20
/* Next, check the actual pbuf pool, but if the pool is locked, we
pretend to be out of buffers and return NULL. */
if(pbuf_pool_free_lock) {
#ifdef PBUF_STATS
++lwip_stats.pbuf.alloc_locked;
#endif /* PBUF_STATS */
return NULL;
}
pbuf_pool_alloc_lock =3D 1;
if(!pbuf_pool_free_lock) {
#endif /* SYS_ISR_PROT */ =20
p =3D pbuf_pool;
if(p) {
pbuf_pool =3D p->next;=20
}
#ifndef SYS_ISR_PROT =20
#ifdef PBUF_STATS
} else {
++lwip_stats.pbuf.alloc_locked;
#endif /* PBUF_STATS */
}
pbuf_pool_alloc_lock =3D 0;
#endif /* SYS_ISR_PROT */ =20
}
#ifdef SYS_ISR_PROT
sys_restore_interrupts(old_level);
#endif /* SYS_ISR_PROT */ =20
=20
#ifdef PBUF_STATS
if(p !=3D NULL) { =20
++lwip_stats.pbuf.used;
if(lwip_stats.pbuf.used > lwip_stats.pbuf.max) {
lwip_stats.pbuf.max =3D lwip_stats.pbuf.used;
}
}
#endif /* PBUF_STATS */
return p; =20
}
/*-----------------------------------------------------------------------=
------------*/
static void
pbuf_pool_free(struct pbuf *p)
{
struct pbuf *q;
#ifdef SYS_ISR_PROT
u32_t old_level;
#endif /* SYS_ISR_PROT */
=20
#ifdef PBUF_STATS
for(q =3D p; q !=3D NULL; q =3D q->next) {
--lwip_stats.pbuf.used;
}
#endif /* PBUF_STATS */
#ifdef SYS_ISR_PROT
old_level =3D sys_disable_interrupts();
#endif /* SYS_ISR_PROT */ =20
if(pbuf_pool_alloc_cache =3D=3D NULL) {
pbuf_pool_alloc_cache =3D p;
} else { =20
for(q =3D pbuf_pool_alloc_cache; q->next !=3D NULL; q =3D q->next);
q->next =3D p; =20
}
#ifdef SYS_ISR_PROT
sys_restore_interrupts(old_level);
#endif /* SYS_ISR_PROT */ =20
}
/*-----------------------------------------------------------------------=
------------*/
/* pbuf_alloc():
*
* Allocates a pbuf at protocol layer l. The actual memory allocated
* for the pbuf is determined by the layer at which the pbuf is
* allocated and the requested size (from the size parameter). The
* flag parameter decides how and where the pbuf should be allocated
* as follows:
*=20
* * PBUF_RAM: buffer memory for pbuf is allocated as one large
* chunk. This includes protocol headers as well.=20
* * PBUF_ROM: no buffer memory is allocated for the pbuf, even for
* protocol headers. Additional headers must be prepended
* by allocating another pbuf and chain in to the front of
* the ROM pbuf. =20
* * PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from
* the pbuf pool that is allocated during pbuf_init().
*/
/*-----------------------------------------------------------------------=
------------*/
struct pbuf *
pbuf_alloc(pbuf_layer l, u16_t size, pbuf_flag flag)
{
struct pbuf *p, *q, *r;
u16_t offset;
s32_t rsize;
offset =3D 0;
switch(l) {
case PBUF_TRANSPORT:
offset +=3D PBUF_TRANSPORT_HLEN;
/* FALLTHROUGH */
case PBUF_IP:
offset +=3D PBUF_IP_HLEN;
/* FALLTHROUGH */
case PBUF_LINK:
offset +=3D PBUF_LINK_HLEN;
break;
case PBUF_RAW:
break;
default:
ASSERT("pbuf_alloc: bad pbuf layer", 0);
return NULL;
}
switch(flag) {
case PBUF_POOL:
/* Allocate head of pbuf chain into p. */
p =3D pbuf_pool_alloc();
if(p =3D=3D NULL) {
#ifdef PBUF_STATS
++lwip_stats.pbuf.err;
#endif /* PBUF_STATS */
return NULL;
}
p->next =3D NULL;
=20
/* Set the payload pointer so that it points offset bytes into
pbuf data memory. */
p->payload =3D MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + =
offset)));
/* The total length of the pbuf is the requested size. */
p->tot_len =3D size;
/* Set the length of the first pbuf is the chain. */
p->len =3D size > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - =
offset: size;
p->flags =3D PBUF_FLAG_POOL;
=20
/* Allocate the tail of the pbuf chain. */
r =3D p;
rsize =3D size - p->len;
while(rsize > 0) { =20
q =3D pbuf_pool_alloc();
if(q =3D=3D NULL) {
DEBUGF(PBUF_DEBUG, ("pbuf_alloc: Out of pbufs in pool,\n"));
#ifdef PBUF_STATS
++lwip_stats.pbuf.err;
#endif /* PBUF_STATS */
pbuf_pool_free(p);
return NULL;
}
q->next =3D NULL;
r->next =3D q;
q->len =3D rsize > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rsize;
q->flags =3D PBUF_FLAG_POOL;
q->payload =3D (void *)((u8_t *)q + sizeof(struct pbuf));
r =3D q;
q->ref =3D 1;
//q =3D q->next; DJH: Appears to be an unnecessary =
statement
rsize -=3D PBUF_POOL_BUFSIZE;
}
r->next =3D NULL;
ASSERT("pbuf_alloc: pbuf->payload properly aligned",
((u32_t)p->payload % MEM_ALIGNMENT) =3D=3D 0);
break;
case PBUF_RAM:
/* If pbuf is to be allocated in RAM, allocate memory for it. */
p =3D mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + size + =
offset));
if(p =3D=3D NULL) {
return NULL;
}
/* Set up internal structure of the pbuf. */
p->payload =3D MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf) + =
offset));
p->len =3D p->tot_len =3D size;
p->next =3D NULL;
p->flags =3D PBUF_FLAG_RAM;
ASSERT("pbuf_alloc: pbuf->payload properly aligned",
((u32_t)p->payload % MEM_ALIGNMENT) =3D=3D 0);
break;
case PBUF_ROM:
/* If the pbuf should point to ROM, we only need to allocate
memory for the pbuf structure. */
p =3D memp_mallocp(MEMP_PBUF);
if(p =3D=3D NULL) {
return NULL;
}
p->payload =3D NULL;
p->len =3D p->tot_len =3D size;
p->next =3D NULL;
p->flags =3D PBUF_FLAG_ROM;
break;
default:
ASSERT("pbuf_alloc: erroneous flag", 0);
return NULL;
}
p->ref =3D 1;
return p;
}
/*-----------------------------------------------------------------------=
------------*/
/* pbuf_refresh():
*
* Moves free buffers from the pbuf_pool_free_cache to the pbuf_pool
* list (if possible).
*
*/
/*-----------------------------------------------------------------------=
------------*/
void
pbuf_refresh(void)
{
struct pbuf *p;
#ifdef SYS_ISR_PROT
u32_t old_level;
old_level =3D sys_disable_interrupts();
#else /* SYS_ISR_PROT */ =20
sys_sem_wait(pbuf_pool_free_sem);
#endif /* else SYS_ISR_PROT */
=20
if(pbuf_pool_free_cache !=3D NULL) {
#ifndef SYS_ISR_PROT =20
pbuf_pool_free_lock =3D 1;
if(!pbuf_pool_alloc_lock) {
#endif /* SYS_ISR_PROT */
if(pbuf_pool =3D=3D NULL) {
pbuf_pool =3D pbuf_pool_free_cache;=09
} else { =20
for(p =3D pbuf_pool; p->next !=3D NULL; p =3D p->next);
p->next =3D pbuf_pool_free_cache; =20
}
pbuf_pool_free_cache =3D NULL;
#ifndef SYS_ISR_PROT =20
#ifdef PBUF_STATS
} else {
++lwip_stats.pbuf.refresh_locked;
#endif /* PBUF_STATS */
}
=20
pbuf_pool_free_lock =3D 0;
#endif /* SYS_ISR_PROT */ =20
}
#ifdef SYS_ISR_PROT
sys_restore_interrupts(old_level);
#else /* SYS_ISR_PROT */
sys_sem_signal(pbuf_pool_free_sem);
#endif /* SYS_ISR_PROT */ =20
}
#define PBUF_POOL_FAST_FREE(p) do { =
\
p->next =3D pbuf_pool_free_cache; =
\
pbuf_pool_free_cache =3D p; =
\
} while (0)
#ifdef SYS_ISR_PROT
#define PBUF_POOL_FREE(p) do { =
\
u32_t old_level =3D =
sys_disable_interrupts(); \
PBUF_POOL_FAST_FREE(p); =
\
sys_restore_interrupts(old_level); =
\
} while(0)
#else /* SYS_ISR_PROT */
#define PBUF_POOL_FREE(p) do { =
\
sys_sem_wait(pbuf_pool_free_sem); =
\
PBUF_POOL_FAST_FREE(p); =
\
sys_sem_signal(pbuf_pool_free_sem); =
\
} while(0)
#endif /* SYS_ISR_PROT */
/*-----------------------------------------------------------------------=
------------*/
/* pbuf_realloc:
*
* Reallocates the memory for a pbuf. If the pbuf is in ROM, this as
* simple as to adjust the ->tot_len and ->len fields. If the pbuf is
* a pbuf chain, as it might be with both pbufs in dynamically
* allocated RAM and for pbufs from the pbuf pool, we have to step
* through the chain until we find the new endpoint in the pbuf chain.
* Then the pbuf that is right on the endpoint is resized and any
* further pbufs on the chain are deallocated.
*/
/*-----------------------------------------------------------------------=
------------*/
void
pbuf_realloc(struct pbuf *p, u16_t size)
{
struct pbuf *q, *r;
u16_t rsize;
ASSERT("pbuf_realloc: sane p->flags", p->flags =3D=3D PBUF_FLAG_POOL =
||
p->flags =3D=3D PBUF_FLAG_ROM ||
p->flags =3D=3D PBUF_FLAG_RAM);
=20
if(p->tot_len <=3D size) {
return;
}
=20
switch(p->flags) {
case PBUF_FLAG_POOL:
/* First, step over any pbufs that should still be in the chain. */
rsize =3D size;
q =3D p; =20
while(rsize > q->len) {
rsize -=3D q->len; =20
q =3D q->next;
}
/* Adjust the length of the pbuf that will be halved. */
q->len =3D rsize;
/* And deallocate any left over pbufs. */
r =3D q->next;
q->next =3D NULL;
q =3D r;
while(q !=3D NULL) {
r =3D q->next;
PBUF_POOL_FREE(q);
#ifdef PBUF_STATS
--lwip_stats.pbuf.used;
#endif /* PBUF_STATS */
q =3D r;
}
break;
case PBUF_FLAG_ROM: =20
p->len =3D size;
break;
case PBUF_FLAG_RAM:
/* First, step over the pbufs that should still be in the chain. */
rsize =3D size;
q =3D p;
while(rsize > q->len) {
rsize -=3D q->len;
q =3D q->next;
}
if(q->flags =3D=3D PBUF_FLAG_RAM) {
/* Reallocate and adjust the length of the pbuf that will be halved. =
*/
mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rsize);
}
=20
q->len =3D rsize;
=20
/* And deallocate any left over pbufs. */
r =3D q->next;
q->next =3D NULL;
q =3D r;
while(q !=3D NULL) {
r =3D q->next;
pbuf_free(q);
q =3D r;
}
break;
}
p->tot_len =3D size;
pbuf_refresh();
}
/*-----------------------------------------------------------------------=
------------*/
/* pbuf_header():
*
* Adjusts the ->payload pointer so that space for a header appears in
* the pbuf. Also, the ->tot_len and ->len fields are adjusted.
*/
/*-----------------------------------------------------------------------=
------------*/
u8_t
pbuf_header(struct pbuf *p, s16_t header_size)
{
void *payload;
if(p->flags & PBUF_FLAG_ROM) {
return 1;
}
=20
payload =3D p->payload;
p->payload =3D (u8_t *)p->payload - header_size/sizeof(u8_t);
DEBUGF(PBUF_DEBUG, ("pbuf_header: old %p new %p (%d)\n", payload, =
p->payload, header_size));
=20
if((u8_t *)p->payload < (u8_t *)p + sizeof(struct pbuf)) {
DEBUGF(PBUF_DEBUG, ("pbuf_header: failed %p %p\n",
(u8_t *)p->payload,
(u8_t *)p + sizeof(struct pbuf)));
p->payload =3D payload;
return 1;
}
p->len +=3D header_size;
p->tot_len +=3D header_size;
=20
return 0;
}
/*-----------------------------------------------------------------------=
------------*/
/* pbuf_free():
*
* Decrements the reference count and deallocates the pbuf if the
* reference count is zero. If the pbuf is a chain all pbufs in the
* chain are deallocated.
*/=20
/*-----------------------------------------------------------------------=
------------*/
u8_t
pbuf_free(struct pbuf *p)
{
struct pbuf *q;
u8_t count =3D 0;
#ifdef SYS_ISR_PROT
u32_t old_level;
#endif /* SYS_ISR_PROT */
=20
if(p =3D=3D NULL) {
return 0;
}
PERF_START;
=20
ASSERT("pbuf_free: sane flags", p->flags =3D=3D PBUF_FLAG_POOL ||
p->flags =3D=3D PBUF_FLAG_ROM ||
p->flags =3D=3D PBUF_FLAG_RAM);
=20
ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
#ifdef SYS_ISR_PROT
/* Since decrementing ref cannot be guarranteed to be a single machine =
operation
we must protect it. Also, the later test of ref must be protected.
*/
old_level =3D sys_disable_interrupts();
#endif /* SYS_ISR_PROT */ =20
/* Decrement reference count. */ =20
p->ref--;
//q =3D NULL; DJH: Unnecessary statement
/* If reference count =3D=3D 0, actually deallocate pbuf. */
if(p->ref =3D=3D 0) {
#ifdef SYS_ISR_PROT
sys_restore_interrupts(old_level);
#endif =20
=20
while(p !=3D NULL) {
/* Check if this is a pbuf from the pool. */
if(p->flags =3D=3D PBUF_FLAG_POOL) {
p->len =3D p->tot_len =3D PBUF_POOL_BUFSIZE;
p->payload =3D (void *)((u8_t *)p + sizeof(struct pbuf));
q =3D p->next;
PBUF_POOL_FREE(p);
#ifdef PBUF_STATS
--lwip_stats.pbuf.used;
#endif /* PBUF_STATS */
} else {
if(p->flags =3D=3D PBUF_FLAG_ROM) {
q =3D p->next;
memp_freep(MEMP_PBUF, p);
} else {
q =3D p->next;
mem_free(p);
}
}
=20
p =3D q;
++count;
}
pbuf_refresh();
}
#ifdef SYS_ISR_PROT
else
sys_restore_interrupts(old_level);
#endif /* SYS_ISR_PROT */ =20
PERF_STOP("pbuf_free");
=20
return count;
}
/*-----------------------------------------------------------------------=
------------*/
/* pbuf_clen():
*
* Returns the length of the pbuf chain.
*/
/*-----------------------------------------------------------------------=
------------*/
u8_t
pbuf_clen(struct pbuf *p)
{
u8_t len;
if(p =3D=3D NULL) {
return 0;
}
=20
for(len =3D 0; p !=3D NULL; p =3D p->next) {
++len;
}
return len;
}
/*-----------------------------------------------------------------------=
------------*/
/* pbuf_ref():
*
* Increments the reference count of the pbuf.
*/
/*-----------------------------------------------------------------------=
------------*/
void
pbuf_ref(struct pbuf *p)
{
#ifdef SYS_ISR_PROT
u32_t old_level;
#endif /* SYS_ISR_PROT */
=20
if(p =3D=3D NULL) {
return;
}
#ifdef SYS_ISR_PROT
old_level =3D sys_disable_interrupts();
#endif /* SYS_ISR_PROT */ =20
++(p->ref);
#ifdef SYS_ISR_PROT
sys_restore_interrupts(old_level);
#endif /* SYS_ISR_PROT */ =20
}
/*-----------------------------------------------------------------------=
-------*/
/* pbuf_ref_chain():
*
* Increments the reference count of all pbufs in a chain.
*/
void
pbuf_ref_chain(struct pbuf *p)
{
#ifdef SYS_ISR_PROT
u32_t old_level =3D sys_disable_interrupts();
#endif /* SYS_ISR_PROT */
=20
while (p !=3D NULL) {
p->ref++;
p=3Dp->next;
}
#ifdef SYS_ISR_PROT
sys_restore_interrupts(old_level);
#endif /* SYS_ISR_PROT */ =20
}
/*-----------------------------------------------------------------------=
------------*/
/* pbuf_chain():
*
* Chains the two pbufs h and t together. The ->tot_len field of the
* first pbuf (h) is adjusted.
*/
/*-----------------------------------------------------------------------=
------------*/
void
pbuf_chain(struct pbuf *h, struct pbuf *t)
{
struct pbuf *p;
if(t =3D=3D NULL) {
return;
}
for(p =3D h; p->next !=3D NULL; p =3D p->next);
p->next =3D t;
h->tot_len +=3D t->tot_len; =20
}
/*-----------------------------------------------------------------------=
------------*/
/* pbuf_dechain():
*
* Adjusts the ->tot_len field of the pbuf and returns the tail (if
* any) of the pbuf chain.
*/
/*-----------------------------------------------------------------------=
------------*/
struct pbuf *
pbuf_dechain(struct pbuf *p)
{
struct pbuf *q;
=20
q =3D p->next;
if (q !=3D NULL) {
q->tot_len =3D p->tot_len - p->len;
}
p->tot_len =3D p->len;
p->next =3D NULL;
return q;
}
/*-----------------------------------------------------------------------=
------------*/
struct pbuf *
pbuf_unref(struct pbuf *f)
{
struct pbuf *p, *q;
DEBUGF(PBUF_DEBUG, ("pbuf_unref: %p \n", f));
/* first pbuf is of type PBUF_REF? */
if (f->flags =3D=3D PBUF_FLAG_REF)
{
/* allocate a pbuf (w/ payload) fully in RAM */
p =3D pbuf_alloc(PBUF_RAW, f->len, PBUF_RAM);
if (p !=3D 0)
{ =20
int i;
unsigned char *src, *dst;
/* copy pbuf struct */
p->next =3D f->next;
src =3D f->payload;
dst =3D p->payload;
i =3D 0;
/* copy payload to RAM pbuf */
while(i < p->len)
{
*dst =3D *src;
dst++;
src++;
}
f->next =3D NULL;
/* de-allocate PBUF_REF */
pbuf_free(f);
f =3D p;
DEBUGF(PBUF_DEBUG, ("pbuf_unref: succesful %p \n", f));
}
else
{
/* deallocate chain */
pbuf_free(f);
f =3D NULL;
DEBUGF(PBUF_DEBUG, ("pbuf_unref: failed\n", f));
return NULL;
}
}
/* p =3D previous pbuf =3D=3D first pbuf */
p =3D f;
/* q =3D current pbuf */
q =3D f->next;
while (q !=3D NULL)
{
q =3D q->next;
}
return f;
}
------=_NextPart_000_00B0_01C29D3D.34FDA840
Content-Type: application/octet-stream;
name="memp.c"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="memp.c"
/*
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
* All rights reserved.=20
*=20
* Redistribution and use in source and binary forms, with or without =
modification,=20
* 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. The name of the author may not be used to endorse or promote =
products
* derived from this software without specific prior written =
permission.=20
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR =
IMPLIED=20
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF=20
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. =
IN NO EVENT=20
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, =
SPECIAL,=20
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, =
PROCUREMENT=20
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR =
BUSINESS=20
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER =
IN=20
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR =
OTHERWISE) ARISING=20
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE =
POSSIBILITY=20
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*=20
* Author: Adam Dunkels <address@hidden>
*
*/
#include "lwipopts.h"
#include "lwip/memp.h"
#include "lwip/pbuf.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include "lwip/api.h"
#include "lwip/api_msg.h"
#include "lwip/tcpip.h"
#include "lwip/sys.h"
#include "lwip/stats.h"
struct memp {
struct memp *next;
};
static struct memp *memp_tab[MEMP_MAX];
static const u16_t memp_sizes[MEMP_MAX] =3D {
sizeof(struct pbuf),
sizeof(struct udp_pcb),
sizeof(struct tcp_pcb),
sizeof(struct tcp_pcb_listen),
sizeof(struct tcp_seg),
sizeof(struct netbuf),
sizeof(struct netconn),
sizeof(struct api_msg),
sizeof(struct tcpip_msg),
sizeof(struct sys_timeout)
};
static const u16_t memp_num[MEMP_MAX] =3D {
MEMP_NUM_PBUF,
MEMP_NUM_UDP_PCB,
MEMP_NUM_TCP_PCB,
MEMP_NUM_TCP_PCB_LISTEN,
MEMP_NUM_TCP_SEG,
MEMP_NUM_NETBUF,
MEMP_NUM_NETCONN,
MEMP_NUM_API_MSG,
MEMP_NUM_TCPIP_MSG,
MEMP_NUM_SYS_TIMEOUT
};
static u8_t memp_memory[(MEMP_NUM_PBUF *
MEM_ALIGN_SIZE(sizeof(struct pbuf) +
sizeof(struct memp)) +
MEMP_NUM_UDP_PCB *
MEM_ALIGN_SIZE(sizeof(struct udp_pcb) +
sizeof(struct memp)) +
MEMP_NUM_TCP_PCB *
MEM_ALIGN_SIZE(sizeof(struct tcp_pcb) +
sizeof(struct memp)) +
MEMP_NUM_TCP_PCB_LISTEN *
MEM_ALIGN_SIZE(sizeof(struct tcp_pcb_listen) +
sizeof(struct memp)) +
MEMP_NUM_TCP_SEG *
MEM_ALIGN_SIZE(sizeof(struct tcp_seg) +
sizeof(struct memp)) +
MEMP_NUM_NETBUF *
MEM_ALIGN_SIZE(sizeof(struct netbuf) +
sizeof(struct memp)) +
MEMP_NUM_NETCONN *
MEM_ALIGN_SIZE(sizeof(struct netconn) +
sizeof(struct memp)) +
MEMP_NUM_API_MSG *
MEM_ALIGN_SIZE(sizeof(struct api_msg) +
sizeof(struct memp)) +
MEMP_NUM_TCPIP_MSG *
MEM_ALIGN_SIZE(sizeof(struct tcpip_msg) +
sizeof(struct memp)) +
MEMP_NUM_SYS_TIMEOUT *
MEM_ALIGN_SIZE(sizeof(struct sys_timeout) +
sizeof(struct memp)))];
/*-----------------------------------------------------------------------=
------------*/
static sys_sem_t mutex;
/*-----------------------------------------------------------------------=
------------*/
#ifdef LWIP_DEBUG
static int
memp_sanity(void)
{
int i, c;
struct memp *m, *n;
for(i =3D 0; i < MEMP_MAX; i++) {
for(m =3D memp_tab[i]; m !=3D NULL; m =3D m->next) {
c =3D 1;
for(n =3D memp_tab[i]; n !=3D NULL; n =3D n->next) {
if(n =3D=3D m) {
--c;
}
if(c < 0) return 0; /* LW was: abort(); */
}
}
}
return 1;
}
#endif /* LWIP_DEBUG */
/*-----------------------------------------------------------------------=
------------*/
void
memp_init(void)
{
struct memp *m, *memp;
u16_t i, j;
u16_t size;
=20
#ifdef MEMP_STATS
for(i =3D 0; i < MEMP_MAX; ++i) {
lwip_stats.memp[i].used =3D lwip_stats.memp[i].max =3D
lwip_stats.memp[i].err =3D 0;
lwip_stats.memp[i].avail =3D memp_num[i];
}
#endif /* MEMP_STATS */
memp =3D (struct memp *)&memp_memory[0];
for(i =3D 0; i < MEMP_MAX; ++i) {
size =3D MEM_ALIGN_SIZE(memp_sizes[i] + sizeof(struct memp));
if(memp_num[i] > 0) {
memp_tab[i] =3D memp;
m =3D memp;
=20
for(j =3D 0; j < memp_num[i]; ++j) {
m->next =3D (struct memp *)MEM_ALIGN((u8_t *)m + size);
memp =3D m;
m =3D m->next;
}
memp->next =3D NULL;
memp =3D m;
} else {
memp_tab[i] =3D NULL;
}
}
mutex =3D sys_sem_new(1);
=20
}
/*-----------------------------------------------------------------------=
------------*/
void *
memp_malloc(memp_t type)
{
struct memp *memp;
void *mem;
=20
ASSERT("memp_malloc: type < MEMP_MAX", type < MEMP_MAX);
memp =3D memp_tab[type];
=20
if(memp !=3D NULL) { =20
memp_tab[type] =3D memp->next; =20
memp->next =3D NULL;
#ifdef MEMP_STATS
++lwip_stats.memp[type].used;
if(lwip_stats.memp[type].used > lwip_stats.memp[type].max) {
lwip_stats.memp[type].max =3D lwip_stats.memp[type].used;
}
#endif /* MEMP_STATS */
ASSERT("memp_malloc: memp properly aligned",
((u32_t)MEM_ALIGN((u8_t *)memp + sizeof(struct memp)) % =
MEM_ALIGNMENT) =3D=3D 0);
mem =3D MEM_ALIGN((u8_t *)memp + sizeof(struct memp));
/* initialize memp memory with zeroes */
bzero(mem, memp_sizes[type]);=09
return mem;
} else {
DEBUGF(MEMP_DEBUG, ("memp_malloc: out of memory in pool %d\n", =
type));
#ifdef MEMP_STATS
++lwip_stats.memp[type].err;
#endif /* MEMP_STATS */
return NULL;
}
}
/*-----------------------------------------------------------------------=
------------*/
void *
memp_mallocp(memp_t type)
{
void *mem;
#ifdef SYS_ISR_PROT
u32_t old_level =3D sys_disable_interrupts();
#else /* SYS_ISR_PROT */ =20
sys_sem_wait(mutex);
#endif /* SYS_ISR_PROT */ =20
mem =3D memp_malloc(type);
#ifdef SYS_ISR_PROT
sys_restore_interrupts(old_level);
#else /* SYS_ISR_PROT */
sys_sem_signal(mutex);
#endif /* SYS_ISR_PROT */ =20
return mem;
}
/*-----------------------------------------------------------------------=
------------*/
#if 0
void *
memp_realloc(memp_t fromtype, memp_t totype, void *mem)
{
void *rmem;
u16_t size;
=20
if(mem =3D=3D NULL) {
return NULL;
}
=20
rmem =3D memp_malloc(totype);
if(rmem !=3D NULL) {=20
size =3D memp_sizes[totype];
if(memp_sizes[fromtype] < size) {
size =3D memp_sizes[fromtype];
}
bcopy(mem, rmem, size);
memp_free(fromtype, mem);
}
return rmem;
}
#endif /* 0 */
/*-----------------------------------------------------------------------=
------------*/
void
memp_free(memp_t type, void *mem)
{
struct memp *memp;
if(mem =3D=3D NULL) {
return;
}
memp =3D (struct memp *)((u8_t *)mem - sizeof(struct memp));
#ifdef MEMP_STATS
lwip_stats.memp[type].used--;=20
#endif /* MEMP_STATS */
=20
memp->next =3D memp_tab[type];=20
memp_tab[type] =3D memp;
ASSERT("memp sanity", memp_sanity());
return;
}
/*-----------------------------------------------------------------------=
------------*/
void=20
memp_freep(memp_t type, void *mem)
{
#ifdef SYS_ISR_PROT
u32_t old_level =3D sys_disable_interrupts();
#else /* SYS_ISR_PROT */ =20
sys_sem_wait(mutex);
#endif /* SYS_ISR_PROT */ =20
memp_free(type, mem);
#ifdef SYS_ISR_PROT
sys_restore_interrupts(old_level);
#else /* SYS_ISR_PROT */
sys_sem_signal(mutex);
#endif /* SYS_ISR_PROT */ =20
}
/*-----------------------------------------------------------------------=
------------*/
------=_NextPart_000_00B0_01C29D3D.34FDA840
Content-Type: application/octet-stream;
name="lwipopts.h"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="lwipopts.h"
/*
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
* All rights reserved.=20
*
* Redistribution and use in source and binary forms, with or without=20
* modification, are permitted provided that the following conditions=20
* are met:=20
* 1. Redistributions of source code must retain the above copyright=20
* notice, this list of conditions and the following disclaimer.=20
* 2. Redistributions in binary form must reproduce the above copyright=20
* notice, this list of conditions and the following disclaimer in =
the=20
* documentation and/or other materials provided with the =
distribution.=20
* 3. Neither the name of the Institute nor the names of its =
contributors=20
* may be used to endorse or promote products derived from this =
software=20
* without specific prior written permission.=20
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' =
AND=20
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE =
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR =
PURPOSE=20
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE =
LIABLE=20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR =
CONSEQUENTIAL=20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE =
GOODS=20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) =
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, =
STRICT=20
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY =
WAY=20
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY =
OF=20
* SUCH DAMAGE.=20
*
* This file is part of the lwIP TCP/IP stack.
*=20
* Author: Adam Dunkels <address@hidden>
*
* $Id: lwipopts.h,v 1.10 2002/02/15 23:12:28 adam Exp $
*/
#ifndef __LWIPOPTS_H__
#define __LWIPOPTS_H__
/* ---------- Memory options ---------- */
/* MEM_ALIGNMENT: should be set to the alignment of the CPU for which
lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2
byte alignment -> define MEM_ALIGNMENT to 2. */
#define MEM_ALIGNMENT 4
/* MEM_SIZE: the size of the heap memory. If the application will send
a lot of data that needs to be copied, this should be set high. */
#define MEM_SIZE 65000
/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
sends a lot of data out of ROM (or other static memory), this
should be set high. */
#define MEMP_NUM_PBUF 16
/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
per active UDP "connection". */
#define MEMP_NUM_UDP_PCB 4
/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP
connections. */
#define MEMP_NUM_TCP_PCB 5
/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
connections. */
#define MEMP_NUM_TCP_PCB_LISTEN 8
/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
segments. */
#define MEMP_NUM_TCP_SEG 16
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
timeouts. */
#define MEMP_NUM_SYS_TIMEOUT 3
/* The following four are used only with the sequential API and can be
set to 0 if the application only will use the raw API. */
/* MEMP_NUM_NETBUF: the number of struct netbufs. */
#define MEMP_NUM_NETBUF 2
/* MEMP_NUM_NETCONN: the number of struct netconns. */
#define MEMP_NUM_NETCONN 4
/* MEMP_NUM_APIMSG: the number of struct api_msg, used for
communication between the TCP/IP stack and the sequential
programs. */
#define MEMP_NUM_API_MSG 8
/* MEMP_NUM_TCPIPMSG: the number of struct tcpip_msg, which is used
for sequential API communication and incoming packets. Used in
src/api/tcpip.c. */
#define MEMP_NUM_TCPIP_MSG 8
/* These two control is reclaimer functions should be compiled
in. Should always be turned on (1). */
#define MEM_RECLAIM 1
#define MEMP_RECLAIM 1
/* ---------- Pbuf options ---------- */
/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
#define PBUF_POOL_SIZE 128
/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
#define PBUF_POOL_BUFSIZE 1024
/* PBUF_LINK_HLEN: the number of bytes that should be allocated for a
link level header. */
#define PBUF_LINK_HLEN 16
/* SYS_ISR_PROT: Define this macro if pbuf functions are called from
an ISR and you need extra (and faster) critical region protection. */
#define SYS_ISR_PROT 1
/* ---------- TCP options ---------- */
#define LWIP_TCP 1
#define TCP_TTL 255
/* Controls if TCP should queue segments that arrive out of
order. Define to 0 if your device is low on memory. */
#define TCP_QUEUE_OOSEQ 1
/* TCP Maximum segment size. */
#define TCP_MSS 128
/* TCP sender buffer space (bytes). */
#define TCP_SND_BUF 256
/* TCP sender buffer space (pbufs). This must be at least =3D 2 *
TCP_SND_BUF/TCP_MSS for things to work. */
#define TCP_SND_QUEUELEN 4 * TCP_SND_BUF/TCP_MSS
/* TCP receive window. */
#define TCP_WND 1024
/* Maximum number of retransmissions of data segments. */
#define TCP_MAXRTX 12
/* Maximum number of retransmissions of SYN segments. */
#define TCP_SYNMAXRTX 4
/* ---------- ARP options ---------- */
#define ARP_TABLE_SIZE 10
#define ARP_QUEUEING 1
/* ---------- IP options ---------- */
/* Define IP_FORWARD to 1 if you wish to have the ability to forward
IP packets across network interfaces. If you are going to run lwIP
on a device with only one network interface, define this to 0. */
#define IP_FORWARD 0
/* If defined to 1, IP options are allowed (but not parsed). If
defined to 0, all packets with IP options are dropped. */
#define IP_OPTIONS 1
/* IP reassembly and segmentation.These are orthogonal even
* if they both deal with IP fragments */
#define IP_REASSEMBLY 1
#define IP_FRAG 1
/* ---------- ICMP options ---------- */
#define ICMP_TTL 255
/* ---------- DHCP options ---------- */
/* Define LWIP_DHCP to 1 if you want DHCP configuration of
interfaces. DHCP is not implemented in lwIP 0.5.1, however, so
turning this on does currently not work. */
#define LWIP_DHCP 0
/* 1 if you want to do an ARP check on the offered address
(recommended). */
#define DHCP_DOES_ARP_CHECK 1
/* ---------- UDP options ---------- */
#define LWIP_UDP 1
#define UDP_TTL 255
/* ---------- Statistics options ---------- */
#define STATS
#ifdef STATS
#define LINK_STATS
#define IP_STATS
#define ICMP_STATS
#define UDP_STATS
#define TCP_STATS
#define MEM_STATS
#define MEMP_STATS
#define PBUF_STATS
#define SYS_STATS
#endif /* STATS */
#endif /* __LWIPOPTS_H__ */
------=_NextPart_000_00B0_01C29D3D.34FDA840--
[This message was sent through the lwip discussion list.]