ユーザー定義の malloc 置換

メモリー・サブシステム (malloccallocrealloc freemallopt、および mallinfo サブルーチン) は、 ユーザー独自の設計によるサブシステムに置き換えることができます。

注: C++ で書かれた置換メモリー・サブシステム は、C++ ライブラリー libC.alibc.a メモリー・サブシステム が使用されているため、サポートされません。

既存のメモリー・サブシステムは、スレッド化アプリケーションと 非スレッド化アプリケーションの両方で働きます。 ユーザー定義のメモリー・サブシステムは、スレッド化プロセスと非スレッド化プロセスの両方で働けるようにスレッド・セーフである必要があります。スレッド・セーフかどうかを検証する検査はないので、非スレッド・セーフのメモリー・モジュールがスレッド化アプリケーションにロードされた場合は、メモリーやデータが破壊される可能性があります。

ユーザー定義のメモリー・サブシステムの 32 ビットおよび 64 ビット・オブジェクトは、 mem32.o という 32 ビット共有オブジェクトと、 mem64.o という 64 ビット共有オブジェクトとともに、 アーカイブに入れる必要があります。

ユーザー共有オブジェクトは、以下のシンボルをエクスポートする必要があります。
  • __malloc__
  • __free__
  • __realloc__
  • __calloc__
  • __mallinfo__
  • __mallopt__
  • __malloc_init__
  • __malloc_prefork_lock__
  • __malloc_postfork_unlock__
ユーザー共有オブジェクトは、任意で以下のシンボルをエクスポートすることができます。
  • __malloc_start__
  • __posix_memalign__

これらのシンボルが存在しなくても、実行は停止しません。

関数の定義を、以下に示します。
void *__malloc__(size_t) :
この関数は、malloc サブルーチンに相当するユーザーの関数です。
void __free__(void *) :
この関数は、free サブルーチンに相当するユーザーの関数です。
void *__realloc__(void *, size_t) :
この関数は、realloc サブルーチンに相当するユーザーの関数です。
void *__calloc__(size_t, size_t) :
この関数は、calloc サブルーチンに相当するユーザーの関数です。
int __mallopt__(int, int) :
この関数は、mallopt サブルーチンに相当するユーザーの関数です。
struct mallinfo __mallinfo__() :
この関数は、mallinfo サブルーチンに相当するユーザーの関数です。
void __malloc_start__()
この関数は、他のユーザー定義 malloc エントリー・ポイントが呼び出される前に一度呼び出されます。
void __posix_memalign__()
この関数は、posix_memalign サブルーチンに相当するユーザーの関数です。 このシンボルが存在しなくても、実行は停止しません。ただし、posix_memalign サブルーチンに対して生成される呼び出しにより予期しない結果が生じます。
以下の関数は、マルチスレッド環境のユーザー定義のメモリー・サブシステムを管理するために、スレッド・サブシステムが使用します。これらは、アプリケーションまたはユーザー定義モジュール (あるいはその両方) が libpthreads.a にバインドされている場合にのみ呼び出されます。ユーザー定義サブシステムがスレッド・セーフでなく、libpthreads.a にバインドされていなくても、これらの関数を定義してエクスポートする必要があります。そうしない場合、オブジェクトがロードされません。
void __malloc_init__(void)
pthread 初期化ルーチンによって呼び出される。 この関数は、スレッド化ユーザー・メモリー・サブシステム を初期化するために使用されます。 ほとんどの場合、これには、ある形式のロック・データの作成や初期化などがあります。 ユーザー定義のメモリー・サブシステム・モジュールが libpthreads.a にバインドされていても、ユーザー定義のメモリー・サブシステムは、__malloc_init__() の呼び出し前に働く必要があります
void __malloc_prefork_lock__(void)
fork サブルーチンの呼び出し時に pthread によって呼び出される。 この関数を使用すると、メモリー・サブシステムは fork() の前の 既知の状態にあり、fork() が戻るまでその状態を維持します。 ほとんど場合、これには、メモリー・サブシステム・ロックの獲得などがあります。
void __malloc_postfork_unlock__(void)
fork サブルーチンの呼び出し時に pthread によって呼び出される。 この関数は、fork の後に、メモリー・サブシステムを親と子で 使用できるようにするために使用されます。 この関数は、__malloc_prefork_lock__ が 行った作業を元に戻す必要があります。 ほとんど場合、これには、メモリー・サブシステム・ロックの解除などがあります。
関数は、すべて共有モジュールからエクスポートする必要があります。 アーカイブの中にある 32 ビットと 64 ビットのインプリメンテーションに対し、 別個のモジュールが存在していなければなりません。 例:
  • mem.exp モジュール:
    __malloc__
    __free__
    __realloc__
    __calloc__
    __mallopt__
    __mallinfo__
    __malloc_init__
    __malloc_prefork_lock__
    __malloc_postfork_unlock__
    __malloc_start__
  • mem_functions32.o モジュール:

    必要な 32 ビット関数のすべてが入っている。

  • mem_functions64.o モジュール:

    必要な 64 ビット関数のすべてが入っている。

以下の例は、共有オブジェクトを作成する場合の例です。 -lpthreads パラメーターは、オブジェクトが pthread 関数を使用する場合にのみ必要です。
  • 32 ビット共有オブジェクトの作成:
    ld -b32 -m -o mem32.o mem_functions32.o ¥
    -bE:mem.exp ¥
    -bM:SRE -lpthreads -lc
  • 64 ビット共有オブジェクトの作成:
    ld -b64 -m -o mem64.o mem_functions64.o ¥
    -bE:mem.exp ¥
    -bM:SRE -lpthreads -lc
  • アーカイブの作成 (共有オブジェクト名は、32 ビット・オブジェクトの場合 は mem32.o、64 ビット・オブジェクトの場合 は mem64.o でなければならない):
     ar -X32_64 -r archive_name mem32.o mem64.o

ユーザー定義のメモリー・サブシステムの使用可能化

ユーザー定義のメモリー・サブシステムは、以下のいずれかを使用して使用可能にできます。
  • MALLOCTYPE 環境変数
  • ユーザーのアプリケーション内の _malloc_user_defined_name グローバル変数。

MALLOCTYPE 環境変数を使用するには、 ユーザー定義のメモリー・サブシステムの入ったアーカイブの指定は、MALLOCTYPEuser:archive_name に設定して行います。 この場合、archive_name はアプリケーションの libpath 内か、または LIBPATH 環境変数で指定したパスにあるようにします。

_malloc_user_defined_name グローバル変数を使うには、ユーザー・アプリケーションは次のようにグローバル変数を宣言する必要があります。
char *_malloc_user_defined_name="archive_name"

この場合、archive_name は、アプリケーションの libpath か、または LIBPATH 環境変数で指定したパスにある必要があります。

注:
  1. setuid アプリケーションが実行されると、LIBPATH 環境変数は無視されるので、アーカイブはアプリケーションの libpath にある必要があります。
  2. archive_name には、 パス情報を入れることはできません。
  3. MALLOCTYPE 環境変数と _malloc_user_defined_name グローバル変数の両方を使用して archive_name を指定すると、 MALLOCTYPE で指定されたアーカイブ名が、 _malloc_user_defined_name で指定したアーカイブ名よりも優先されます。

32 ビットと 64 ビットに関する考慮事項

アーカイブに 32 ビットと 64 ビットの両方の共有オブジェクトが入っていない場合で、 かつユーザー定義のメモリー・サブシステムが MALLOCTYPE 環境変数 を用いて使用可能になった場合は、32 ビット・アプリケーションからの 64 ビット・プロセス の実行と、64 ビット・アプリケーションからの 32 ビット・プロセスの実行で問題が生じます。 新しいプロセスは、exec サブルーチンを用いて作成される際、 コール側アプリケーションの環境を受け継ぎます。 つまり、MALLOCTYPE 環境変数は継承され、新規プロセスはユーザー定義メモリー・サブシステムのロードを試みます。 このタイプのプログラムに関するアーカイブ・メンバーがなければ、 ロードは失敗し、新しいプロセスは終了します。

スレッドに関する考慮事項

提供されている関数はすべて、マルチスレッド環境で働く必要があります。モジュールが libpthreads.a にリンクされている場合であっても、 __malloc__() は、少なくとも __malloc_init__() が呼び出され、pthreads が初期化される前に動く必要があります。 これが必要なのは、pthread の初期化には、__malloc_init__() の呼び出し前に malloc() が必要なためです。

提供されているメモリー関数はすべて、 スレッド化環境と非スレッド化環境の両方で働く必要があります。 __malloc__() 関数 は、__malloc_init__() への依存関係を持たずに完全に 実行できなければなりません (すなわち、__malloc__() は、 最初 __malloc_init__() がまだ実行していない ことを前提とする必要があります。) __malloc_init__() が完了すると、__malloc__() は、__malloc_init__() によって行われた作業に依存することができます。 これが必要なのは、pthread 初期化は、__malloc_init__() の 呼び出し前に malloc() を使用するためです。

不要なスレッド関連ルーチンが呼び出されることを防ぐために、以下の変数が備えられています。
  • __multi_threaded 変数は、スレッドが作成されるまではゼロで、 スレッドが作成されると非ゼロになり、そのプロセスではゼロにリセットされることはありません。
  • __n_pthreads 変数は pthread が初期化されるまでは -1 で、初期化されると 1 に設定されます。 それ以後、この変数はアクティブ・スレッドの数のカウントになります。

例:

__malloc__()pthread_mutex_lock() を使用する場合、コードは以下のようになります。

if (__multi_threaded)
pthread_mutex_lock(mutexptr);

/* ..... work ....... */

if (__multi_threaded)
pthread_mutex_unlock(mutexptr);

この例では、pthread が完全に初期化されるまで、__malloc__() による pthread 関数の実行が阻止されます。 2 番目のスレッドが開始するまでロックが行われないので、 単一スレッド・アプリケーションも加速されます。

制限

C++ で書かれたメモリー・サブシステムは、libC.a の初期化の問題と依存関係、 ならびに libc.a メモリー・サブシステムの理由で、サポートされません。

setlocale サブルーチンが malloc() を用いて ロケールを初期化するため、エラー・メッセージは変換されません。 malloc() が失敗すると、 setlocale サブルーチンは終了できず、アプリケーションは依然 POSIX ロケール内にあるため、表示されるのはデフォルトの英語メッセージのみです。

静的に作成された既存のプログラムは、再コンパイルしないと、ユーザー定義のメモリー・サブシステムを使用できません。

エラー・レポート作成

malloc サブルーチンが最初に呼び出されるときに、MALLOCTYPE 環境変数で指定されたアーカイブの 32 ビットもしくは 64 ビット・オブジェクトがロードされます。 ロードが失敗すると、メッセージが表示され、アプリケーションは終了します。 ロードが成功すると、必要なシンボルがすべて存在しているかどうかの確認が試みられます。 欠落しているシンボルがあると、アプリケーションは終了し、 欠落シンボルのリストが表示されます。