lwip-users
[Top][All Lists]
Advanced

[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.]




reply via email to

[Prev in Thread] Current Thread [Next in Thread]