Esempio n. 1
0
File: mem3.c Progetto: soubok/libset
/*
** Unlink the chunk at index i from 
** whatever list is currently a member of.
*/
static void memsys3Unlink(int i){
  int size, hash;
  assert( sqlite3_mutex_held(mem.mutex) );
  size = mem.aPool[i-1].u.hdr.size;
  assert( size==mem.aPool[i+size-1].u.hdr.prevSize );
  assert( size>=2 );
  if( size <= MX_SMALL ){
    memsys3UnlinkFromList(i, &mem.aiSmall[size-2]);
  }else{
    hash = size % N_HASH;
    memsys3UnlinkFromList(i, &mem.aiHash[hash]);
  }
}
/*
** Unlink the chunk at index i from 
** whatever list is currently a member of.
*/
static void memsys3Unlink(u32 i){
  u32 size, hash;
  assert( sqlite4_mutex_held(mem3.mutex) );
  assert( (mem3.aPool[i-1].u.hdr.size4x & 1)==0 );
  assert( i>=1 );
  size = mem3.aPool[i-1].u.hdr.size4x/4;
  assert( size==mem3.aPool[i+size-1].u.hdr.prevSize );
  assert( size>=2 );
  if( size <= MX_SMALL ){
    memsys3UnlinkFromList(i, &mem3.aiSmall[size-2]);
  }else{
    hash = size % N_HASH;
    memsys3UnlinkFromList(i, &mem3.aiHash[hash]);
  }
}
/*
** *pRoot is the head of a list of free chunks of the same size
** or same size hash.  In other words, *pRoot is an entry in either
** mem3.aiSmall[] or mem3.aiHash[].  
**
** This routine examines all entries on the given list and tries
** to coalesce each entries with adjacent free chunks.  
**
** If it sees a chunk that is larger than mem3.iMaster, it replaces 
** the current mem3.iMaster with the new larger chunk.  In order for
** this mem3.iMaster replacement to work, the master chunk must be
** linked into the hash tables.  That is not the normal state of
** affairs, of course.  The calling routine must link the master
** chunk before invoking this routine, then must unlink the (possibly
** changed) master chunk once this routine has finished.
*/
static void memsys3Merge(u32 *pRoot){
  u32 iNext, prev, size, i, x;

  assert( sqlite4_mutex_held(mem3.mutex) );
  for(i=*pRoot; i>0; i=iNext){
    iNext = mem3.aPool[i].u.list.next;
    size = mem3.aPool[i-1].u.hdr.size4x;
    assert( (size&1)==0 );
    if( (size&2)==0 ){
      memsys3UnlinkFromList(i, pRoot);
      assert( i > mem3.aPool[i-1].u.hdr.prevSize );
      prev = i - mem3.aPool[i-1].u.hdr.prevSize;
      if( prev==iNext ){
        iNext = mem3.aPool[prev].u.list.next;
      }
      memsys3Unlink(prev);
      size = i + size/4 - prev;
      x = mem3.aPool[prev-1].u.hdr.size4x & 2;
      mem3.aPool[prev-1].u.hdr.size4x = size*4 | x;
      mem3.aPool[prev+size-1].u.hdr.prevSize = size;
      memsys3Link(prev);
      i = prev;
    }else{
      size /= 4;
    }
    if( size>mem3.szMaster ){
      mem3.iMaster = i;
      mem3.szMaster = size;
    }
  }
}
Esempio n. 4
0
File: mem3.c Progetto: soubok/libset
/*
** *pRoot is the head of a list of free chunks of the same size
** or same size hash.  In other words, *pRoot is an entry in either
** mem.aiSmall[] or mem.aiHash[].  
**
** This routine examines all entries on the given list and tries
** to coalesce each entries with adjacent free chunks.  
**
** If it sees a chunk that is larger than mem.iMaster, it replaces 
** the current mem.iMaster with the new larger chunk.  In order for
** this mem.iMaster replacement to work, the master chunk must be
** linked into the hash tables.  That is not the normal state of
** affairs, of course.  The calling routine must link the master
** chunk before invoking this routine, then must unlink the (possibly
** changed) master chunk once this routine has finished.
*/
static void memsys3Merge(int *pRoot){
  int iNext, prev, size, i;

  assert( sqlite3_mutex_held(mem.mutex) );
  for(i=*pRoot; i>0; i=iNext){
    iNext = mem.aPool[i].u.list.next;
    size = mem.aPool[i-1].u.hdr.size;
    assert( size>0 );
    if( mem.aPool[i-1].u.hdr.prevSize>0 ){
      memsys3UnlinkFromList(i, pRoot);
      prev = i - mem.aPool[i-1].u.hdr.prevSize;
      assert( prev>=0 );
      if( prev==iNext ){
        iNext = mem.aPool[prev].u.list.next;
      }
      memsys3Unlink(prev);
      size = i + size - prev;
      mem.aPool[prev-1].u.hdr.size = size;
      mem.aPool[prev+size-1].u.hdr.prevSize = size;
      memsys3Link(prev);
      i = prev;
    }
    if( size>mem.szMaster ){
      mem.iMaster = i;
      mem.szMaster = size;
    }
  }
}
/*
** Return a block of memory of at least nBytes in size.
** Return NULL if unable.
**
** This function assumes that the necessary mutexes, if any, are
** already held by the caller. Hence "Unsafe".
*/
static void *memsys3MallocUnsafe(int nByte){
  u32 i;
  u32 nBlock;
  u32 toFree;

  assert( sqlite4_mutex_held(mem3.mutex) );
  assert( sizeof(Mem3Block)==8 );
  if( nByte<=12 ){
    nBlock = 2;
  }else{
    nBlock = (nByte + 11)/8;
  }
  assert( nBlock>=2 );

  /* STEP 1:
  ** Look for an entry of the correct size in either the small
  ** chunk table or in the large chunk hash table.  This is
  ** successful most of the time (about 9 times out of 10).
  */
  if( nBlock <= MX_SMALL ){
    i = mem3.aiSmall[nBlock-2];
    if( i>0 ){
      memsys3UnlinkFromList(i, &mem3.aiSmall[nBlock-2]);
      return memsys3Checkout(i, nBlock);
    }
  }else{
    int hash = nBlock % N_HASH;
    for(i=mem3.aiHash[hash]; i>0; i=mem3.aPool[i].u.list.next){
      if( mem3.aPool[i-1].u.hdr.size4x/4==nBlock ){
        memsys3UnlinkFromList(i, &mem3.aiHash[hash]);
        return memsys3Checkout(i, nBlock);
      }
    }
  }

  /* STEP 2:
  ** Try to satisfy the allocation by carving a piece off of the end
  ** of the master chunk.  This step usually works if step 1 fails.
  */
  if( mem3.szMaster>=nBlock ){
    return memsys3FromMaster(nBlock);
  }


  /* STEP 3:  
  ** Loop through the entire memory pool.  Coalesce adjacent free
  ** chunks.  Recompute the master chunk as the largest free chunk.
  ** Then try again to satisfy the allocation by carving a piece off
  ** of the end of the master chunk.  This step happens very
  ** rarely (we hope!)
  */
  for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2){
    memsys3OutOfMemory(toFree);
    if( mem3.iMaster ){
      memsys3Link(mem3.iMaster);
      mem3.iMaster = 0;
      mem3.szMaster = 0;
    }
    for(i=0; i<N_HASH; i++){
      memsys3Merge(&mem3.aiHash[i]);
    }
    for(i=0; i<MX_SMALL-1; i++){
      memsys3Merge(&mem3.aiSmall[i]);
    }
    if( mem3.szMaster ){
      memsys3Unlink(mem3.iMaster);
      if( mem3.szMaster>=nBlock ){
        return memsys3FromMaster(nBlock);
      }
    }
  }

  /* If none of the above worked, then we fail. */
  return 0;
}
Esempio n. 6
0
//给用户分配n字节的空间,返回该空间的地址。
//该函数返回至少n字节大小的block,没有则返回null。该函数假设所有必要的互斥锁都上了,所以不安全
static void *memsys3MallocUnsafe(int nByte) {
    u32 i;
    u32 nBlock;
    u32 toFree;

    assert( sqlite3_mutex_held(mem3.mutex) );   //如果不能加锁,则终止程序
    assert( sizeof(Mem3Block)==8 );   //若Mem3Block大小为8,继续往下执行
    if( nByte<=12 ) {               //给nBlock赋值
        nBlock = 2;
    } else {
        nBlock = (nByte + 11)/8;
    }
    assert( nBlock>=2 );

    /* STEP 1:
    ** Look for an entry of the correct size in either the small
    ** chunk table or in the large chunk hash table.  This is
    ** successful most of the time (about 9 times out of 10).
    */
    //首先在小chunk或者大chunk中寻找正确大小块的入口,一般都会成功
    if( nBlock <= MX_SMALL ) {       //nBlock小于MX_SMALL,则在小chunk中找
        i = mem3.aiSmall[nBlock-2];
        if( i>0 ) {
            memsys3UnlinkFromList(i, &mem3.aiSmall[nBlock-2]);
            return memsys3Checkout(i, nBlock);  //返回找到的满足的chunk
        }
    } else {   //若nBlock大于MX_SMALL,则在大chunk中找
        int hash = nBlock % N_HASH;
        for(i=mem3.aiHash[hash]; i>0; i=mem3.aPool[i].u.list.next) {
            if( mem3.aPool[i-1].u.hdr.size4x/4==nBlock ) {
                memsys3UnlinkFromList(i, &mem3.aiHash[hash]);
                return memsys3Checkout(i, nBlock);   //返回找到的chunk
            }
        }
    }

    /* STEP 2:
    ** Try to satisfy the allocation by carving a piece off of the end
    ** of the master chunk.  This step usually works if step 1 fails.
    */
    //尝试从master chunk中分裂出合适的空间,第一步失败才执行
    if( mem3.szMaster>=nBlock ) {
        return memsys3FromMaster(nBlock);  //从master chunk中获取chunk
    }


    /* STEP 3:
    ** Loop through the entire memory pool.  Coalesce adjacent free
    ** chunks.  Recompute the master chunk as the largest free chunk.
    ** Then try again to satisfy the allocation by carving a piece off
    ** of the end of the master chunk.  This step happens very
    ** rarely (we hope!)
    */
    //遍历整个内存池,合并相邻空闲chunk,重新计算主要的chunk大小,
    //再次尝试从master chunk中分裂出满足分配条件的chunk。前面都不行才执行该步骤。
    for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2) { //遍历内存池
        memsys3OutOfMemory(toFree);     //不够分配则释放
        if( mem3.iMaster ) {              //master chunk存在,将其链接到相应块索引表中
            memsys3Link(mem3.iMaster);
            mem3.iMaster = 0;
            mem3.szMaster = 0;
        }
        for(i=0; i<N_HASH; i++) {
            memsys3Merge(&mem3.aiHash[i]);  //链接相邻空chunk到aiHash中
        }
        for(i=0; i<MX_SMALL-1; i++) {
            memsys3Merge(&mem3.aiSmall[i]); //链接相邻空chunk到aiSmall中
        }
        if( mem3.szMaster ) {            //当前master chunk不为0,则从索引表中断开
            memsys3Unlink(mem3.iMaster);
            if( mem3.szMaster>=nBlock ) {
                return memsys3FromMaster(nBlock); //返回得到的内存空间
            }
        }
    }

    /* If none of the above worked, then we fail. */
    return 0;  //若上面三步都失败了,那就失败了,返回0
}