Logo Search packages:      
Sourcecode: ksh version File versions  Download package

vmlast.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*          Copyright (c) 1985-2009 AT&T Intellectual Property          *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                    by AT&T Intellectual Property                     *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                  David Korn <dgk@research.att.com>                   *
*                   Phong Vo <kpv@research.att.com>                    *
*                                                                      *
***********************************************************************/
#if defined(_UWIN) && defined(_BLD_ast)

void _STUB_vmlast(){}

#else

#include    "vmhdr.h"

/*    Allocation with freeing and reallocing of last allocated block only.
**
**    Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
*/

#if __STD_C
static Void_t* lastalloc(Vmalloc_t* vm, size_t size)
#else
static Void_t* lastalloc(vm, size)
Vmalloc_t*  vm;
size_t            size;
#endif
{
      reg Block_t *tp, *next;
      reg Seg_t   *seg, *last;
      reg size_t  s;
      reg Vmdata_t*     vd = vm->data;
      reg int           local, inuse;
      size_t            orgsize = 0;

      SETINUSE(vd, inuse);
      if(!(local = vd->mode&VM_TRUST))
      {     GETLOCAL(vd,local);
            if(ISLOCK(vd,local))
            {     CLRINUSE(vd, inuse);
                  return NIL(Void_t*);
            }
            SETLOCK(vd,local);
            orgsize = size;
      }

      size = size < ALIGN ? ALIGN : ROUND(size,ALIGN);
      for(;;)
      {     for(last = NIL(Seg_t*), seg = vd->seg; seg; last = seg, seg = seg->next)
            {     if(!(tp = seg->free) || (SIZE(tp)+sizeof(Head_t)) < size)
                        continue;
                  if(last)
                  {     last->next = seg->next;
                        seg->next = vd->seg;
                        vd->seg = seg;
                  }
                  goto got_block;
            }

            /* there is no usable free space in region, try extending */
            if((tp = (*_Vmextend)(vm,size,NIL(Vmsearch_f))) )
            {     seg = SEG(tp);
                  goto got_block;
            }
            else if(vd->mode&VM_AGAIN)
                  vd->mode &= ~VM_AGAIN;
            else  goto done;
      }

got_block:
      if((s = SIZE(tp)) >= size)
      {     next = (Block_t*)((Vmuchar_t*)tp+size);
            SIZE(next) = s - size;
            SEG(next) = seg;
            seg->free = next;
      }
      else  seg->free = NIL(Block_t*);

      vd->free = seg->last = tp;

      if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
            (*_Vmtrace)(vm, NIL(Vmuchar_t*), (Vmuchar_t*)tp, orgsize, 0);

done:
      CLRLOCK(vd,local);
      ANNOUNCE(local, vm, VM_ALLOC, (Void_t*)tp, vm->disc);
      CLRINUSE(vd, inuse);
      return (Void_t*)tp;
}

#if __STD_C
static int lastfree(Vmalloc_t* vm, reg Void_t* data )
#else
static int lastfree(vm, data)
Vmalloc_t*  vm;
reg Void_t* data;
#endif
{
      reg Seg_t*  seg;
      reg Block_t*      fp;
      reg size_t  s;
      reg Vmdata_t*     vd = vm->data;
      reg int           local, inuse;

      if(!data)
            return 0;

      SETINUSE(vd, inuse);
      if(!(local = vd->mode&VM_TRUST) )
      {     GETLOCAL(vd, local);
            if(ISLOCK(vd, local))
            {     CLRINUSE(vd, inuse);
                  return -1;
            }
            SETLOCK(vd, local);
      }
      if(data != (Void_t*)vd->free)
      {     if(!local && vm->disc->exceptf)
                  (void)(*vm->disc->exceptf)(vm,VM_BADADDR,data,vm->disc);
            CLRLOCK(vd, local);
            CLRINUSE(vd, inuse);
            return -1;
      }

      seg = vd->seg;
      if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
      {     if(seg->free )
                  s = (Vmuchar_t*)(seg->free) - (Vmuchar_t*)data;
            else  s = (Vmuchar_t*)BLOCK(seg->baddr) - (Vmuchar_t*)data;
            (*_Vmtrace)(vm, (Vmuchar_t*)data, NIL(Vmuchar_t*), s, 0);
      }

      vd->free = NIL(Block_t*);
      fp = (Block_t*)data;
      SEG(fp)  = seg;
      SIZE(fp) = ((Vmuchar_t*)BLOCK(seg->baddr) - (Vmuchar_t*)data) - sizeof(Head_t);
      seg->free = fp;
      seg->last = NIL(Block_t*);

      CLRLOCK(vd, local);
      ANNOUNCE(local, vm, VM_FREE, data, vm->disc);
      CLRINUSE(vd, inuse);
      return 0;
}

#if __STD_C
static Void_t* lastresize(Vmalloc_t* vm, reg Void_t* data, size_t size, int type )
#else
static Void_t* lastresize(vm, data, size, type )
Vmalloc_t*  vm;
reg Void_t* data;
size_t            size;
int         type;
#endif
{
      reg Block_t*      tp;
      reg Seg_t   *seg;
      reg size_t  oldsize;
      reg ssize_t s, ds;
      reg Vmdata_t*     vd = vm->data;
      reg int           local, inuse;
      reg Void_t* addr;
      Void_t*           orgdata = NIL(Void_t*);
      size_t            orgsize = 0;

      SETINUSE(vd, inuse);
      if(!data)
      {     oldsize = 0;
            data = lastalloc(vm,size);
            goto done;
      }
      if(size <= 0)
      {     (void)lastfree(vm,data);
            CLRINUSE(vd, inuse);
            return NIL(Void_t*);
      }

      if(!(local = vd->mode&VM_TRUST))
      {     GETLOCAL(vd, local);
            if(ISLOCK(vd, local))
            {     CLRINUSE(vd, inuse);
                  return NIL(Void_t*);
            }
            SETLOCK(vd, local);
            orgdata = data;
            orgsize = size;
      }

      if(data == (Void_t*)vd->free)
            seg = vd->seg;
      else
      {     /* see if it was one of ours */
            for(seg = vd->seg; seg; seg = seg->next)
                  if(data >= seg->addr && data < (Void_t*)seg->baddr)
                        break;
            if(!seg || (VLONG(data)%ALIGN) != 0 ||
               (seg->last && (Vmuchar_t*)data > (Vmuchar_t*)seg->last) )
            {     CLRLOCK(vd,0);
                  CLRINUSE(vd, inuse);
                  return NIL(Void_t*);
            }
      }

      /* set 's' to be the current available space */
      if(data != seg->last)
      {     if(seg->last && (Vmuchar_t*)data < (Vmuchar_t*)seg->last)
                  oldsize = (Vmuchar_t*)seg->last - (Vmuchar_t*)data;
            else  oldsize = (Vmuchar_t*)BLOCK(seg->baddr) - (Vmuchar_t*)data;
            s = -1;
      }
      else
      {     s = (Vmuchar_t*)BLOCK(seg->baddr) - (Vmuchar_t*)data;
            if(!(tp = seg->free) )
                  oldsize = s;
            else
            {     oldsize = (Vmuchar_t*)tp - (Vmuchar_t*)data;
                  seg->free = NIL(Block_t*);
            }
      }

      size = size < ALIGN ? ALIGN : ROUND(size,ALIGN);
      if(s < 0 || (ssize_t)size > s)
      {     if(s >= 0) /* amount to extend */
            {     ds = size-s; ds = ROUND(ds,vd->incr);
                  addr = (*vm->disc->memoryf)(vm, seg->addr, seg->extent,
                                        seg->extent+ds, vm->disc);
                  if(addr == seg->addr)
                  {     s += ds;
                        seg->size += ds;
                        seg->extent += ds;
                        seg->baddr += ds;
                        SIZE(BLOCK(seg->baddr)) = BUSY;
                  }
                  else  goto do_alloc;
            }
            else
            { do_alloc:
                  if(!(type&(VM_RSMOVE|VM_RSCOPY)) )
                        data = NIL(Void_t*);
                  else
                  {     tp = vd->free;
                        if(!(addr = KPVALLOC(vm,size,lastalloc)) )
                        {     vd->free = tp;
                              data = NIL(Void_t*);
                        }
                        else
                        {     if(type&VM_RSCOPY)
                              {     ds = oldsize < size ? oldsize : size;
                                    memcpy(addr, data, ds);
                              }

                              if(s >= 0 && seg != vd->seg)
                              {     tp = (Block_t*)data;
                                    SEG(tp) = seg;
                                    SIZE(tp) = s - sizeof(Head_t);
                                    seg->free = tp;
                              }

                              /* new block and size */
                              data = addr;
                              seg = vd->seg;
                              s = (Vmuchar_t*)BLOCK(seg->baddr) -
                                  (Vmuchar_t*)data;
                              seg->free = NIL(Block_t*);
                        }
                  }
            }
      }

      if(data)
      {     if(s >= (ssize_t)(size+sizeof(Head_t)) )
            {     tp = (Block_t*)((Vmuchar_t*)data + size);
                  SEG(tp) = seg;
                  SIZE(tp) = (s - size) - sizeof(Head_t);
                  seg->free = tp;
            }

            vd->free = seg->last = (Block_t*)data;

            if(!local && (vd->mode&VM_TRACE) && _Vmtrace)
                  (*_Vmtrace)(vm,(Vmuchar_t*)orgdata,(Vmuchar_t*)data,orgsize,0);
      }

      CLRLOCK(vd, local);
      ANNOUNCE(local, vm, VM_RESIZE, data, vm->disc);

done: if(data && (type&VM_RSZERO) && size > oldsize)
            memset((Void_t*)((Vmuchar_t*)data + oldsize), 0, size-oldsize);

      CLRINUSE(vd, inuse);
      return data;
}


#if __STD_C
static long lastaddr(Vmalloc_t* vm, Void_t* addr)
#else
static long lastaddr(vm, addr)
Vmalloc_t*  vm;
Void_t*           addr;
#endif
{
      reg Vmdata_t*     vd = vm->data;

      if(!(vd->mode&VM_TRUST) && ISLOCK(vd,0))
            return -1L;
      if(!vd->free || addr < (Void_t*)vd->free || addr >= (Void_t*)vd->seg->baddr)
            return -1L;
      else  return (Vmuchar_t*)addr - (Vmuchar_t*)vd->free;
}

#if __STD_C
static long lastsize(Vmalloc_t* vm, Void_t* addr)
#else
static long lastsize(vm, addr)
Vmalloc_t*  vm;
Void_t*           addr;
#endif
{
      reg Vmdata_t*     vd = vm->data;

      if(!(vd->mode&VM_TRUST) && ISLOCK(vd,0))
            return -1L;
      if(!vd->free || addr != (Void_t*)vd->free )
            return -1L;
      else if(vd->seg->free)
            return (Vmuchar_t*)vd->seg->free - (Vmuchar_t*)addr;
      else  return (Vmuchar_t*)vd->seg->baddr - (Vmuchar_t*)addr - sizeof(Head_t);
}

#if __STD_C
static int lastcompact(Vmalloc_t* vm)
#else
static int lastcompact(vm)
Vmalloc_t*  vm;
#endif
{
      reg Block_t*      fp;
      reg Seg_t   *seg, *next;
      reg size_t  s;
      reg Vmdata_t*     vd = vm->data;
      reg int           inuse;

      SETINUSE(vd, inuse);
      if(!(vd->mode&VM_TRUST))
      {     if(ISLOCK(vd,0))
            {     CLRINUSE(vd, inuse);
                  return -1;
            }
            SETLOCK(vd,0);
      }

      for(seg = vd->seg; seg; seg = next)
      {     next = seg->next;

            if(!(fp = seg->free))
                  continue;

            seg->free = NIL(Block_t*);
            if(seg->size == (s = SIZE(fp)&~BITS))
                  s = seg->extent;
            else  s += sizeof(Head_t);

            if((*_Vmtruncate)(vm,seg,s,1) == s)
                  seg->free = fp;
      }

      if((vd->mode&VM_TRACE) && _Vmtrace)
            (*_Vmtrace)(vm,(Vmuchar_t*)0,(Vmuchar_t*)0,0,0);

      CLRLOCK(vd,0);
      CLRINUSE(vd, inuse);
      return 0;
}

#if __STD_C
static Void_t* lastalign(Vmalloc_t* vm, size_t size, size_t align)
#else
static Void_t* lastalign(vm, size, align)
Vmalloc_t*  vm;
size_t            size;
size_t            align;
#endif
{
      reg Vmuchar_t*    data;
      reg Seg_t*  seg;
      reg Block_t*      next;
      reg int           local, inuse;
      reg size_t  s, orgsize = 0, orgalign = 0;
      reg Vmdata_t*     vd = vm->data;

      if(size <= 0 || align <= 0)
            return NIL(Void_t*);

      SETINUSE(vd, inuse);
      if(!(local = vd->mode&VM_TRUST) )
      {     GETLOCAL(vd,local);
            if(ISLOCK(vd,local) )
            {     CLRINUSE(vd, inuse);
                  return NIL(Void_t*);
            }
            SETLOCK(vd,local);
            orgsize = size;
            orgalign = align;
      }

      size = size <= TINYSIZE ? TINYSIZE : ROUND(size,ALIGN);
      align = MULTIPLE(align,ALIGN);

      s = size + align; 
      if(!(data = (Vmuchar_t*)KPVALLOC(vm,s,lastalloc)) )
            goto done;

      /* find the segment containing this block */
      for(seg = vd->seg; seg; seg = seg->next)
            if(seg->last == (Block_t*)data)
                  break;
      /**/ASSERT(seg);

      /* get a suitably aligned address */
      if((s = (size_t)(VLONG(data)%align)) != 0)
            data += align-s; /**/ASSERT((VLONG(data)%align) == 0);

      /* free the unused tail */
      next = (Block_t*)(data+size);
      if((s = (seg->baddr - (Vmuchar_t*)next)) >= sizeof(Block_t))
      {     SEG(next) = seg;
            SIZE(next) = s - sizeof(Head_t);
            seg->free = next;
      }

      vd->free = seg->last = (Block_t*)data;

      if(!local && !(vd->mode&VM_TRUST) && _Vmtrace && (vd->mode&VM_TRACE) )
            (*_Vmtrace)(vm,NIL(Vmuchar_t*),data,orgsize,orgalign);

done:
      CLRLOCK(vd,local);
      ANNOUNCE(local, vm, VM_ALLOC, (Void_t*)data, vm->disc);

      CLRINUSE(vd, inuse);
      return (Void_t*)data;
}

/* Public method for free-1 allocation */
static Vmethod_t _Vmlast =
{
      lastalloc,
      lastresize,
      lastfree,
      lastaddr,
      lastsize,
      lastcompact,
      lastalign,
      VM_MTLAST
};

__DEFINE__(Vmethod_t*,Vmlast,&_Vmlast);

#ifdef NoF
NoF(vmlast)
#endif

#endif

Generated by  Doxygen 1.6.0   Back to index