/[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.25 by likewise, Wed Mar 26 13:50:03 2003 UTC revision 1.26 by likewise, Fri Mar 28 08:49:05 2003 UTC
# Line 34  Line 34 
34   *   *
35   */   */
36    
37  #define NEW_PBUF_REALLOC 1 /* should fix bug #1903 */  #define NEW_PBUF_REALLOC 1 /* enabling this should fix bug #1903 */
38    #define PBUF_CHAIN_DOES_REFER 1 /** enabling this fixes bug #2968 */
39    
40  #include "lwip/opt.h"  #include "lwip/opt.h"
41    
# Line 205  pbuf_pool_free(struct pbuf *p) Line 206  pbuf_pool_free(struct pbuf *p)
206   * * PBUF_REF: no buffer memory is allocated for the pbuf, even for   * * PBUF_REF: no buffer memory is allocated for the pbuf, even for
207   *             protocol headers. It is assumed that the pbuf is only   *             protocol headers. It is assumed that the pbuf is only
208   *             being used in a single thread. If the pbuf gets queued,   *             being used in a single thread. If the pbuf gets queued,
209   *             then pbuf_unref should be called to copy the buffer.   *             then pbuf_take should be called to copy the buffer.
210   * * 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
211   *              the pbuf pool that is allocated during pbuf_init().   *              the pbuf pool that is allocated during pbuf_init().
212   */   */
# Line 414  pbuf_refresh(void) Line 415  pbuf_refresh(void)
415   * through the chain until we find the new endpoint in the pbuf chain.   * through the chain until we find the new endpoint in the pbuf chain.
416   * Then the pbuf that is right on the endpoint is resized and any   * Then the pbuf that is right on the endpoint is resized and any
417   * further pbufs on the chain are deallocated.   * further pbufs on the chain are deallocated.
418   * @bug #1903 should be fixed   * @bug Cannot grow the size of a pbuf (chain).
  * @bug Does not grow pbuf chains  
419   */   */
420  /*-----------------------------------------------------------------------------------*/  /*-----------------------------------------------------------------------------------*/
421  #if NEW_PBUF_REALLOC  #if NEW_PBUF_REALLOC
# Line 599  pbuf_header(struct pbuf *p, s16_t header Line 599  pbuf_header(struct pbuf *p, s16_t header
599        
600    return 0;    return 0;
601  }  }
602  /*-----------------------------------------------------------------------------------*/  
603  /* pbuf_free():  /**
604     * Free a pbuf (chain) from its user, de-allocate if zero users.
605     *
606     * For a single pbuf, decrement its reference count. If it reaches
607     * zero, de-allocate the associated memory.
608     *
609     * For chained pbufs, all reference counts of the pbufs in the chain
610     * are decremented. Only if the first pbuf reference count reaches
611     * zero, all pbufs are de-allocated.
612   *   *
613   * Decrements the reference count and deallocates the pbuf if the   * @param pbuf pbuf (chain) to be freed from its user.
614   * reference count is zero. If the pbuf is a chain all pbufs in the   *
615   * chain are deallocated.   * @note The reference count should not decrease when inspecting the
616     * pbuf chain from head to tail.
617     *
618     * @note Chained pbufs with different reference counts should really
619     * not occur. Something that references to the first pbuf, has access
620     * to the complete chain, so all references
621   */   */
622  /*-----------------------------------------------------------------------------------*/  /*-----------------------------------------------------------------------------------*/
623  u8_t  u8_t
# Line 612  pbuf_free(struct pbuf *p) Line 625  pbuf_free(struct pbuf *p)
625  {  {
626    struct pbuf *q;    struct pbuf *q;
627    u8_t count = 0;    u8_t count = 0;
628      u16_t last_ref_count;
629    SYS_ARCH_DECL_PROTECT(old_level);    SYS_ARCH_DECL_PROTECT(old_level);
630    
631    if (p == NULL) {    if (p == NULL) {
# Line 626  pbuf_free(struct pbuf *p) Line 640  pbuf_free(struct pbuf *p)
640      p->flags == PBUF_FLAG_RAM ||      p->flags == PBUF_FLAG_RAM ||
641      p->flags == PBUF_FLAG_REF );      p->flags == PBUF_FLAG_REF );
642    
643      LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
644      p->ref--;
645    
646    /* Since decrementing ref cannot be guarranteed to be a single machine operation    /* Since decrementing ref cannot be guarranteed to be a single machine operation
647     * 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.
648     */     */
649    SYS_ARCH_PROTECT(old_level);    SYS_ARCH_PROTECT(old_level);
650    /* decrement individual reference count for each pbufs in chain */    /* decrement individual reference count for each pbuf in chain */
651    for (q = p; q != NULL; q = q->next) {    for (q = p->next; q != NULL; q = q->next) {
652      LWIP_ASSERT("pbuf_free: q->ref > 0", q->ref > 0);      /* reference counts can be 0, as 2nd and further pbufs will
653      q->ref--;         only be freed if the head of the chain is freed */
654        LWIP_ASSERT("pbuf_free: q->ref >= 0", q->ref >= 0);
655        /* decrease reference count, but do not wrap! */
656        if (q->ref > 0)
657          q->ref--;
658    }    }
659    
660    /* if reference count == 0, actually deallocate pbuf */    /* first pbuf now no longer needed? */
661    if (p->ref == 0) {    if (p->ref == 0) {
662      SYS_ARCH_UNPROTECT(old_level);      SYS_ARCH_UNPROTECT(old_level);
663    
# Line 733  pbuf_ref_chain(struct pbuf *p) Line 754  pbuf_ref_chain(struct pbuf *p)
754    
755      SYS_ARCH_UNPROTECT(old_level);      SYS_ARCH_UNPROTECT(old_level);
756  }  }
757  /*-----------------------------------------------------------------------------------*/  
758  /* pbuf_chain():  
759    /**
760   *   *
761   * Chains the two pbufs h and t together. The ->tot_len field of the   * Link two pbuf (chains) together.
762   * first pbuf (h) is adjusted.   *
763     * The ->tot_len field of the first pbuf (h) is adjusted.
764   */   */
765  /*-----------------------------------------------------------------------------------*/  /*-----------------------------------------------------------------------------------*/
766  void  void
# Line 745  pbuf_chain(struct pbuf *h, struct pbuf * Line 768  pbuf_chain(struct pbuf *h, struct pbuf *
768  {  {
769    struct pbuf *p;    struct pbuf *p;
770    
771    if(t == NULL) {    LWIP_ASSERT("h != NULL", h != NULL);
772      return;    LWIP_ASSERT("t != NULL", t != NULL);
773      
774      /* proceed to last pbuf of chain */
775      for(p = h; p->next != NULL; p = p->next) {
776        /* add length of second chain to totals of first chain */
777        p->tot_len += t->tot_len;
778    }    }
779    for(p = h; p->next != NULL; p = p->next);    /* chain */
780    p->next = t;    p->next = t;
781    h->tot_len += t->tot_len;    #if PBUF_CHAIN_DOES_REFER /** TODO (WORK IN PROGRESS) */
782      /* t is now referenced to one more time */
783      pbuf_ref(t);
784      DEBUGF(DEBUG_PBUF | DBG_FRESH | 2, ("pbuf_chain: referencing %p\n", q));
785    #endif
786  }  }
787    
788  /**  /**
789   * Dechains a pbuf from any succeeding pbufs in the chain.   * Dechains the first pbuf from its succeeding pbufs in the chain.
790   *   *
791   * Makes p->tot_len field equal to p->len.   * Makes p->tot_len field equal to p->len.
792   * @param p pbuf to dechain   * @param p pbuf to dechain
# Line 768  pbuf_dechain(struct pbuf *p) Line 800  pbuf_dechain(struct pbuf *p)
800    q = p->next;    q = p->next;
801    /* pbuf has successor in chain? */    /* pbuf has successor in chain? */
802    if (q != NULL) {    if (q != NULL) {
803      /* LW: shouldn't q->tot_len be already exactly this? (make this an assert?) */      /* tot_len invariant: (p->tot_len == p->len + p->next->tot_len) */
804        LWIP_ASSERT("p->tot_len = p->len + q->tot_len", p->tot_len = p->len + q->tot_len);
805        /* enforce invariant if assertion is disabled */
806      q->tot_len = p->tot_len - p->len;      q->tot_len = p->tot_len - p->len;
807    }    }
808    /* decouple pbuf from remainder */    /* decouple pbuf from remainder */
809    p->tot_len = p->len;    p->tot_len = p->len;
810    p->next = NULL;    p->next = NULL;
811    #if PBUF_CHAIN_DOES_REFER /** TODO (WORK IN PROGRESS) */
812      /* q is no longer referenced by p */
813      pbuf_free(q);
814      DEBUGF(DEBUG_PBUF | DBG_FRESH | 2, ("pbuf_dechain: unreferencing %p\n", q));
815    #endif
816    return q;    return q;
817  }  }
818    
819  /**  /**
820   *   *
821   * Replace any PBUF_REF pbufs of a chain into PBUF_POOL/RAM buffers.   * Create PBUF_POOL (or PBUF_RAM) copies of PBUF_REF pbufs.
822   *   *
823   * Go through pbuf chain and replace any PBUF_REF buffers with PBUF_POOL   * Go through a pbuf chain and replace any PBUF_REF buffers
824   * (or PBUF_RAM) buffers.   * with PBUF_POOL (or PBUF_RAM) pbufs, each taking a copy of
825     * the referenced data.
826   *   *
827   * Used to queue packets on behalf of the lwIP stack, such as ARP based   * Used to queue packets on behalf of the lwIP stack, such as ARP based
828   * queueing.   * queueing.
# Line 792  pbuf_dechain(struct pbuf *p) Line 832  pbuf_dechain(struct pbuf *p)
832   * @return Pointer to new head of pbuf chain.   * @return Pointer to new head of pbuf chain.
833   */   */
834  struct pbuf *  struct pbuf *
835  pbuf_unref(struct pbuf *f)  pbuf_take(struct pbuf *f)
836  {  {
837    struct pbuf *p, *prev, *top;    struct pbuf *p, *prev, *top;
838    LWIP_ASSERT("pbuf_unref: f != NULL", f != NULL);    LWIP_ASSERT("pbuf_take: f != NULL", f != NULL);
839    DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_unref(%p)\n", (void*)f));    DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_take(%p)\n", (void*)f));
840    
841    prev = NULL;    prev = NULL;
842    p = f;    p = f;
# Line 809  pbuf_unref(struct pbuf *f) Line 849  pbuf_unref(struct pbuf *f)
849      {      {
850        /* the replacement pbuf */        /* the replacement pbuf */
851        struct pbuf *q;        struct pbuf *q;
852            q = NULL;        q = NULL;
853        DEBUGF(PBUF_DEBUG | DBG_TRACE, ("pbuf_unref: encountered PBUF_REF %p\n", (void *)p));        DEBUGF(PBUF_DEBUG | DBG_TRACE, ("pbuf_take: encountered PBUF_REF %p\n", (void *)p));
854        /* allocate a pbuf (w/ payload) fully in RAM */        /* allocate a pbuf (w/ payload) fully in RAM */
855        /* PBUF_POOL buffers are faster if we can use them */        /* PBUF_POOL buffers are faster if we can use them */
856        if (p->len <= PBUF_POOL_BUFSIZE) {        if (p->len <= PBUF_POOL_BUFSIZE) {
857          q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL);          q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL);
858          if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_unref: Could not allocate PBUF_RAW\n"));          if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAW\n"));
859        }        }
860        /* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */        /* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */
861        if (q == NULL) {        if (q == NULL) {
862          q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM);          q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM);
863          if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_unref: Could not allocate PBUF_POOL\n"));          if (q == NULL) DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n"));
864        }        }
865        if (q != NULL)        if (q != NULL)
866        {          {  
# Line 838  pbuf_unref(struct pbuf *f) Line 878  pbuf_unref(struct pbuf *f)
878          q->len = p->len;          q->len = p->len;
879          /* do not copy ref, since someone else might be using the old buffer */          /* do not copy ref, since someone else might be using the old buffer */
880          /* pbuf is not freed, as this is the responsibility of the application */          /* pbuf is not freed, as this is the responsibility of the application */
881          DEBUGF(PBUF_DEBUG, ("pbuf_unref: replaced PBUF_REF %p with %q\n", (void *)p, (void *)q));          DEBUGF(PBUF_DEBUG, ("pbuf_take: replaced PBUF_REF %p with %q\n", (void *)p, (void *)q));
882          p = q;          p = q;
883        }        }
884        else        else
885        {        {
886          /* deallocate chain */          /* deallocate chain */
887          pbuf_free(top);          pbuf_free(top);
888          DEBUGF(PBUF_DEBUG | 2, ("pbuf_unref: failed to allocate replacement pbuf for %p\n", (void *)p));          DEBUGF(PBUF_DEBUG | 2, ("pbuf_take: failed to allocate replacement pbuf for %p\n", (void *)p));
889          return NULL;          return NULL;
890        }        }
891      }      }
892          else {      else {
893            DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_unref: not PBUF_REF"));        DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: not PBUF_REF"));
894          }      }
895    
896      prev = p;      prev = p;
897      p = p->next;      p = p->next;
898    } while (p);    } while (p);
899    DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_unref: end of chain reached."));    DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: end of chain reached."));
900        
901    return top;    return top;
902  }  }

Legend:
Removed from v.1.25  
changed lines
  Added in v.1.26

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