Back to index

lightning-sunbird  0.9+nobinonly
Defines | Functions | Variables
allchblk.c File Reference
#include <stdio.h>
#include "gc_priv.h"

Go to the source code of this file.

Defines

#define DEBUG
#define MAX_BLACK_LIST_ALLOC   (2*HBLKSIZE)
#define LAST_TRIP   2

Functions

void GC_print_hblkfreelist ()
static GC_bool setup_header (hdr *hhdr, word sz, int kind, unsigned char flags)
struct hblkGC_allochblk (word sz, int kind, unsigned char flags)
void GC_freehblk (struct hblk *p)

Variables

struct hblkGC_hblkfreelist = 0
struct hblkGC_savhbp = (struct hblk *)0
word GC_max_hblk_size = HBLKSIZE
struct hblkGC_freehblk_ptr = 0

Define Documentation

Definition at line 17 of file allchblk.c.

#define LAST_TRIP   2

Definition at line 104 of file allchblk.c.

Definition at line 36 of file allchblk.c.


Function Documentation

struct hblk* GC_allochblk ( word  sz,
int  kind,
unsigned char  flags 
) [read]

Definition at line 122 of file allchblk.c.

{
    register struct hblk *thishbp;
    register hdr * thishdr;        /* Header corr. to thishbp */
    register struct hblk *hbp;
    register hdr * hhdr;           /* Header corr. to hbp */
    struct hblk *prevhbp;
    register hdr * phdr;           /* Header corr. to prevhbp */
    signed_word size_needed;    /* number of bytes in requested objects */
    signed_word size_avail; /* bytes available in this block   */
    int trip_count = 0;

    size_needed = HBLKSIZE * OBJ_SZ_TO_BLOCKS(sz);
    if ((word)size_needed >  GC_max_hblk_size)
       GC_max_hblk_size = size_needed;

    /* search for a big enough block in free list */
       hbp = GC_savhbp;
       hhdr = HDR(hbp);
       for(;;) {

           prevhbp = hbp;
           phdr = hhdr;
           hbp = (prevhbp == 0? GC_hblkfreelist : phdr->hb_next);
           hhdr = HDR(hbp);

           if( prevhbp == GC_savhbp) {
              if (trip_count == LAST_TRIP) return(0);
              ++trip_count;
           }

           if( hbp == 0 ) continue;

           size_avail = hhdr->hb_sz;
#          ifdef EXACT_FIRST
              if (trip_count <= 1 && size_avail != size_needed) continue;
#          endif
           if (size_avail < size_needed) continue;
#          ifdef PRESERVE_LAST
              if (size_avail != size_needed
                  && !GC_incremental
                  && (word)size_needed <= GC_max_hblk_size/2
                  && GC_in_last_heap_sect((ptr_t)hbp)
                  && GC_should_collect()) {
                  continue;
              } 
#          endif
           /* If the next heap block is obviously better, go on.      */
           /* This prevents us from disassembling a single large block */
           /* to get tiny blocks.                              */
           {
             signed_word next_size;
             
             thishbp = hhdr -> hb_next;
             if (thishbp == 0) thishbp = GC_hblkfreelist; 
             thishdr = HDR(thishbp);
             next_size = (signed_word)(thishdr -> hb_sz);
             if (next_size < size_avail
                 && next_size >= size_needed
                 && !GC_is_black_listed(thishbp, (word)size_needed)) {
                 continue;
             }
           }
           if ( !IS_UNCOLLECTABLE(kind) &&
                (kind != PTRFREE || size_needed > MAX_BLACK_LIST_ALLOC)) {
             struct hblk * lasthbp = hbp;
             ptr_t search_end = (ptr_t)hbp + size_avail - size_needed;
             signed_word orig_avail = size_avail;
             signed_word eff_size_needed = ((flags & IGNORE_OFF_PAGE)?
                                          HBLKSIZE
                                          : size_needed);
             
             
             while ((ptr_t)lasthbp <= search_end
                    && (thishbp = GC_is_black_listed(lasthbp,
                                                (word)eff_size_needed))) {
               lasthbp = thishbp;
             }
             size_avail -= (ptr_t)lasthbp - (ptr_t)hbp;
             thishbp = lasthbp;
             if (size_avail >= size_needed) {
               if (thishbp != hbp && GC_install_header(thishbp)) {
                 /* Split the block at thishbp */
                     thishdr = HDR(thishbp);
                     /* GC_invalidate_map not needed, since we will   */
                     /* allocate this block.                          */
                    thishdr -> hb_next = hhdr -> hb_next;
                    thishdr -> hb_sz = size_avail;
                    hhdr -> hb_sz = (ptr_t)thishbp - (ptr_t)hbp;
                    hhdr -> hb_next = thishbp;
                /* Advance to thishbp */
                    prevhbp = hbp;
                    phdr = hhdr;
                    hbp = thishbp;
                    hhdr = thishdr;
              }
             } else if (size_needed > (signed_word)BL_LIMIT
                        && orig_avail - size_needed
                         > (signed_word)BL_LIMIT) {
               /* Punt, since anything else risks unreasonable heap growth. */
               WARN("Needed to allocate blacklisted block at 0x%lx\n",
                   (word)hbp);
               thishbp = hbp;
               size_avail = orig_avail;
             } else if (size_avail == 0
                      && size_needed == HBLKSIZE
                      && prevhbp != 0) {
#             ifndef FIND_LEAK
                static unsigned count = 0;
                
                /* The block is completely blacklisted.  We need      */
                /* to drop some such blocks, since otherwise we spend */
                /* all our time traversing them if pointerfree */
                /* blocks are unpopular.                       */
                 /* A dropped block will be reconsidered at next GC.  */
                 if ((++count & 3) == 0) {
                   /* Allocate and drop the block in small chunks, to */
                   /* maximize the chance that we will recover some   */
                   /* later.                                          */
                     struct hblk * limit = hbp + (hhdr->hb_sz/HBLKSIZE);
                     struct hblk * h;
                     
                    GC_words_wasted += hhdr->hb_sz;
                     phdr -> hb_next = hhdr -> hb_next;
                     for (h = hbp; h < limit; h++) {
                       if (h == hbp || GC_install_header(h)) {
                         hhdr = HDR(h);
                         (void) setup_header(
                              hhdr,
                                     BYTES_TO_WORDS(HBLKSIZE - HDR_BYTES),
                                     PTRFREE, 0); /* Cant fail */
                              if (GC_debugging_started) {
                                BZERO(hbp + HDR_BYTES, HBLKSIZE - HDR_BYTES);
                              }
                       }
                     }
                   /* Restore hbp to point at free block */
                     if (GC_savhbp == hbp) GC_savhbp = prevhbp;
                     hbp = prevhbp;
                     hhdr = phdr;
                     if (hbp == GC_savhbp) --trip_count;
                 }
#             endif
             }
           }
           if( size_avail >= size_needed ) {
              /* found a big enough block       */
              /* let thishbp --> the block      */
              /* set prevhbp, hbp to bracket it */
                  thishbp = hbp;
                  thishdr = hhdr;
                  if( size_avail == size_needed ) {
                     hbp = hhdr->hb_next;
                     hhdr = HDR(hbp);
                  } else {
                     hbp = (struct hblk *)
                         (((word)thishbp) + size_needed);
                     if (!GC_install_header(hbp)) {
                         hbp = thishbp;
                         continue;
                     }
                     hhdr = HDR(hbp);
                     GC_invalidate_map(hhdr);
                     hhdr->hb_next = thishdr->hb_next;
                     hhdr->hb_sz = size_avail - size_needed;
                  }
              /* remove *thishbp from hblk freelist */
                  if( prevhbp == 0 ) {
                     GC_hblkfreelist = hbp;
                  } else {
                     phdr->hb_next = hbp;
                  }
              /* save current list search position */
                  GC_savhbp = hbp;
              break;
           }
       }
       
    /* Notify virtual dirty bit implementation that we are about to write. */
       GC_write_hint(thishbp);
       /* This should deal better with large blocks.    */
    
    /* Add it to map of valid blocks */
       if (!GC_install_counts(thishbp, (word)size_needed)) return(0);
       /* This leaks memory under very rare conditions. */
              
    /* Set up header */
        if (!setup_header(thishdr, sz, kind, flags)) {
            GC_remove_counts(thishbp, (word)size_needed);
            return(0); /* ditto */
        }
        
    /* Clear block if necessary */
       if (GC_debugging_started
           || sz > MAXOBJSZ && GC_obj_kinds[kind].ok_init) {
           BZERO(thishbp + HDR_BYTES,  size_needed - HDR_BYTES);
       }

    /* We just successfully allocated a block.  Restart count of      */
    /* consecutive failures.                                          */
    {
       extern unsigned GC_fail_count;
       
       GC_fail_count = 0;
    }
    
    return( thishbp );
}

Here is the call graph for this function:

Here is the caller graph for this function:

void GC_freehblk ( struct hblk p)

Definition at line 344 of file allchblk.c.

{
register hdr *phdr;  /* Header corresponding to p */
register struct hblk *hbp, *prevhbp;
register hdr *hhdr, *prevhdr;
register signed_word size;

    /* GC_savhbp may become invalid due to coalescing.  Clear it. */
       GC_savhbp = (struct hblk *)0;

    phdr = HDR(p);
    size = phdr->hb_sz;
    size = HBLKSIZE * OBJ_SZ_TO_BLOCKS(size);
    GC_remove_counts(p, (word)size);
    phdr->hb_sz = size;
    GC_invalidate_map(phdr);
    prevhbp = 0;
    
    /* The following optimization was suggested by David Detlefs.     */
    /* Note that the header cannot be NIL, since there cannot be an   */
    /* intervening  call to GC_freehblk without resetting             */
    /* GC_freehblk_ptr.                                               */
    if (GC_freehblk_ptr != 0 &&
       HDR(GC_freehblk_ptr)->hb_map == GC_invalid_map &&
       (ptr_t)GC_freehblk_ptr < (ptr_t)p) {
      hbp = GC_freehblk_ptr;
    } else {
      hbp = GC_hblkfreelist;
    };
    hhdr = HDR(hbp);

    while( (hbp != 0) && (hbp < p) ) {
       prevhbp = hbp;
       prevhdr = hhdr;
       hbp = hhdr->hb_next;
       hhdr = HDR(hbp);
    }
    GC_freehblk_ptr = prevhbp;
    
    /* Check for duplicate deallocation in the easy case */
      if (hbp != 0 && (ptr_t)p + size > (ptr_t)hbp
        || prevhbp != 0 && (ptr_t)prevhbp + prevhdr->hb_sz > (ptr_t)p) {
        GC_printf1("Duplicate large block deallocation of 0x%lx\n",
                 (unsigned long) p);
        GC_printf2("Surrounding free blocks are 0x%lx and 0x%lx\n",
                 (unsigned long) prevhbp, (unsigned long) hbp);
      }

    /* Coalesce with successor, if possible */
      if( (((word)p)+size) == ((word)hbp) ) {
       phdr->hb_next = hhdr->hb_next;
       phdr->hb_sz += hhdr->hb_sz;
       GC_remove_header(hbp);
      } else {
       phdr->hb_next = hbp;
      }

    
    if( prevhbp == 0 ) {
       GC_hblkfreelist = p;
    } else if( (((word)prevhbp) + prevhdr->hb_sz)
              == ((word)p) ) {
      /* Coalesce with predecessor */
       prevhdr->hb_next = phdr->hb_next;
       prevhdr->hb_sz += phdr->hb_sz;
       GC_remove_header(p);
    } else {
       prevhdr->hb_next = p;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 47 of file allchblk.c.

{
    struct hblk * h = GC_hblkfreelist;
    word total_free = 0;
    hdr * hhdr = HDR(h);
    word sz;
    
    while (h != 0) {
        sz = hhdr -> hb_sz;
       GC_printf2("0x%lx size %lu ", (unsigned long)h, (unsigned long)sz);
       total_free += sz;
        if (GC_is_black_listed(h, HBLKSIZE) != 0) {
             GC_printf0("start black listed\n");
        } else if (GC_is_black_listed(h, hhdr -> hb_sz) != 0) {
             GC_printf0("partially black listed\n");
        } else {
             GC_printf0("not black listed\n");
        }
        h = hhdr -> hb_next;
        hhdr = HDR(h);
    }
    GC_printf1("Total of %lu bytes on free list\n", (unsigned long)total_free);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static GC_bool setup_header ( hdr hhdr,
word  sz,
int  kind,
unsigned char  flags 
) [static]

Definition at line 76 of file allchblk.c.

{
    register word descr;
    
    /* Add description of valid object pointers */
      if (!GC_add_map_entry(sz)) return(FALSE);
      hhdr -> hb_map = GC_obj_map[sz > MAXOBJSZ? 0 : sz];
      
    /* Set size, kind and mark proc fields */
      hhdr -> hb_sz = sz;
      hhdr -> hb_obj_kind = kind;
      hhdr -> hb_flags = flags;
      descr = GC_obj_kinds[kind].ok_descriptor;
      if (GC_obj_kinds[kind].ok_relocate_descr) descr += WORDS_TO_BYTES(sz);
      hhdr -> hb_descr = descr;
      
    /* Clear mark bits */
      GC_clear_hdr_marks(hhdr);
      
    hhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
    return(TRUE);
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

struct hblk* GC_freehblk_ptr = 0

Definition at line 334 of file allchblk.c.

struct hblk* GC_hblkfreelist = 0

Definition at line 40 of file allchblk.c.

Definition at line 109 of file allchblk.c.

struct hblk* GC_savhbp = (struct hblk *)0

Definition at line 42 of file allchblk.c.