/[lwip]/lwip/src/core/pbuf.c
ViewVC logotype

Diff of /lwip/src/core/pbuf.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.27 by davidhaas, Fri Mar 28 19:45:37 2003 UTC revision 1.28 by likewise, Sun Mar 30 22:24:10 2003 UTC
# Line 2  Line 2 
2   * @file   * @file
3   * Packet buffers/chains management module   * Packet buffers/chains management module
4   */   */
5    
6  /*  /*
7   * Copyright (c) 2001-2003 Swedish Institute of Computer Science.   * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
8   * All rights reserved.   * All rights reserved.
# Line 34  Line 35 
35   *   *
36   */   */
37    
 #define NEW_PBUF_REALLOC 1 /* enabling this should fix bug #1903 */  
 #define PBUF_CHAIN_DOES_REFER 1 /** enabling this fixes bug #2968 */  
   
38  #include "lwip/opt.h"  #include "lwip/opt.h"
39    
40  #include "lwip/stats.h"  #include "lwip/stats.h"
# Line 61  static struct pbuf *pbuf_pool = NULL; Line 59  static struct pbuf *pbuf_pool = NULL;
59  static struct pbuf *pbuf_pool_alloc_cache = NULL;  static struct pbuf *pbuf_pool_alloc_cache = NULL;
60  static struct pbuf *pbuf_pool_free_cache = NULL;  static struct pbuf *pbuf_pool_free_cache = NULL;
61    
62  /*-----------------------------------------------------------------------------------*/  /**
63  /* pbuf_init():   *
64     * Initializes the pbuf module.
65   *   *
66   * Initializes the pbuf module. A large part of memory is allocated   * A large part of memory is allocated for holding the pool of pbufs.
67   * for holding the pool of pbufs. The size of the individual pbufs in   * The size of the individual pbufs in the pool is given by the size
68   * the pool is given by the size parameter, and the number of pbufs in   * parameter, and the number of pbufs in the pool by the num parameter.
  * the pool by the num parameter.  
69   *   *
70   * After the memory has been allocated, the pbufs are set up. The   * After the memory has been allocated, the pbufs are set up. The
71   * ->next pointer in each pbuf is set up to point to the next pbuf in   * ->next pointer in each pbuf is set up to point to the next pbuf in
72   * the pool.   * the pool.
73     *
74   */   */
 /*-----------------------------------------------------------------------------------*/  
75  void  void
76  pbuf_init(void)  pbuf_init(void)
77  {  {
78    struct pbuf *p, *q = 0;    struct pbuf *p, *q = NULL;
79    u16_t i;    u16_t i;
80    
81    pbuf_pool = (struct pbuf *)&pbuf_pool_memory[0];    pbuf_pool = (struct pbuf *)&pbuf_pool_memory[0];
# Line 108  pbuf_init(void) Line 106  pbuf_init(void)
106    pbuf_pool_free_sem = sys_sem_new(1);    pbuf_pool_free_sem = sys_sem_new(1);
107  #endif    #endif  
108  }  }
109  /*-----------------------------------------------------------------------------------*/  
110  /* The following two functions are only called from pbuf_alloc(). */  /**
111  /*-----------------------------------------------------------------------------------*/   * @internal only called from pbuf_alloc()
112     */
113  static struct pbuf *  static struct pbuf *
114  pbuf_pool_alloc(void)  pbuf_pool_alloc(void)
115  {  {
# Line 163  pbuf_pool_alloc(void) Line 162  pbuf_pool_alloc(void)
162    SYS_ARCH_UNPROTECT(old_level);    SYS_ARCH_UNPROTECT(old_level);
163    return p;      return p;  
164  }  }
165  /*-----------------------------------------------------------------------------------*/  
166    /**
167     * @internal only called from pbuf_alloc()
168     */
169  static void  static void
170  pbuf_pool_free(struct pbuf *p)  pbuf_pool_free(struct pbuf *p)
171  {  {
# Line 185  pbuf_pool_free(struct pbuf *p) Line 187  pbuf_pool_free(struct pbuf *p)
187    }    }
188    SYS_ARCH_UNPROTECT(old_level);    SYS_ARCH_UNPROTECT(old_level);
189  }  }
190  /*-----------------------------------------------------------------------------------*/  
191  /* pbuf_alloc():  /**
192   *   *
193   * Allocates a pbuf at protocol layer l. The actual memory allocated   * Allocates a pbuf at protocol layer l.
194   * for the pbuf is determined by the layer at which the pbuf is   * The actual memory allocated for the pbuf is determined by the
195   * allocated and the requested size (from the size parameter). The   * layer at which the pbuf is allocated and the requested size
196   * flag parameter decides how and where the pbuf should be allocated   * (from the size parameter). The flag parameter decides how and
197   * as follows:   * where the pbuf should be allocated as follows:
198   *   *
199   * * PBUF_RAM: buffer memory for pbuf is allocated as one large   * - PBUF_RAM: buffer memory for pbuf is allocated as one large
200   *             chunk. This includes protocol headers as well.   *             chunk. This includes protocol headers as well.
201   * * PBUF_ROM: no buffer memory is allocated for the pbuf, even for   * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for
202   *             protocol headers. Additional headers must be prepended   *             protocol headers. Additional headers must be prepended
203   *             by allocating another pbuf and chain in to the front of   *             by allocating another pbuf and chain in to the front of
204   *             the ROM pbuf. It is assumed that the memory used is really   *             the ROM pbuf. It is assumed that the memory used is really
205   *             similar to ROM in that it is immutable and will not be   *             similar to ROM in that it is immutable and will not be
206   *             changed. Memory which is dynamic should generally not   *             changed. Memory which is dynamic should generally not
207   *             be attached to PBUF_ROM pbufs. Use PBUF_REF instead.   *             be attached to PBUF_ROM pbufs. Use PBUF_REF instead.
208   * * PBUF_REF: no buffer memory is allocated for the pbuf, even for   * - PBUF_REF: no buffer memory is allocated for the pbuf, even for
209   *             protocol headers. It is assumed that the pbuf is only   *             protocol headers. It is assumed that the pbuf is only
210   *             being used in a single thread. If the pbuf gets queued,   *             being used in a single thread. If the pbuf gets queued,
211   *             then pbuf_take should be called to copy the buffer.   *             then pbuf_take should be called to copy the buffer.
212   * * PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from   * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from
213   *              the pbuf pool that is allocated during pbuf_init().   *              the pbuf pool that is allocated during pbuf_init().
214   */   */
 /*-----------------------------------------------------------------------------------*/  
215  struct pbuf *  struct pbuf *
216  pbuf_alloc(pbuf_layer l, u16_t size, pbuf_flag flag)  pbuf_alloc(pbuf_layer l, u16_t size, pbuf_flag flag)
217  {  {
218    struct pbuf *p, *q, *r;    struct pbuf *p, *q, *r;
219    u16_t offset;    u16_t offset;
220    s32_t rsize;    s32_t rem_len;
221    
222    /* determine header offset */    /* determine header offset */
223    offset = 0;    offset = 0;
224    switch(l) {    switch (l) {
225    case PBUF_TRANSPORT:    case PBUF_TRANSPORT:
226      offset += PBUF_TRANSPORT_HLEN;      offset += PBUF_TRANSPORT_HLEN;
227      /* FALLTHROUGH */      /* FALLTHROUGH */
# Line 237  pbuf_alloc(pbuf_layer l, u16_t size, pbu Line 238  pbuf_alloc(pbuf_layer l, u16_t size, pbu
238      return NULL;      return NULL;
239    }    }
240    
241    switch(flag) {    switch (flag) {
242    case PBUF_POOL:    case PBUF_POOL:
243      /* allocate head of pbuf chain into p */      /* allocate head of pbuf chain into p */
244      p = pbuf_pool_alloc();      p = pbuf_pool_alloc();
245      if(p == NULL) {      if (p == NULL) {
246  #ifdef PBUF_STATS  #ifdef PBUF_STATS
247        ++lwip_stats.pbuf.err;        ++lwip_stats.pbuf.err;
248  #endif /* PBUF_STATS */  #endif /* PBUF_STATS */
# Line 251  pbuf_alloc(pbuf_layer l, u16_t size, pbu Line 252  pbuf_alloc(pbuf_layer l, u16_t size, pbu
252            
253      /* make the payload pointer points offset bytes into pbuf data memory */      /* make the payload pointer points offset bytes into pbuf data memory */
254      p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset)));      p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset)));
   
255      /* the total length of the pbuf is the requested size */      /* the total length of the pbuf is the requested size */
256      p->tot_len = size;      p->tot_len = size;
   
257      /* set the length of the first pbuf is the chain */      /* set the length of the first pbuf is the chain */
258      p->len = size > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: size;      p->len = size > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: size;
   
259      p->flags = PBUF_FLAG_POOL;      p->flags = PBUF_FLAG_POOL;
260            
261      /* allocate the tail of the pbuf chain. */      /* allocate the tail of the pbuf chain. */
262      r = p;      r = p;
263      rsize = size - p->len;      rem_len = size - p->len;
264      while(rsize > 0) {            while(rem_len > 0) {      
265        q = pbuf_pool_alloc();        q = pbuf_pool_alloc();
266        if (q == NULL) {        if (q == NULL) {
267          DEBUGF(PBUF_DEBUG | 2, ("pbuf_alloc: Out of pbufs in pool.\n"));          DEBUGF(PBUF_DEBUG | 2, ("pbuf_alloc: Out of pbufs in pool.\n"));
268  #ifdef PBUF_STATS  #ifdef PBUF_STATS
269          ++lwip_stats.pbuf.err;          ++lwip_stats.pbuf.err;
270  #endif /* PBUF_STATS */  #endif /* PBUF_STATS */
271            /* bail out unsuccesfully */
272          pbuf_pool_free(p);          pbuf_pool_free(p);
273          return NULL;          return NULL;
274        }        }
275        q->next = NULL;        q->next = NULL;
276        r->next = q;        r->next = q;
277        q->len = rsize > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rsize;        q->len = rem_len > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rem_len;
278        q->flags = PBUF_FLAG_POOL;        q->flags = PBUF_FLAG_POOL;
279        q->payload = (void *)((u8_t *)q + sizeof(struct pbuf));        q->payload = (void *)((u8_t *)q + sizeof(struct pbuf));
280        r = q;        r = q;
281        q->ref = 1;        q->ref = 1;
282        rsize -= PBUF_POOL_BUFSIZE;        rem_len -= PBUF_POOL_BUFSIZE;
283      }      }
284      /* end of chain */      /* end of chain */
285      r->next = NULL;      r->next = NULL;
# Line 291  pbuf_alloc(pbuf_layer l, u16_t size, pbu Line 290  pbuf_alloc(pbuf_layer l, u16_t size, pbu
290    case PBUF_RAM:    case PBUF_RAM:
291      /* If pbuf is to be allocated in RAM, allocate memory for it. */      /* If pbuf is to be allocated in RAM, allocate memory for it. */
292      p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + size + offset));      p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + size + offset));
293      if(p == NULL) {      if (p == NULL) {
294        return NULL;        return NULL;
295      }      }
296      /* Set up internal structure of the pbuf. */      /* Set up internal structure of the pbuf. */
# Line 309  pbuf_alloc(pbuf_layer l, u16_t size, pbu Line 308  pbuf_alloc(pbuf_layer l, u16_t size, pbu
308    case PBUF_REF:    case PBUF_REF:
309      /* only allocate memory for the pbuf structure */      /* only allocate memory for the pbuf structure */
310      p = memp_mallocp(MEMP_PBUF);      p = memp_mallocp(MEMP_PBUF);
311      if(p == NULL) {      if (p == NULL) {
312        DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_REF.\n"));        DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_REF.\n"));
313        return NULL;        return NULL;
314      }      }
315            /* caller must set this field properly, afterwards */      /* caller must set this field properly, afterwards */
316      p->payload = NULL;      p->payload = NULL;
317      p->len = p->tot_len = size;      p->len = p->tot_len = size;
318      p->next = NULL;      p->next = NULL;
# Line 326  pbuf_alloc(pbuf_layer l, u16_t size, pbu Line 325  pbuf_alloc(pbuf_layer l, u16_t size, pbu
325    p->ref = 1;    p->ref = 1;
326    return p;    return p;
327  }  }
328  /*-----------------------------------------------------------------------------------*/  
329  /* pbuf_refresh():  /**
330   *   *
331   * Moves free buffers from the pbuf_pool_free_cache to the pbuf_pool   * Moves free buffers from the pbuf_pool_free_cache to the pbuf_pool
332   * list (if possible).   * list (if possible).
333   *   *
334   */   */
 /*-----------------------------------------------------------------------------------*/  
335  void  void
336  pbuf_refresh(void)  pbuf_refresh(void)
337  {  {
# Line 401  pbuf_refresh(void) Line 399  pbuf_refresh(void)
399  #endif /* SYS_LIGHTWEIGHT_PROT */  #endif /* SYS_LIGHTWEIGHT_PROT */
400    
401  /**  /**
402   * Shrink a pbuf chain to a certain size.   * Shrink a pbuf chain to a desired length.
403   *   *
404   * @param p pbuf to shrink.   * @param p pbuf to shrink.
405   * @param size new size   * @param new_len desired new length of pbuf chain
406   *   *
407   * Depending on the desired size, the first few pbufs in a chain might   * Depending on the desired length, the first few pbufs in a chain might
408   * be skipped.   * be skipped and left unchanged. The new last pbuf in the chain will be
409     * resized, and any remaining pbufs will be freed.
410     *
411   * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.   * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.
412   * If the chain   *
413   * a pbuf chain, as it might be with both pbufs in dynamically   * @bug Cannot grow the size of a pbuf (chain) (yet).
  * 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.  
  * @bug Cannot grow the size of a pbuf (chain).  
414   */   */
 /*-----------------------------------------------------------------------------------*/  
 #if NEW_PBUF_REALLOC  
415  void  void
416  pbuf_realloc(struct pbuf *p, u16_t new_len)  pbuf_realloc(struct pbuf *p, u16_t new_len)
417  {  {
# Line 431  pbuf_realloc(struct pbuf *p, u16_t new_l Line 424  pbuf_realloc(struct pbuf *p, u16_t new_l
424                p->flags == PBUF_FLAG_RAM ||                p->flags == PBUF_FLAG_RAM ||
425                p->flags == PBUF_FLAG_REF);                p->flags == PBUF_FLAG_REF);
426    
427      /* desired length larger than current length? */
428    if (new_len >= p->tot_len) {    if (new_len >= p->tot_len) {
429      /** enlarging not yet supported */      /* enlarging not yet supported */
430      return;      return;
431    }    }
432        
433    /* { the pbuf chains grows by (new_len - p->tot_len) bytes } */    /* the pbuf chain grows by (new_len - p->tot_len) bytes
434       * (which may be negative in case of shrinking) */
435    grow = new_len - p->tot_len;    grow = new_len - p->tot_len;
436        
437    /* first, step over any pbufs that should remain in the chain */    /* first, step over any pbufs that should remain in the chain */
# Line 446  pbuf_realloc(struct pbuf *p, u16_t new_l Line 441  pbuf_realloc(struct pbuf *p, u16_t new_l
441    while (rem_len > q->len) {    while (rem_len > q->len) {
442      /* decrease remaining length by pbuf length */      /* decrease remaining length by pbuf length */
443      rem_len -= q->len;      rem_len -= q->len;
444        /* decrease total length indicator */
445      q->tot_len += grow;      q->tot_len += grow;
446        /* proceed to next pbuf in chain */
447      q = q->next;      q = q->next;
448    }    }
449    /* { we have now reached the new last pbuf } */    /* we have now reached the new last pbuf (in q) */
450    /* { rem_len == desired length for pbuf q } */      /* rem_len == desired length for pbuf q */  
451    
452    /* shrink allocated memory for PBUF_RAM */    /* shrink allocated memory for PBUF_RAM */
453    /* (other types merely adjust their length fields */    /* (other types merely adjust their length fields */
454    if ((q->flags == PBUF_FLAG_RAM) && (rem_len != q->len )) {    if ((q->flags == PBUF_FLAG_RAM) && (rem_len != q->len)) {
455      /* reallocate and adjust the length of the pbuf that will be split */      /* reallocate and adjust the length of the pbuf that will be split */
456      mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);      mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);
457    }    }
458    /* adjust length fields */    /* adjust length fields for new last pbuf */
459    q->len = rem_len;    q->len = rem_len;
460    q->tot_len = q->len;    q->tot_len = q->len;
461    
462    /* deallocate any left over pbufs */    /* any remaining pbufs in chain? */
463    /* remember next pbuf in chain */    if (q->next != NULL) {
464    r = q->next;      /* free remaining pbufs in chain */
465        pbuf_free(q->next);
466      }
467    /* q is last packet in chain */    /* q is last packet in chain */
468    q->next = NULL;    q->next = NULL;
   /* first pbuf to be dealloced */  
   q = r;  
   /* any pbuf left? */  
   while(q != NULL) {  
     /* remember next pbuf in chain */  
     r = q->next;  
     /* deallocate pbuf */  
     if (q->flags == PBUF_FLAG_POOL) {  
       PBUF_POOL_FREE(q);  
     } else {  
       pbuf_free(q);  
     }  
     q = r;  
   }  
469    
470    pbuf_refresh();    pbuf_refresh();
471  }  }
 #else /* pbuf_realloc() of CVS version 1.23 */  
 void  
 pbuf_realloc(struct pbuf *p, u16_t size)  
 {  
   struct pbuf *q, *r;  
   u16_t rsize;  
   
   LWIP_ASSERT("pbuf_realloc: sane p->flags", p->flags == PBUF_FLAG_POOL ||  
               p->flags == PBUF_FLAG_ROM ||  
               p->flags == PBUF_FLAG_RAM ||  
               p->flags == PBUF_FLAG_REF);  
   
   if(p->tot_len <= size) {  
     return;  
   }  
     
   switch(p->flags) {  
   case PBUF_FLAG_POOL:  
     /* First, step over any pbufs that should still be in the chain. */  
     rsize = size;  
     q = p;    
     while(rsize > q->len) {  
       rsize -= q->len;        
       q = q->next;  
     }  
     /* Adjust the length of the pbuf that will be halved. */  
     q->len = rsize;  
   
     /* And deallocate any left over pbufs. */  
     r = q->next;  
     q->next = NULL;  
     q = r;  
     while(q != NULL) {  
       r = q->next;  
       PBUF_POOL_FREE(q);  
       q = r;  
     }  
     break;  
   case PBUF_FLAG_ROM:  
   case PBUF_FLAG_REF:  
     p->len = size;  
     break;  
   case PBUF_FLAG_RAM:  
     /* First, step over the pbufs that should still be in the chain. */  
     rsize = size;  
     q = p;  
     while(rsize > q->len) {  
       rsize -= q->len;  
       q = q->next;  
     }  
     if(q->flags == 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);  
     }  
       
     q->len = rsize;  
       
     /* And deallocate any left over pbufs. */  
     r = q->next;  
     q->next = NULL;  
     q = r;  
     while(q != NULL) {  
       r = q->next;  
       pbuf_free(q);  
       q = r;  
     }  
     break;  
   }  
   p->tot_len = size;  
   
   pbuf_refresh();  
 }  
 #endif  
472    
473  /**  /**
474   * Decreases the header size by the given amount.   * Tries to decrease the payload pointer by the given header size.
475   *   *
476   * Adjusts the ->payload pointer so that space for a header appears in   * Adjusts the ->payload pointer so that space for a header appears in
477   * the pbuf. Also, the ->tot_len and ->len fields are adjusted.   * the pbuf. Also, the ->tot_len and ->len fields are adjusted.
# Line 569  pbuf_realloc(struct pbuf *p, u16_t size) Line 481  pbuf_realloc(struct pbuf *p, u16_t size)
481   *   *
482   * @return 1 on failure, 0 on succes.   * @return 1 on failure, 0 on succes.
483   */   */
 /*-----------------------------------------------------------------------------------*/  
484  u8_t  u8_t
485  pbuf_header(struct pbuf *p, s16_t header_size)  pbuf_header(struct pbuf *p, s16_t header_size)
486  {  {
487    void *payload;    void *payload;
488    /* referencing pbufs cannot be realloc()ed */    /* referencing pbufs cannot be realloc()ed */
489      /* TODO: WHY NOT? just adjust payload, tot_len and len? */
490    if (p->flags == PBUF_FLAG_ROM ||    if (p->flags == PBUF_FLAG_ROM ||
491        p->flags == PBUF_FLAG_REF) {        p->flags == PBUF_FLAG_REF) {
492        /* failure */
493      return 1;      return 1;
494    }    }
495        
# Line 603  pbuf_header(struct pbuf *p, s16_t header Line 516  pbuf_header(struct pbuf *p, s16_t header
516  /**  /**
517   * Free a pbuf (chain) from its user, de-allocate if zero users.   * Free a pbuf (chain) from its user, de-allocate if zero users.
518   *   *
519   * For a single pbuf, decrement its reference count. If it reaches   * Decrements the pbuf reference count. If it reaches
520   * zero, de-allocate the associated memory.   * zero, the pbuf is deallocated.
521   *   *
522   * For chained pbufs, all reference counts of the pbufs in the chain   * This is repeated for each pbuf in the chain, until a non-zero
523   * are decremented. Only if the first pbuf reference count reaches   * reference count is encountered, or the end of the chain is reached.
  * zero, all pbufs are de-allocated.  
524   *   *
525   * @param pbuf pbuf (chain) to be freed from its user.   * @param pbuf pbuf (chain) to be freed from its user.
526   *   *
527   * @note The reference count should not decrease when inspecting the   * @return the number of unreferenced pbufs that were de-allocated
528   * pbuf chain from head to tail.   * from the head of the chain.
529   *   *
530   * @note Chained pbufs with different reference counts should really   * @note the reference counter of a pbuf equals the number of pointers
531   * not occur. Something that references to the first pbuf, has access   * that refer to the pbuf (or into the pbuf).
532   * to the complete chain, so all references   *
533     * @internal examples:
534     *
535     * 1->2->3 becomes ...1->3
536     * 3->3->3 becomes 2->3->3
537     * 1->1->2 becomes ....->1
538     * 2->1->1 becomes 1->1->1
539     * 1->1->1 becomes .......
540     *
541   */   */
 /*-----------------------------------------------------------------------------------*/  
542  u8_t  u8_t
543  pbuf_free(struct pbuf *p)  pbuf_free(struct pbuf *p)
544  {  {
545    struct pbuf *q;    struct pbuf *q;
546    u8_t count = 0;    u8_t count;
547    SYS_ARCH_DECL_PROTECT(old_level);    SYS_ARCH_DECL_PROTECT(old_level);
548    
549    if (p == NULL) {    if (p == NULL) {
# Line 639  pbuf_free(struct pbuf *p) Line 558  pbuf_free(struct pbuf *p)
558      p->flags == PBUF_FLAG_RAM ||      p->flags == PBUF_FLAG_RAM ||
559      p->flags == PBUF_FLAG_REF );      p->flags == PBUF_FLAG_REF );
560    
561    LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);    q = p;
562    p->ref--;    count = 0;
563      /* Since decrementing ref cannot be guaranteed to be a single machine operation
   /* Since decrementing ref cannot be guarranteed to be a single machine operation  
564     * we must protect it. Also, the later test of ref must be protected.     * we must protect it. Also, the later test of ref must be protected.
565     */     */
566    SYS_ARCH_PROTECT(old_level);    SYS_ARCH_PROTECT(old_level);
567    /* decrement individual reference count for each pbuf in chain */    /* de-allocate all consecutive pbufs from the head of the chain that
568    for (q = p->next; q != NULL; q = q->next) {     * obtain a zero reference count */
569      /* reference counts can be 0, as 2nd and further pbufs will    while (p != NULL) {
570         only be freed if the head of the chain is freed */      /* all pbufs in a chain are referenced at least once */
571      LWIP_ASSERT("pbuf_free: q->ref >= 0", q->ref >= 0);      LWIP_ASSERT("pbuf_free: q->ref > 0", q->ref > 0);
572      /* decrease reference count, but do not wrap! */      p->ref--;
573      if (q->ref > 0)      /* this pbuf is no longer referenced to? */
574        q->ref--;      if (p->ref == 0)
575    }      {
576          /* remember next pbuf in chain for next iteration */
   /* first pbuf now no longer needed? */  
   if (p->ref == 0) {  
     SYS_ARCH_UNPROTECT(old_level);  
   
     while (p != NULL) {  
       /* remember next in chain */  
577        q = p->next;        q = p->next;
578        /* this is a pbuf from the pool? */    
579          /* is this a pbuf from the pool? */
580        if (p->flags == PBUF_FLAG_POOL) {        if (p->flags == PBUF_FLAG_POOL) {
581          p->len = p->tot_len = PBUF_POOL_BUFSIZE;          p->len = p->tot_len = PBUF_POOL_BUFSIZE;
582          p->payload = (void *)((u8_t *)p + sizeof(struct pbuf));          p->payload = (void *)((u8_t *)p + sizeof(struct pbuf));
583          PBUF_POOL_FREE(p);          PBUF_POOL_FREE(p);
584        /* RAM/ROM referencing pbuf */        /* a RAM/ROM referencing pbuf */
585        } else if (p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_REF) {        } else if (p->flags == PBUF_FLAG_ROM || p->flags == PBUF_FLAG_REF) {
586          memp_freep(MEMP_PBUF, p);          memp_freep(MEMP_PBUF, p);
587        /* pbuf with data */        /* pbuf with data */
588        } else {        } else {
589          mem_free(p);          mem_free(p);
590        }        }
591        /* next in chain */        count++;
592          /* proceed to next pbuf */
593        p = q;        p = q;
594        /* Only free the next one in a chain if it's reference count is 0.      /* p->ref > 0, this pbuf is still referenced to */
595        This allows buffer chains to have multiple headers pointing to them. */      /* (so the remaining pbufs in chain as well)    */
596        if (p != NULL)      } else {
597        {        /* stop walking through chain */
598          p->ref--;        p = NULL;
         if (p->ref > 0)  
           break;  
       }  
   
       ++count;  
599      }      }
600      pbuf_refresh();    }
601    } else    SYS_ARCH_UNPROTECT(old_level);
602      SYS_ARCH_UNPROTECT(old_level);    pbuf_refresh();
603    PERF_STOP("pbuf_free");    PERF_STOP("pbuf_free");
604      /* return number of de-allocated pbufs */
605    return count;    return count;
606  }  }
607  /*-----------------------------------------------------------------------------------*/  
608  /* pbuf_clen():  /**
609     * Count number of pbufs in a chain
610   *   *
611   * Returns the length of the pbuf chain.   * @param p first pbuf of chain
612     * @return the number of pbufs in a chain
613   */   */
614  /*-----------------------------------------------------------------------------------*/  
615  u8_t  u8_t
616  pbuf_clen(struct pbuf *p)  pbuf_clen(struct pbuf *p)
617  {  {
618    u8_t len;    u8_t len;
619    
620    if(p == NULL) {    len = 0;  
621      return 0;    while (p != NULL) {
   }  
     
   for(len = 0; p != NULL; p = p->next) {  
622      ++len;      ++len;
623        p = p->next;
624    }    }
625    return len;    return len;
626  }  }
627  /*-----------------------------------------------------------------------------------*/  /**
628  /* pbuf_ref():   *
629     * Increment the reference count of the pbuf.
630     *
631     * @param p pbuf to increase reference counter of
632   *   *
  * Increments the reference count of the pbuf.  
633   */   */
 /*-----------------------------------------------------------------------------------*/  
634  void  void
635  pbuf_ref(struct pbuf *p)  pbuf_ref(struct pbuf *p)
636  {  {
637      SYS_ARCH_DECL_PROTECT(old_level);    SYS_ARCH_DECL_PROTECT(old_level);
638          /* pbuf given? */  
639    if(p == NULL) {    if(p != NULL) {
640      return;      SYS_ARCH_PROTECT(old_level);
641        ++(p->ref);
642        SYS_ARCH_UNPROTECT(old_level);
643    }    }
   
   SYS_ARCH_PROTECT(old_level);  
   ++(p->ref);  
   SYS_ARCH_UNPROTECT(old_level);  
644  }  }
645    
646  /*------------------------------------------------------------------------------*/  /**
647  /* pbuf_ref_chain():   *
648     * Increment the reference count of all pbufs in a chain.
649     *
650     * @param p first pbuf of chain
651   *   *
  * Increments the reference count of all pbufs in a chain.  
652   */   */
653  void  void
654  pbuf_ref_chain(struct pbuf *p)  pbuf_ref_chain(struct pbuf *p)
655  {  {
656      SYS_ARCH_DECL_PROTECT(old_level);    SYS_ARCH_DECL_PROTECT(old_level);
657      SYS_ARCH_PROTECT(old_level);    SYS_ARCH_PROTECT(old_level);
658            
659      while (p != NULL) {    while (p != NULL) {
660          p->ref++;      ++p->ref;
661          p=p->next;      p = p->next;
662      }    }
663      SYS_ARCH_UNPROTECT(old_level);
     SYS_ARCH_UNPROTECT(old_level);  
664  }  }
665    
666    
# Line 761  pbuf_ref_chain(struct pbuf *p) Line 670  pbuf_ref_chain(struct pbuf *p)
670   *   *
671   * The ->tot_len field of the first pbuf (h) is adjusted.   * The ->tot_len field of the first pbuf (h) is adjusted.
672   */   */
 /*-----------------------------------------------------------------------------------*/  
673  void  void
674  pbuf_chain(struct pbuf *h, struct pbuf *t)  pbuf_chain(struct pbuf *h, struct pbuf *t)
675  {  {
# Line 771  pbuf_chain(struct pbuf *h, struct pbuf * Line 679  pbuf_chain(struct pbuf *h, struct pbuf *
679    LWIP_ASSERT("t != NULL", t != NULL);    LWIP_ASSERT("t != NULL", t != NULL);
680        
681    /* proceed to last pbuf of chain */    /* proceed to last pbuf of chain */
682    for(p = h; p->next != NULL; p = p->next) {    for (p = h; p->next != NULL; p = p->next) {
683      /* add length of second chain to totals of first chain */      /* add length of second chain to totals of first chain */
684      p->tot_len += t->tot_len;      p->tot_len += t->tot_len;
685    }    }
686    /* chain */    /* chain last pbuf of h chain (p) with first of tail (t) */
687    p->next = t;    p->next = t;
 #if PBUF_CHAIN_DOES_REFER /** TODO (WORK IN PROGRESS) */  
688    /* t is now referenced to one more time */    /* t is now referenced to one more time */
689    pbuf_ref(t);    pbuf_ref(t);
690    DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: referencing %p\n", (void *) t));    DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_chain: referencing tail %p\n", (void *) t));
 #endif  
691  }  }
692    
693  /**  /**
# Line 789  pbuf_chain(struct pbuf *h, struct pbuf * Line 695  pbuf_chain(struct pbuf *h, struct pbuf *
695   *   *
696   * Makes p->tot_len field equal to p->len.   * Makes p->tot_len field equal to p->len.
697   * @param p pbuf to dechain   * @param p pbuf to dechain
698   * @return remainder (if any) of the pbuf chain.   * @return remainder of the pbuf chain, or NULL if it was de-allocated.
699   */   */
700  struct pbuf *  struct pbuf *
701  pbuf_dechain(struct pbuf *p)  pbuf_dechain(struct pbuf *p)
702  {  {
703    struct pbuf *q;    struct pbuf *q;
704        /* tail */  
705    q = p->next;    q = p->next;
706    /* pbuf has successor in chain? */    /* pbuf has successor in chain? */
707    if (q != NULL) {    if (q != NULL) {
# Line 809  pbuf_dechain(struct pbuf *p) Line 715  pbuf_dechain(struct pbuf *p)
715    p->next = NULL;    p->next = NULL;
716  #if PBUF_CHAIN_DOES_REFER /** TODO (WORK IN PROGRESS) */  #if PBUF_CHAIN_DOES_REFER /** TODO (WORK IN PROGRESS) */
717    /* q is no longer referenced by p */    /* q is no longer referenced by p */
718    pbuf_free(q);    deallocated = pbuf_free(q);
719    DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dechain: unreferencing %p\n", (void *) q));    DEBUGF(PBUF_DEBUG | DBG_FRESH | 2, ("pbuf_dechain: unreferencing %p\n", (void *) q));
720  #endif  #endif
721    return q;    /* return remaining tail or NULL if deallocated */
722      return (deallocated? NULL: q);
723  }  }
724    
725  /**  /**
# Line 823  pbuf_dechain(struct pbuf *p) Line 730  pbuf_dechain(struct pbuf *p)
730   * with PBUF_POOL (or PBUF_RAM) pbufs, each taking a copy of   * with PBUF_POOL (or PBUF_RAM) pbufs, each taking a copy of
731   * the referenced data.   * the referenced data.
732   *   *
733   * Used to queue packets on behalf of the lwIP stack, such as ARP based   * @note The pbuf you give as argument, may have been replaced
734   * queueing.   * by calling pbuf_take(p). You must therefore explicitly use
735     * p = pbuf_take(p);
736     * @note Any replaced pbufs will be freed through pbuf_free().
737     *
738     * Used to queue packets on behalf of the lwIP stack, such as
739     * ARP based queueing.
740   *   *
741   * @param f Head of pbuf chain to process   * @param f Head of pbuf chain to process
742   *   *
743   * @return Pointer to new head of pbuf chain.   * @return Pointer to new head of pbuf chain (which may have been
744     * replaced itself).
745   */   */
746  struct pbuf *  struct pbuf *
747  pbuf_take(struct pbuf *f)  pbuf_take(struct pbuf *f)
748  {  {
749    struct pbuf *p, *prev, *top;    struct pbuf *p, *prev, *top;
750    LWIP_ASSERT("pbuf_take: f != NULL", f != NULL);    LWIP_ASSERT("pbuf_take: f != NULL", f != NULL);
751    DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_take(%p)\n", (void*)f));    DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_take(%p)", (void*)f));
752    
753    prev = NULL;    prev = NULL;
754    p = f;    p = f;
# Line 848  pbuf_take(struct pbuf *f) Line 761  pbuf_take(struct pbuf *f)
761      {      {
762        /* the replacement pbuf */        /* the replacement pbuf */
763        struct pbuf *q;        struct pbuf *q;
764        q = NULL;        DEBUGF(PBUF_DEBUG | DBG_TRACE, ("pbuf_take: encountered PBUF_REF %p", (void *)p));
       DEBUGF(PBUF_DEBUG | DBG_TRACE, ("pbuf_take: encountered PBUF_REF %p\n", (void *)p));  
765        /* allocate a pbuf (w/ payload) fully in RAM */        /* allocate a pbuf (w/ payload) fully in RAM */
766        /* PBUF_POOL buffers are faster if we can use them */        /* PBUF_POOL buffers are faster if we can use them */
767        if (p->len <= PBUF_POOL_BUFSIZE) {        if (p->len <= PBUF_POOL_BUFSIZE) {
768          q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL);          q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL);
769          if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAW\n"));          if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL"));
770          } else {
771            /* no replacement pbuf yet */
772            q = NULL;
773            DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: PBUF_POOL too small to replace PBUF_REF"));
774        }        }
775        /* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */        /* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */
776        if (q == NULL) {        if (q == NULL) {
777          q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM);          q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM);
778          if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n"));          if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAM"));
779        }        }
780          /* replacement pbuf could be allocated? */
781        if (q != NULL)        if (q != NULL)
782        {          {  
783          /* copy successor */          /* copy successor */
784          q->next = p->next;          q->next = p->next;
785            /* remove linkage from original pbuf */
786            p->next = NULL;
787            /* remove linkage to original pbuf */
788          if (prev != NULL)          if (prev != NULL)
789            /* Break chain and insert new pbuf instead */            /* prev->next == p at this point */
790              /* break chain and insert new pbuf instead */
791            prev->next = q;            prev->next = q;
792              /* p is no longer pointed to by prev or by our caller,
793               * as the caller must do p = pbuf_take(p); so free it
794               * from our usage.
795               * note that we have set p->next to NULL already so that
796               * we will not free the rest of the chain by accident.
797               */
798              pbuf_free(p);
799            /* prev == NULL, so we replaced the top pbuf of the chain */
800          else          else
801            top = q;            top = q;
         p->next = NULL;  
802          /* copy pbuf payload */          /* copy pbuf payload */
803          memcpy(q->payload, p->payload, p->len);          memcpy(q->payload, p->payload, p->len);
804          q->tot_len = p->tot_len;          q->tot_len = p->tot_len;

Legend:
Removed from v.1.27  
changed lines
  Added in v.1.28

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26