memory manager (2)

mem_heap_create_func

memory heapを作成する。mem_heap_createなどのマクロから実行される。
(関数名がXXXXX_funcなどとなっている場合、マクロ経由で実行される)

引数
n: 先頭のブロックサイズを指定する。0を指定した場合はデフォルトサイズ
(MEM_BLOCK_START_SIZE)になる。
init_blockを指定した場合は、init_blockのサイズを指定する。
init_block: memory heapの作成を高速化したい場合に、mem_heap_create_funcの呼び出し側で先頭のブロックのメモリを確保してinit_blockに指定する。これにより、mem_heap_create_func内で先頭のブロックをmalloc/freeする必要がなくなる。
type: heap typeを指定。
file_name: mem_heap_createなどのマクロを実行したファイル名
line: マクロを実行した行番号

(1)mem_heap_create_blockで先頭ブロック(block)を作成
(2)UT_LIST_INITでblock->baseを初期化
(3)UT_LIST_ADD_FIRSTでblockをリストの先頭に登録
(4)コンパイルオプションにUNIV_MEM_DEBUGが指定されているときは、mem_hash_insertでblockを登録する
(5)blockをreturnする

mem_heap_free_func

memory heapを開放する。mem_heap_freeマクロから実行される。

(1)最後のブロックを取得
block = UT_LIST_GET_LAST(heap->base);
(2)heap->free_blockがある場合、それを開放する。
(3)ループでブロックリストを前にたどりながら、全部のブロックを開放していく。先頭ブロックがheap自身なので、これでheapを開放できる。

mem_heap_alloc

memory heapからメモリを割り当てる。

(1)heap->baseのブロックリストから一番後ろのブロックを取得

    block = UT_LIST_GET_LAST(heap->base);

(2)ブロックの空き領域が足りなかったら、mem_heap_add_blockで新しいブロックを追加する。ブロックが作成できなかったらNULLを返す。

    if (mem_block_get_len(block) 
            < mem_block_get_free(block) + MEM_SPACE_NEEDED(n)) {
        block = mem_heap_add_block(heap, n);

(3)ブロックの空き領域のオフセットを取得。

    free = mem_block_get_free(block);

(4)使用するバッファの先頭位置を計算する。

    buf = (byte*)block + free;

(5)ブロックの空き領域のオフセット位置を移動する。

    mem_block_set_free(block, free + MEM_SPACE_NEEDED(n));

(6)確保したメモリのポインタを返す。

mem_heap_get_heap_top

memory heapの現在の空き領域の先頭ポインタを取得する。
(1)最後のブロックを取得

    block = UT_LIST_GET_LAST(heap->base);

(2)空き領域のポインタを取得

    buf = (byte*)block + mem_block_get_free(block);
    return(buf);

mem_heap_get_free_heap_top

引数(old_top)で指定した位置以降に確保したメモリを開放する。
mem_heap_get_heap_topで空き領域の先頭位置を取得しておいて、複数のメモリを取得したあと、mem_heap_get_free_heap_topを実行することによって、メモリの開放をまとめて実行できる。スタックポインタをシフトすることによってメモリを開放する動作に似ている。
(mem_heap_get_heap_top/mem_heap_get_free_heap_topの仕組みを利用している
箇所は見当たらなかった。mem_heap_get_free_heap_topはmem_heap_emptyで使用
されている。)

(1)最後のブロックを取得

    block = UT_LIST_GET_LAST(heap->base);

(2)old_topが含まれるブロックが見つかるまで、リストを前にたどっていく
old_topが含まれないブロックは、mem_heap_block_freeで開放していく

    while (block != NULL) {
        if (((byte*)block + mem_block_get_free(block) >= old_top)
                        && ((byte*)block <= old_top)) {
            /* Found the right block */
            break;
        }
        /* Store prev_block value before freeing the current block
        (the current block will be erased in freeing) */
        prev_block = UT_LIST_GET_PREV(list, block);

        mem_heap_block_free(heap, block);
        block = prev_block;
    }

(3)ブロックの空き領域のoffsetを、old_topに設定する

    mem_block_set_free(block, old_top - (byte*)block); 

(4)ブロックのstartとfreeが同じになった場合、そのブロックは全く使用されて
いないので開放する。ただし先頭ブロックは開放しない。
(先頭ブロックかどうかはheap != blockでチェックしている)

    /* If free == start, we may free the block if it is not the first
    one */
    if ((heap != block) && (mem_block_get_free(block) == 
                            mem_block_get_start(block))) {
        mem_heap_block_free(heap, block);
    }

mem_heap_empty

memory heapを空にする。
先頭ブロックのバッファの開始位置を指定して、mem_heap_free_heap_topを実行している。

    mem_heap_free_heap_top(heap, (byte*)heap + mem_block_get_start(heap));
 heap->free_blockがある場合、それも開放する。