本シリーズのトップページ |
---|
https://qiita.com/robozushi10/items/ca7c25dab3c279ba4e2b |
はじめに
本記事の趣旨は「01 概要」に記しているが、
要は 13年前(=2008年) に K&R をマネて実装した「自作メモリアロケータ」の振り返りである.
本項ではコード全文を記す.
余談
1.
デバッグ用関数定義 memman_debug.c を見ると、「hoge」「piyo」といったログ表示をさせていた..
当時、ifdef が切り替わることをテストしていたのだろうか..
2.
不必要にラッパ関数が多いが、当時の開発現場のコードをマネたのだと思う.
当時のコードは printf() を呼び出すまでに、5個ほどラッパ関数が存在していた.
Makefile
PROGRAM=memman
SRCS=main.c \
memman.c \
memman_core.c \
memman_resource.c \
memman_debug.c
HDRS=memman.h \
priv_memman_core.h \
priv_memman_debug.h \
priv_memman_std.h
OBJS=$(SRCS:%.c=%.o)
CC = gcc
LIBPATH =
LIBS = -lpthread
CFLAGS = -Wall -g -O0 $(INCHEADER)
LDFLAGS = $(LIBPATH)
$(PROGRAM):$(SRCS) $(HDRS)
$(CC) $(CFLAGS) -o $(PROGRAM) $(SRCS) $(LDFLAGS) $(LIBS)
clean:
\rm -f $(PROGRAM) $(OBJS)
main.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>
#include "memman.h"
#ifdef DEBUG
#include "priv_memman_debug.h"
#endif
#ifdef DEBUG_CHK_MEMLEAK
#include "priv_memman_debug.h"
#endif
sem_t Sem;
int
main()
{
mem_inst_t * instance = NULL;
char * buf[1000];
int i = 0;
int j = 0;
req_mem_inst_t req;
/* セマフォについても管理モジュールを作成し,内部で資源情報を
* 保持すると良いが,ここでは作成していない */
sem_init /* セマフォの初期化 */
(
&Sem, /* セマフォ変数の初期化 */
0, /* 0:スレッドでセマフォ共有, 非0:プロセスで共有 */
1 /* 並列処理数 */
);
req.functor_alloc = &malloc,
req.functor_free = &free,
req.pool_size = 4096,
req.key = "main",
req.sem = &Sem;
req.pshared = 0;
req.value = 0;
#if 1
instance = Mman_new_inst(&req);
for(j = 0; j < 500; j++)
{
for(i = 0; i < 1000; i++)
{
buf[i] = instance->alloc(0,i);
}
for(i = 0; i < 1000; i++) /* alloc よりも小さい値にするとメモリリークが確認出来る */
{
instance->free(0, buf[i]);
}
}
#ifdef DEBUG_CHK_MEMLEAK
//Mmc_debug_dump_buf();
#endif /* DEBUG_CHK_MEMLEAK */
/* robozushi10 セマフォ破棄についても管理モジュールを作成すると良い */
Mman_delete_inst(instance->id);
Mman_close(); /* フリーリスト破棄 + フリーノード破棄 */
#else
for(j = 0; j < 500; j++)
{
for(i = 0; i < 1000; i++)
{
buf[i] = malloc(i);
}
for(i = 0; i < 1000; i++)
{
free(buf[i]);
}
}
#endif
return 0;
}
memman.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "memman.h"
#include "priv_memman_std.h"
#include "priv_memman_core.h"
#include "priv_memman_debug.h"
extern mman_t memrtbl[];
/* key からメモリリソース情報の ID を取得する */
static int
mman_key2id(const char * key)
{
int id = 0;
const int invalid_id = -1;
for(id = 0; id < Mman_get_rsrc_num(); id++)
{
if(MMAN_STRCMP(key, ==, memrtbl[id].key))
{
return id;
}
}
/* even if id is not exist, you don't need error message */
return invalid_id;
}
/* メモリリソーステーブルに登録 */
static void
mman_register_memrtbl(req_mem_inst_t * req, mem_inst_t * inst)
{
int id = mman_key2id(req->key);
memrtbl[id].id = id;
strcpy(memrtbl[id].key, req->key);
memrtbl[id].instance = inst;
memrtbl[id].functor_alloc = req->functor_alloc;
memrtbl[id].functor_free = req->functor_free;
memrtbl[id].pool_size = req->pool_size;
memrtbl[id].rest_size = req->pool_size;
memrtbl[id].position = 0;
memrtbl[id].sem = req->sem;
}
/* ID からメモリリソース情報へのポインタ取得 */
inline
static mman_t *
mman_get_rsrc(int id)
{
return &memrtbl[id];
}
/* key からメモリリソース情報へのポインタ取得 */
static mman_t *
mman_get_rsrc_by_key(char * key)
{
int id = mman_key2id(key);
if(-1 == id)
{
FATAL("mman_key2id error at mman_get_rsrc_by_key(%s)\n", key);
}
return &memrtbl[id];
}
/* インスタンスのセットアップ */
static mem_inst_t *
mman_create_instance(req_mem_inst_t * req)
{
mman_t * p = NULL;
mem_inst_t * inst = NULL;
inst = malloc(sizeof(mem_inst_t));
if(NULL == inst)
{
FATAL("malloc error at mman_create_instance\n");
}
/* メモリリソーステーブルに登録 */
mman_register_memrtbl(req, inst);
/* メモリリソース情報へのポインタ取得 */
p = mman_get_rsrc_by_key(req->key);
inst->id = p->id;
inst->alloc = &Mman_alloc;
inst->free = &Mman_free;
inst->get_used_size = NULL;
inst->get_rest_size = NULL;
return inst;
}
/* ID をキーにして,インスタンスを返す(内部用) */
inline
static mem_inst_t *
mman_get_inst(int id)
{
if((id < 0) || (Mman_get_rsrc_num() < id))
{
err_mesg("invalid id(%d)\n", id);
}
return memrtbl[id].instance;
}
/* key をキーにして,インスタンスを返す(内部用) */
inline
static mem_inst_t *
mman_get_inst_by_key(char * key)
{
int id = mman_key2id(key);
/* even if id is not exist, you don't need error message */
return memrtbl[id].instance;
}
/* すでにインスタンスが存在しているかどうか */
static int
mman_is_inst_already_exist(char * key)
{
mem_inst_t * p = NULL;
enum { not_exist, exist };
p = mman_get_inst_by_key(key);
return (NULL != p) ? exist : not_exist;
}
/* インスタンス作成I/F */
mem_inst_t *
Mman_new_inst(req_mem_inst_t * req)
{
mem_inst_t * inst = NULL;
int exist = 0;
static int is_flist = 0;
if(!is_flist)
{
Mmc_initialize(Mman_get_rsrc_num());
is_flist = 1;
}
/* 既にインスタンスが存在しているか */
exist = mman_is_inst_already_exist(req->key);
if(exist)
{
err_mesg("instance is already exist\n");
return NULL; /* すでにインスタンスが存在している */
}
/* インスタンス作成 */
inst = mman_create_instance(req);
if(NULL == inst)
{
err_mesg("could not create instance\n");
return NULL;
}
return inst;
}
inline
static void
mman_erase_instance(mem_inst_t * inst)
{
free(inst);
}
void
Mman_delete_inst(int id)
{
mman_t * p = mman_get_rsrc(id);
mem_inst_t * inst = p->instance;
mman_erase_instance(inst);
p->instance = NULL;
}
void
Mman_close(void)
{
Mmc_shutdown(Mman_get_rsrc_num());
}
mem_inst_t *
Mman_get_inst(int id)
{
return mman_get_inst(id);
}
void *
Mman_alloc(int id, size_t size)
{
mman_t * p = mman_get_rsrc(id);
/* robozushi10: verify request size */
return Mmc_alloc(id, size, p->functor_alloc);
}
void
Mman_free(int id, void * ptr)
{
mman_t * p = mman_get_rsrc(id);
Mmc_free(id, ptr, p->functor_free);
}
memman.h
/* 外部公開ヘッダ */
#ifndef __MEMMAN_H__
#define __MEMMAN_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>
#if 0
#define DEBUG /* デバッグログ表示 */
#define DEBUG_CHK_MEMLEAK /* メモリリークチェック */
#endif
#define DBG_BUFSIZ (128) /* メモリリークチェック用バッファ行数 */
/* インスタンス要求時に用いる */
typedef
struct _req_mem_inst_t
{
void * (* functor_alloc)(size_t size); /* メモリ獲得ファンクター */
void (* functor_free) (void * ptr); /* メモリ解放ファンクター */
size_t pool_size; /* メモリサイズ */
char * key; /* 識別キー(7文字まで) */
sem_t * sem; /* セマフォID */
int pshared; /* 0: プロセスでセマフォを共有する */
unsigned int value; /* 同時実行可能な数 */
}
req_mem_inst_t;
/* ユーザが使用するアクセッサ */
typedef
struct _mem_inst_t
{
void * (* alloc) (int id, size_t size); /* メモリ獲得I/F */
void (* free) (int id, void * ptr); /* メモリ解放I/F */
void (* get_used_size)(void); /* 使用量取得I/F */
void (* get_rest_size)(void); /* 残量取得関I/F */
int id;
}
mem_inst_t;
/* インスタンス作成I/F */
mem_inst_t * Mman_new_inst (req_mem_inst_t * req);
mem_inst_t * Mman_get_inst (int id);
void Mman_delete_inst(int id);
/* メモリ操作I/F */
void * Mman_alloc(int id, size_t size);
void Mman_free (int id, void * p) ;
void Mman_close(void);
#endif /* __MEMMAN_H__ */
memman_core.c
/* [プログラミング言語C] p225 を流用 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "memman.h"
#include "priv_memman_std.h"
#include "priv_memman_core.h"
#ifdef DEBUG
#include "priv_memman_debug.h" /* for debug */
#endif /* DEBUG */
#ifdef DEBUG_CHK_MEMLEAK
#include "priv_memman_debug.h" /* for debug */
#endif /* DEBUG */
#define NALLOC 5120 /* x86 では,sbrk(NALLOC * 8) が最小単位になる */
/* 極端に小さくする(2など)とデバッグ出来る */
typedef
struct _mmc_flist_t
{
Header base;
Header * freep;
}
mmc_flist_t;
static mmc_flist_t ** flist_tbl = NULL;
static void * mmc_alloc (int id, unsigned nbytes, void * functor);
static void mmc_free (int id, void * p, void * functor);
static void * add_freelist (int id, void * ap);
static Header * morecore (int id, unsigned nu, void * functor);
inline
static mmc_flist_t * mmc_get_flist(int id);
/* フリーリストテーブルの構築 */
void
Mmc_initialize(int resource_num)
{
int i = 0;
flist_tbl = malloc(sizeof(mmc_flist_t **) * resource_num);
for(i = 0; i < resource_num; i++)
{
flist_tbl[i] = malloc(sizeof(mmc_flist_t));
}
}
/* フリーノードをシステムに返却する */
static void
mmc_walk_flist_for_free(void)
{
;
}
/* フリーリストテーブルの破棄 */
void
Mmc_shutdown(int resource_num)
{
int i = 0;
for(i = 0; i < resource_num; i++)
{
free(flist_tbl[i]);
}
free(flist_tbl);
mmc_walk_flist_for_free(); /* フリーノードをシステムに返却する */
}
void
Mmc_free
(
int id,
void * p,
void * functor
)
{
(void) id;
mmc_free(id, p, functor);
}
/* メモリ解放関数。実際には free せずにフリーリストにつなぐだけ */
static void
mmc_free(int id, void * p, void * functor)
{
Header * bp = (Header *)p;
Header * hp = ((Header *)p)-1;
(void) functor;
/* robozushi10: need sem look */
MMAN_DBP("[id:%d]mmc_free(): mmc_free(%p)\n", id, p);
hp->s.ptr = NULL;
#ifdef DEBUG_CHK_MEMLEAK
Mmc_debug_rm_addr((unsigned)p);
#endif /* DEBUG_CHK_MEMLEAK */
MMAN_DBP("[id:%d]mmc_free(): call add_freelist(%p)\n", id, bp);
add_freelist(id, (void *)bp);
/* robozushi10: need sem unlook */
}
void *
Mmc_alloc
(
int id,
size_t size,
void * functor
)
{
return mmc_alloc(id, size, functor);
}
static void *
mmc_alloc(int id, unsigned nbytes, void * functor)
{
mmc_flist_t * flist = NULL;
Header * freep = NULL;
Header * prevp = NULL;
Header * base = NULL;
Header * p = NULL;
unsigned int nunits = ((nbytes + sizeof(Header)-1) / sizeof(Header)) + 1;
/* robozushi10: need sem look */
flist = mmc_get_flist(id);
freep = flist->freep;
prevp = freep;
base = &(flist->base);
if(prevp == NULL) /* 初回のアロケートの場合 */
{
base->s.ptr = base;
freep = base;
prevp = base;
base->s.size = 0;
}
/* 2回目以降は、前回 freep で記憶させておいたアドレスを辿ってフリーノードを探す */
/* フリーリストを辿って使用可能なフリーノードを探す */
MMAN_DBP("[id=%d]mmc_alloc(): mmc_alloc(%d bytes)\n", id, nbytes);
for(p = prevp->s.ptr; ; prevp=p, p=p->s.ptr)
{
MMAN_DBP
(
"[id:%d]mmc_alloc(): (p, p->s.ptr, p->s.size) = (%p, %p, %dblk)\n",
id, p, p->s.ptr, p->s.size
);
/* 見つかったフリーノードには要求分以上のブロックがあるか? */
if(p->s.size >= nunits)
{
if(p->s.size == nunits) /* 丁度、要求分だけフリーノードがあった */
{
MMAN_DBP("[id:%d]mmc_alloc(): found free-node just fit size(%d blk)\n", id, p->s.size);
/* フリーノードを全部使い切ったので,フリーリストから削除する */
prevp->s.ptr = p->s.ptr;
}
else /* フリーノードから nunitsブロック分拝借する */
{
/* フリーノードの末尾から使用する */
p->s.size -= nunits;
p += p->s.size;
p->s.size = nunits;
MMAN_DBP("[id:%d]mmc_alloc(): found free-node(%p, %dblk)\n", id, p, p->s.size);
}
/* p が現在ポイントしているよりも1つ前のフリーノードのアドレスを freep に *
* 記憶させておく. これにより,次に mmc_alloc() が呼ばれたときは freep で記憶 *
* させておいたフリーノードから探索を開始する *
* (フリーリストは循環構造になっているので全てのノード探索は可能) */
flist->freep = freep = prevp;
MMAN_DBP("[id:%d]mmc_alloc(): Remember freep=prevp=%p\n", id, freep);
MMAN_DBP("[id:%d]mmc_alloc(): return %p\n", id, (void *)(p+1));
#ifdef DEBUG_CHK_MEMLEAK
Mmc_debug_cp_addr((unsigned)(void *)(p+1));
#endif /* DEBUG_CHK_MEMLEAK */
/* robozushi10: need sem unlook */
return (void *)(p+1); /* ヘッダ部分を除いた先頭領域のアドレスを返す */
}
/* 初期状態では p は base をポイントしている => base.s.ptr=freep=prevp=&base */
if(p == freep)
{ /* フリーリストを一周した */
MMAN_DBP("[id:%d]mmc_alloc(): not found free-node\n", id);
MMAN_DBP("[id:%d]mmc_alloc(): call morecore(%d blk)\n", id, nunits);
flist->freep = freep;
#if 1
p = morecore(id, nunits, functor); /* フリーノードが無いのでシステムにメモリ要求 */
#else
#endif
if(p == NULL)
{
/* robozushi10: need sem unlook */
return NULL; /* メモリリーク!! 割り当て可能なメモリが無い */
}
}
} /* for loop end */
/* robozushi10: need sem unlook */
}
/* システム依存のメモリ要求関数(void * functor)を呼び出す */
static Header *
morecore(int id, unsigned nu, void * functor)
{
mmc_flist_t * flist = mmc_get_flist(id);
Header * freep = flist->freep;
char * cp = NULL;
Header * up = NULL;
void * (* p_func)(size_t) = functor;
/* 最低 NALLOC からブロックサイズを要求する */
nu = (nu < NALLOC) ? NALLOC : nu;
MMAN_DBP("[id:%d]morecore(): require %dblk, %dByte\n", id, nu, nu * sizeof(Header));
#if 0 /* sbrk() を使った場合 */
cp = (void *)sbrk(nu * sizeof(Header)); /* ヒープ領域を広げる */
if(cp == (char *)-1)
{
return NULL;
}
#else /* malloc で動作確認済み */
cp = (*p_func)(nu * sizeof(Header));
if(cp == NULL)
{
/* robozushi10: need sem unlook */
FATAL
(
"[id:%d]morecore(): alloc(func=%p)(size=%d)\n",
id,
p_func,
nu * sizeof(Header)
);
}
#endif
up = (Header *)cp; /* sbrk()の返り値 */
up->s.size = nu; /* 使用可能なブロックサイズ値 */
MMAN_DBP("[id:%d]morecore(): allocated new node (addr=%p, blk size=%d)\n", id, up, up->s.size);
MMAN_DBP("[id:%d]morecore(): call add_freelist(%p)\n", id, (void *)(up+1));
freep = add_freelist(id, (void *)(up+1)); /* ヘッダを除いたブロック領域の先頭アドレス */
return freep;
}
static void *
add_freelist(int id, void * ap)
{
mmc_flist_t * flist = mmc_get_flist(id);
Header * freep = flist->freep;
Header * bp = ((Header *)ap)-1;
Header * p = NULL;
/* ブレークポイントがフリーノード間に無ければループを継続 */
for(p = freep; !((p < bp) && (bp < p->s.ptr)); p = p->s.ptr)
{
if((p >= p->s.ptr) && (bp > p || bp < p->s.ptr))
{
/* リストを一周し,かつ,ブレークポイントがフリーノード間にある場合 */
/* なお、if(p >= p->s.ptr) だけではフリーリストの終端が見つけられない */
#ifdef DEBUG
if(bp > p)
{
MMAN_DBP("[id:%d]add_freelist(): bp(%p) > p(%p)\n", id, bp, p);
}
else if(bp < p->s.ptr)
{
MMAN_DBP("[id:%d]add_freelist(): bp(%p) < p->s.ptr(%p)\n", id, bp, p->s.ptr);
}
#endif
break;
}
}
if((bp + bp->s.size) == p->s.ptr)
{ /* 新たにノードを登録すると丁度既にあるノードと連結する場合,*
* 2つのノードを合併させる */
MMAN_DBP
(
"[id:%d]add_freelist(): bp->s.size(%d) + p->s.ptr->s.size(%d) = %d\n",
id,
bp->s.size,
p->s.ptr->s.size,
bp->s.size + p->s.ptr->s.size
);
bp->s.size += p->s.ptr->s.size;
bp->s.ptr = p->s.ptr->s.ptr;
}
else
{
bp->s.ptr = p->s.ptr;
MMAN_DBP("[id:%d]add_freelist(): link [new node(%p)] => [next node(%p)]\n", id, bp, bp->s.ptr);
}
if(p + p->s.size == bp)
{ /* 現在のフリーノードにブロック分(s.size)だけアドレスを進めると *
* sbrk()で確保した領域の先頭アドレスと同じになる場合, 現在のフ *
* リーリスト領域と bp 領域を併せてしまう */
p->s.size += bp->s.size;
p->s.ptr = bp->s.ptr;
}
else
{
p->s.ptr = bp;
MMAN_DBP("[id:%d]add_freelist(): link(2) [new node(%p)]\n", id, p->s.ptr);
}
flist->freep = freep = p;
return freep;
}
/* フリーリスト情報構造体を返す */
inline
static mmc_flist_t *
mmc_get_flist(int id)
{
return flist_tbl[id];
}
memman_debug.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "memman.h"
#include "priv_memman_std.h"
#include "priv_memman_core.h"
#include "priv_memman_debug.h"
static unsigned buf[DBG_BUFSIZ];
void
Mmc_debug_cp_addr(unsigned addr)
{
static int i = 0;
printf("hogepiyo\n");
i &= (DBG_BUFSIZ - 1); /* DBG_BUFSIZ を超えると上書きする */
buf[i++] = addr;
}
void
Mmc_debug_rm_addr(unsigned addr)
{
int i = 0;
//printf("hogepiyo2\n");
for(i = 0; i < DBG_BUFSIZ; i++)
{
if(buf[i] == addr)
{
buf[i] = 0;
}
}
}
void
Mmc_debug_dump_buf(void)
{
fprintf(stderr, "-------------------------\n");
fprintf(stderr, " memory leack check \n");
fprintf(stderr, "-------------------------\n");
int i = 0;
while(i != DBG_BUFSIZ)
{
i &= (DBG_BUFSIZ - 1);
if(buf[i] != 0)
{
printf("[%d] 0x%08x\n", i, buf[i]);
}
i++;
}
}
memman_resource.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>
#include "memman.h"
#include "priv_memman_std.h"
#include "priv_memman_core.h"
#include "priv_memman_debug.h"
/* メモリリソーステーブル *//* 型の定義は priv_memman_std.h にて */
#define MMAN_RESOURCE_BOTTOM \
{ -1, "", NULL, 0, 0, NULL, NULL, NULL, 0, 0, NULL}
mman_t
memrtbl[] =
{
/* [id] [key] [sem_id] [pshared] [sem val] [instance] [alloc func] [free func] [pool size] [rest size] [position]*/
{ 0, "main", NULL, 0, 0, NULL, NULL, NULL, 0, 0, NULL},
MMAN_RESOURCE_BOTTOM
};
int
Mman_get_rsrc_num(void)
{
return MMAN_KEYNUM(memrtbl);
}
priv_memman_core.h
#ifndef __PRIV_MEMMNAN_CORE_H__
#define __PRIV_MEMMNAN_CORE_H__
#include "memman.h"
#include "priv_memman_std.h"
#define ALIGNSIZE 4
typedef
struct header_t
{
union header * ptr;
unsigned int size;
}
header;
union header
{
header s;
unsigned char align[ALIGNSIZE];
};
typedef union header Header;
void * Mmc_alloc(int id, size_t size, void * functor);
void Mmc_free (int id, void * p, void * functor);
void Mmc_initialize(int resource_num);
void Mmc_shutdown (int resource_num);
#endif /* __PRIV_MEMMNAN_CORE_H__ */
priv_memman_debug.h
#ifndef __PRIV_MEMMAN_DEBUG_H__
#define __PRIV_MEMMAN_DEBUG_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "memman.h"
#include "priv_memman_std.h"
#include "priv_memman_core.h"
void Mmc_debug_cp_addr (unsigned addr);
void Mmc_debug_rm_addr (unsigned addr);
void Mmc_debug_dump_buf(void);
#endif /* __PRIV_MEMMAN_DEBUG_H__ */
priv_memman_std.h
#ifndef __PRIV_MEMMNAN_STD_H__
#define __PRIV_MEMMNAN_STD_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "memman.h"
#define MMAN_KEYNUM(a) (sizeof(a)/sizeof(*a))
#define MMAN_STRCMP(a, R, b) \
( \
(a) && (b) && (strlen(a) R strlen(b)) && (0 R strcmp(a, b)) \
)
#ifdef DEBUG
#define err_mesg(fmt, args...) \
{ \
fprintf \
( \
stderr, \
"[%s:%-4d] ERROR: " fmt, \
__FILE__, \
__LINE__, \
## args \
); \
}
#define FATAL(fmt, args...) \
{ \
fprintf \
( \
stderr, \
"[%s:%-4d] FATAL: " fmt, \
__FILE__, \
__LINE__, \
## args \
); \
exit(2); \
}
#define MMAN_DBP(fmt, args...) \
{ \
fprintf \
( \
stdout, \
"[%s:%-4d] DEBUG: " fmt, \
__FILE__, \
__LINE__, \
## args \
); \
}
#else /* DEBUG */
#define err_mesg(fmt, args...)
#define FATAL(fmt, args...)
#define MMAN_DBP(fmt, args...)
#endif /* DEBUG */
/* typedef を使った場合 */
typedef void * Fn_alloc(size_t size);
typedef void Fn_free (void * ptr);
/* メモリ管理構造体 */
typedef
struct mman_t
{
int id;
char key[8];
sem_t * sem;
int pshared;
unsigned int value;
mem_inst_t * instance;
#if 0 /* typedef を使った場合 */
Fn_alloc * alloc;
Fn_free * free;
#else
void * (* functor_alloc)(size_t size);
void (* functor_free) (void * ptr);
#endif
size_t pool_size;
size_t rest_size;
void * position;
}
mman_t;
extern int Mman_get_rsrc_num(void);
#endif /* __PRIV_MEMMNAN_STD_H__ */