2014年9月28日日曜日

Ubuntuに H8/300H用の gccをインストールしてみる。

Ubuntu 14.04に H8/300H用の gccをインストールしてみた。

H8/300Hは Softiesプロジェクトとは直接の関係は無い。
わざわざ直接の関係は無いと言う事は、間接の関係があると察していただけたと思う。
そもそも、Softiesプロジェクトは組み込み開発のテスト環境を提供するのが始まりだった。特に、単体テストフレームワークの CUnitがそれだ。そしてその CUnitは自社製の "ra7taj"という仮想マシンをテストするためのものであった。ra7tajの開発を 2年間一時停止して Softiesプロジェクトを進めてきた。CUnitの開発が今年の盆休みに実用域に達してひと段落したので、今月から ra7tajの開発を再開した。
それがなんで H8/300Hと関係があるのか??

ra7tajは不安定ながらも Solarisや Linux上で動作しているので、いよいよ次のステップではターゲットに組み込んで使えるようにすることになるが、そのターゲットが H8/300Hなのである。
今時なんで ARMとかじゃなくてH8/300Hかというと、…長くなるので止めとくが、CPUパワーもメモリも「そこそこ」しか無い環境で動かしてみたかったからである。
欲を言えば、8051くらいでも動作させたいが、ちょっとメモリが足りなさすぎるので見送りとなった。実を言うと、もう少し速くターゲット環境で動かしたかったが、2011年に欲を出してコンパクション可能なコレクタにしたら、それまで動作していたところがあちこちと調子悪くなってしまい、現在デバッグ中である。実際にターゲットを動かすのはいつになるやら。 ビルド環境を作るなんて気が早いかもしれない。
それに CUnitで単体テストやるのが楽しすぎて…。

CUnit作る前はどうやって ra7tajテストしていたかというと、Javaのプログラムから JNI経由で関数を呼び出していた。 Heapの状況を Swingで視覚化したりして大変便利だったのだが、ra7taj自体に JNI互換の関数を提供しはじめたら、テスト対象の ra7tajの JNIと テストドライバである JDKの JNIのシンボルが衝突して破綻してしまった。

なお、Softiesはオープンソースにしたいが、使用している一部のライブラリのライセンスの都合で未だ公開できる状況ではない。
ライセンス問題をクリアするまでもう少し掛かりそうである。

インストール

話が脱線してしまったので、元に戻そう。

インストールといっても、apt-getコマンドを使うだけである。
$sudo apt-get update

した後、
$ sudo apt-get install gcc-h8300-hms
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
以下の特別パッケージがインストールされます:
  binutils-h8300-hms
提案パッケージ:
  binutils-doc gcc-doc
以下のパッケージが新たにインストールされます:
  binutils-h8300-hms gcc-h8300-hms
アップグレード: 0 個、新規インストール: 2 個、削除: 0 個、保留: 5 個。
5,554 kB のアーカイブを取得する必要があります。
この操作後に追加で 14.9 MB のディスク容量が消費されます。
続行しますか? [Y/n] y
取得:1 http://jp.archive.ubuntu.com/ubuntu/ trusty/universe binutils-h8300-hms
 amd64 2.16.1-9ubuntu1 [2,125 kB]
取得:2 http://jp.archive.ubuntu.com/ubuntu/ trusty/universe gcc-h8300-hms amd64
 1:3.4.6+dfsg2-1ubuntu1 [3,429 kB]
5,554 kB を 14秒 で取得しました (381 kB/s)                                     
以前に未選択のパッケージ binutils-h8300-hms を選択しています。
(データベースを読み込んでいます ... 現在 328030 個のファイルとディレクトリが
インストールされています。)
Preparing to unpack .../binutils-h8300-hms_2.16.1-9ubuntu1_amd64.deb ...
Unpacking binutils-h8300-hms (2.16.1-9ubuntu1) ...
以前に未選択のパッケージ gcc-h8300-hms を選択しています。
Preparing to unpack .../gcc-h8300-hms_1%3a3.4.6+dfsg2-1ubuntu1_amd64.deb ...
Unpacking gcc-h8300-hms (1:3.4.6+dfsg2-1ubuntu1) ...
Processing triggers for man-db (2.6.7.1-1) ...
binutils-h8300-hms (2.16.1-9ubuntu1) を設定しています ...
gcc-h8300-hms (1:3.4.6+dfsg2-1ubuntu1) を設定しています ...
$

gcc本体だけでなく、binutilsも一緒にインストールされた。

gccのバージョンは最近の 4.8.xとかでなくて少し古い。

コマンドが認識されるかいくつか試してみる。
$ h8300-hms-gcc --version
h8300-hms-gcc (GCC) 3.4.6
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$

$ h8300-hms-objdump --version
GNU objdump 2.16.1 Debian GNU/Linux
Copyright 2005 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License.  This program has absolutely no warranty.
$

スタートアップルーチンは準備してないので、Hello, world.とかを試すのは今度にしよう。

2014年9月10日水曜日

言語Cで synchronizedを実現する(その1)

Javaの synchronized構文は便利だ。
オブジェクトをロックし、クリチカルセクションを実行したあと、確実にロックを解除するすることが言語でサポートされている。

そのような機構がない言語の場合、つぎのように記述するだろう。
lock();
// critical section
unlock();


クリチカルセクションが 1~2行程度ならよいが、長くなると何が起こるか分からない。
うっかり、この中で
if (hasError)
 return errorCode;


などとやってしまうとロックが解除されず、処理がとまってしまうか、再びロックしようとして多重ロックしてしまうかも知れない。

今回のチャレンジは、次のように関数を記述することだ。

void synchronized function(Something this) {
 // critical section
}


Javaでは synchronizedなメソッドのほかに、synchronizedブロックが記述できるが、ここでは関数だけを対象とする。

synchronizedな関数に入るときオブジェクトをロックし、出るときにアンロックする。
これを実現するための課題は、
  1. 関数に入るときと出る時に処理を行なえること。
  2. 関数に synchronized属性を持たせること。
  3. 関数が synchronizedを持って意いるか判断可能なこと。
  4. ロックするオブジェクトを認識できること。

1.関数に入るときと出る時に処理を行なう

これは以前の記事で取り上げたことのある、gcc拡張の __cyg_profile_func_enter, __cyg_profile_func_exitを使えそうである。
実験ではオブジェクトをロックせず、下記のようにトレース出力をする。
void NO_INSTRUMENT __cyg_profile_func_enter(void *function, void *caller) {
        if (isSynchronized(function))
                printf("enter synchronized function %p\n", function);
        else
                printf("enter %p\n", function);
}

void NO_INSTRUMENT __cyg_profile_func_exit(void *function, void *caller) {
        if (isSynchronized(function))
                printf("exit synchronized function %p\n", function);
        else
                printf("exit %p\n", function);
}


なお、NO_INSTRUMENTはコードを見やすくするための下記のようなマクロである。
#define NO_INSTRUMENT __attribute__((no_instrument_function))

2.関数に synchronized属性を持たせる

これはちょっと難しい。

上記の例にある、 isSynchronized(function)をどうやって実現するか。

関数に任意の属性を持たせたい。
関数とは別管理のルックアップテーブルを持たせれば簡単そうだが、別管理が面倒くさい。
関数が synchronizedかどうか人間が知りたいとき、いちいち管理テーブルを見ないとならない。
void synchronized function...のような記述できるほうが管理しやすい。
そのためには Javaのアノテーションのような機能が必要になる。
しかし、言語Cにはアノテーションは無い。 gcc拡張を探したがそれに近いものは無い。

諦め掛けていたが、トンでもないアイデアを思いついた。
synchronized用のメモリセクションを作り、そこに配置した関数を synchronizedとみなすことにしよう。

synchronizedセクションを作って関数を配置するには、gcc拡張の __attribute__構文が使える。
次のようなマクロを定義すれば、あとは関数に synchronizedを付けるだけ。
#define synchronized __attribute__((section("synchronized")))
gcc以外にもソースコード上にセクションを明記できるものがあるが、#pragma構文を使うものは残念ながら #defineすることはできない。

早速書いてみよう。 使い分けできるのが分かるよう synchronizedでない普通の関数も作っておく。

Sub.h(主要部分だけ)
extern void sub1();
extern synchronized void sub2();


Sub.c(主要部分だけ)
void sub1() {
 printf("sub1 called.\n");
}

void synchronized sub2() {
 printf("sub2 called.\n");
}


これをビルドしてできた Sub.oを逆アセンブルしてみると、ちゃんと synchronizedセクションに対応づけられている。
$ objdump -d Sub.o

Sub.o:     file format elf32-i386


Disassembly of section .text:

00000000 :
   0: 55                    push   %ebp
   1: 89 e5                 mov    %esp,%ebp
   3: 83 ec 18              sub    $0x18,%esp
   6: 8b 45 04              mov    0x4(%ebp),%eax
   9: 89 44 24 04           mov    %eax,0x4(%esp)
   d: c7 04 24 00 00 00 00  movl   $0x0,(%esp)
  14: e8 fc ff ff ff        call   15 
  19: c7 04 24 00 00 00 00  movl   $0x0,(%esp)
  20: e8 fc ff ff ff        call   21 
  25: 8b 45 04              mov    0x4(%ebp),%eax
  28: 89 44 24 04           mov    %eax,0x4(%esp)
  2c: c7 04 24 00 00 00 00  movl   $0x0,(%esp)
  33: e8 fc ff ff ff        call   34 
  38: c9                    leave  
  39: c3                    ret    

Disassembly of section synchronized:

00000000 :
   0: 55                    push   %ebp
   1: 89 e5                 mov    %esp,%ebp
   3: 83 ec 18              sub    $0x18,%esp
   6: 8b 45 04              mov    0x4(%ebp),%eax
   9: 89 44 24 04           mov    %eax,0x4(%esp)
   d: c7 04 24 00 00 00 00  movl   $0x0,(%esp)
  14: e8 fc ff ff ff        call   15 
  19: c7 04 24 0d 00 00 00  movl   $0xd,(%esp)
  20: e8 fc ff ff ff        call   21 
  25: 8b 45 04              mov    0x4(%ebp),%eax
  28: 89 44 24 04           mov    %eax,0x4(%esp)
  2c: c7 04 24 00 00 00 00  movl   $0x0,(%esp)
  33: e8 fc ff ff ff        call   34 
  38: c9                    leave  
  39: c3                    ret 

因みに synchronizedでない普通の関数は .textセクション。

3.関数が synchronizedを持って意いるか判断

そして、isSynchronized関数はつぎの通り。
int NO_INSTRUMENT isSynchronized(void* function) {
 extern char __start_synchronized;
 extern char __stop_synchronized;

 return (function >= (void*)&__start_synchronized)
  && (function < (void*)&__stop_synchronized);
}

gccでは、__start_, __stop_の後にセクション名をつけたものが、それぞれセクションの先頭と後端のアドレスを示している。 これを実行時に関数アドレスと比較することで、そのセクションの中の関数かどうか判断できるというわけである。

あとは次のようなプログラムで sub1()と sub2()を実際に呼び出してみる。 動作が確認しやすいよう、synchronizedセクションの先頭、後端アドレスと、sub1(), sub2()のアドレスも出力しておき、つづいてsub1()と sub2()を実際に呼び出す。

int NO_INSTRUMENT main(int argc, char** argv) {
 extern char __start_synchronized;
 extern char __stop_synchronized;

 printf("[synchronized section]\n");
 printf("start: %p\n", &__start_synchronized);
 printf("end: %p\n", &__stop_synchronized);
 printf("\n");

 printf("[function address]\n");
 printf("sub1: %p\n", sub1);
 printf("sub2: %p\n", sub2);
 printf("\n");

 printf("[call functions]\n");
 sub1();
 printf("\n");
 sub2();
 return 0;
}
結果は次のように、synchronizedとそうでないものがちゃんと区別できることを確認できた。
$ ./Main
[synchronized section]
start: 0x80486ec
end: 0x8048726

[function address]
sub1: 0x8048600
sub2: 0x80486ec

[call functions]
enter 0x8048600
sub1 called.
exit 0x8048600

enter synchronized function 0x80486ec
sub2 called.
exit synchronized function 0x80486ec

なお、Sub.h, Sub.cの両方で sub2()に synchronizedを記述したが、Sub.h, Sub.cのいづれか一方だけに記述しても結果は同じになる。

この手法は、synchronized以外にも使えるかも知れない。 なんとも馬鹿げたやり方だが。
※本プロジェクトの名称 softiesの先頭の sは stupidの略ですから、何でもアリです。 お許しください。

2014年7月4日金曜日

Ubuntuを 14.04にアップデート

Softiesプロジェクトでは、Open Solarisと Ubuntuを使用しているが、10-2から 12.04と 14.04にアップデートした。

ホスト OSを Windows 7 Professionalとし、VirtualBox 4.2.10の上で動かす。

ところが、OSインストール後、Guest Additionsを設定しようとすると、エラーが発生。

「Building the shared folder support module ...fail!」

これでは、ウインドウサイズが小さいままで使いにくい。

Guest Additionsの設定手順を間違えたと思い、コンソールから手動でスクリプトを起動してみたりいろいろ試してみたが何度やっても同じ。

試しに、VirtualBoxを 4.3.12にしたら、 Guest Additionsの設定が成功した。

と思ったら、今度は『仮想マシンの状態を保存』にして VirtualBoxを閉じようとすると、「Oracle VM VirtualBox Managerは動作を停止しました」のエラーが発生。

「問題が発生したため、プログラムが正しく動作しなくなりました。 プログラムは閉じられ、解決策がある場合は Windowsから通知されます。」とメッセージが表示される。(12.04, 14.04とも)

サスペンドできないのはこれまた大変不便。 VirtualBox停止させるまえに必ずシャットダウンしなければならない。

VirtualBoxのディスプレイ設定で、3Dアクセラレーションを有効化を外したら、エラーが出なくなった。

VMwareでもいろいろ問題起こすが、開発環境をアップデートするたびに何かしらの試行錯誤が強いられるのはしんどい。

2014年5月19日月曜日

Sun Microsystems, Inc. 同窓会

いよいよ今週末 May 24, 2014の 6:00pm-11:00pm、マウンテンビューで Alumni Reunionが開催される。

参加費用は $160。

残念ながら申し込みは 5月 1日に締め切られているようだ。

Sun Microsystems Reunion Announcement
Top Ten Signs That You Miss Sun Microsystems

我々が最も影響を受けたのは、Digital Reserch Inc., Netscape Communications Corporationそして Sun Microsystems, Inc.だった。
そして、それらの輝きと興奮は今も失われることは無い。

2014年4月30日水曜日

pthreadの条件変数

今日は決算報告書を 作成して 顧問の税理士さんに作成してもらって確認したあと、銀行、役所、税務署を 徘徊して 廻って国税(法人税、復興特別法人税、消費税)と県税、市税を納付してきた。
今期は若干の設備投資が発生したため、利益は少なかった。 というより、前の期での設備更新を先延ばしにしたためその期は利益が出て、逆に今期に更新分が偏ってしまった。
設備投資は計画的に行わなければ資金の運用にも、生産性にも問題が生じてしまう。 しっかりやらないと。

夕方には帰社できたが取引先は休みに入っているので、自社のプロジェクトに時間を割くことにした。

softies projectとは別に、Unix上で動作する T-Kernelもどき(サブセット)を作ることにする。
T-Kernelを扱う業務では簡単なモックを作ってテストしているが、それとは別にシミュレータも作りたくなった。
既にシミュレータはあるはずなので新たに作るのは時間の無駄になるのだが、今回の目的はシミュレーションというよりも T-Kernelの仕様を理解することにある。


主成功シナリヲ

まず、1st iterationでは、下記の関数に対して主成功シナリヲ(最も基本的な使い方)だけを実装して単体テストしてみると、それなりにうまくいった。

tk_cre_mtx  tk_del_tsk  tk_ext_tsk  tk_ref_mtx tk_slp_tsk
tk_cre_tsk  tk_dly_tsk  tk_get_tid  tk_ref_tsk tk_sta_tsk
tk_del_mtx  tk_exd_tsk  tk_loc_mtx  tk_rel_wai tk_unl_mtx
taskは pthreadに、mutexは pthread_mutexに単純に対応させた。

代替シナリヲ

2st iterationでは、代替シナリヲ(主成功シナリヲではない別の使い方)を実装して単体テストしてみる。

tk_dly_tskを使用しているテストが通らなくなった。たとえば tk_dly_tsk(2000U)としてあるので 2秒経過後に抜けてきて欲しいのだが、10ミリ秒そこそこで抜けてきてしまう。
10ミリ秒というのは単体テストのフレームワークのオーバヘッドも含んでいるので、もう少し短い時間かも知れない。
いづれにしても期待する動作になってない。

tk_dly_tskの主成功シナリヲでは、引数で指定した時間を経過した後関数から復帰するだけだったので、単純な usleep(3C)で遅延を実装していた。

tk_dly_tskの代替シナリヲでは、他タスクから tk_rel_waiを呼ばれると、SUSPEND状態が解除されてエラーコード E_RLWAIを返さなければならない。
SUSPEND状態を抜けるには他にも tk_ter_tskもあるし、tk_slp_tskで SUSPENDして tk_wup_tskで解除というのもある。

このように待ち合わせと解除の方法が多岐にわたるため、何の要因により SUSPENDを解除しようとしているのかを記憶しなければならない。

usleepではシグナルを使うことにより中断させることはできるが、複数のタスクから条件変数の操作を安全に行うことはできない。
そこで、mutexおよび条件変数を使用することにした。


バグの原因

時間待ちを行うために pthread_cond_timedwait(3T)を使用したが、問題はそこにあった。

この関数は時間待ちをするものではなく、時刻を待つものである。
そしてその時刻とは 1970年 1月 1日 0時 0分 0秒 GMTを期限とする相対値である。 多くのマニュアルには、abstimeと書かれている。

これを見落として、2st iterationで最初に書いたコードでは単純に待ち時間を与えたものを引数に使ったものだから、2秒間待つつもりが、1970年 1月 1日 0時 0分 2秒 GMTまで待つことを指定したことになる。
1970年というのは読者の中にはまだ生まれてない方もいることだろう。そのくらい大昔である。
pthread_cont_timedwaitを呼び出しても僅かなオーバヘッドが生ずるだけで、ほとんど直ちに復帰してくるのである。

バグの影響

それでも組み込みの開発でありがちな、時計が設定されていない状態では偶然それっぽい時間になるかもしれなかった。
そんな出鱈目な状態でテストをパスさせてしまうと、市場で不具合になることだろう。
シミュレーションでよかった。

そうなると、過去に開発したものが怪しくなってきた。

幸い、請け負ったものの中には pthread_cond_timedwait(3T)を使ったものが無いことが確認できた。

softies projectでは、lwd_lang_Objectクラスの waitAsMillis関数で使っている。
しかし、ちゃんと現在時刻を取得し、待ち時間を加えて使っている。
エラー処理の違いのため、lwd_lang_Objectをそのまま使用することはできないが、参考にすべきだったかも知れない。


教訓

  • ちゃんとマニュアル読め
  • 正常に動くコードを参照しろ

参考文献

  • ビル・ルイス+ダニエル・バーグ著『Pスレッドプログラミング』岩本信一訳 プレンティスホール 1999年
  • David R.Butenhof著『POSIXスレッドプログラミング』油井 尊訳 アジソン・ウェスレイ 1998年

2014年1月2日木曜日

mallocライブラリ その1 (alternative malloc library 1)

現代のプログラミングに於いてメモリの動的割り当ては欠かせない機能の一つである。
リソースは「要る物を」「要る時に」「要る分だけ」無駄なく割り当てることは重要だと考える。

近代的な言語にはガベージコレクタを標準で備えるようになっているが、言語 Cでのメモリ管理はプログラマに任せられている。
我々は動的メモリ管理のために mallocや free関数を使用するが、どうしても間違いが生じてしまう。

  • 未割り当て領域へのアクセス
  • 使用中の領域を解放/解放済み領域へのアクセス
  • 二重解放
  • 解放漏れ(メモリリーク)
  • オーバラン/アンダーラン

softiesプロジェクトでは、これらの問題を検出するための LWD mallocライブラリを開発している。
この用途には valgrindというメモリの監視以外にも使える使いやすいツールが既にあるが、Solarisには非対応で、動作も若干鈍調である。
我々はより軽量で Solarisでも使用できることを目標に置いている。

使用法

このライブラリはメモリを大量に消費する。
そのため、専ら小規模な単体テストに使用されることを想定している。

静的ライブラリ libmalloc.aをテスト対象のプログラムにリンクして使用する。
(都合が悪ければライブラリ名称は任意に変更して良い)

libmalloc.aがホームディレクトリの下のlibにあり、Test.cからデバッグ版の Testをビルドする例を以下に示す。
 $ cc -g -o Test -L ~/lib -lmalloc Test.c

Makefileを使用する場合には、下記の定義を含めればよい。
CFLAGS = -g
LFLAGS = -L ~/lib
LDLIBS = -lmalloc


正常な使用例

まず、メモリを割り当て、それを解放した場合の例を見てみよう。

#include <malloc.h>
#include <stdio.h>

int main() {
 char* bytes1 = (char*)malloc(5);
 char* bytes2 = (char*)malloc(8);
 free(bytes1);
 free(bytes2);
 return 0;
}

このプログラムは 5バイトと 8バイトの領域を割り当て、その両方を解放する Test1.cである。

$ ./Test1
HEAP REPORT
  SUMMARY
   total allocated: 13(bytes)  2
   memory leak: 0(bytes)  0

SUMMARYには、total allocatedに 2回の割り当てで合計 13バイト割り当て、memory leakに解放漏れが無いことが示されている。
(bytes)の後ろの値は領域の数を表している。

メモリリークの検出例

つぎは、メモリの解放を忘れた場合の例である。
#include <malloc.h>
#include <stdio.h>

int main() {
 char* bytes1 = (char*)malloc(5);
 char* bytes2 = (char*)malloc(8);
 free(bytes2);
 return 0;
}

先ほどと同じ 5バイトと 8バイトの割り当てを行った後、8バイトの方のみ解放する。

$ ./Test2
HEAP REPORT
  SUMMARY
   total allocated: 13(bytes)  2
   memory leak: 5(bytes)  1

  DETAIL OF MEMORY LEAK
 no.     memory size(byte) created by
   1 0xfae00000          5

SUMMARYには、total allocatedに 2回の割り当てで合計 13バイト割り当て、memory leakに そのうちの 1回分の 5バイトが解放漏れを起こしたことが示されている。
さらに DETAIL OF MEMORY LEAKでは、5バイトの解放漏れ領域のアドレスが 0xfea0000であることを示している。

解放漏れが複数ある場合には、その数分だけ 1行ずつ表示される。

created byの欄が空欄なのは許して欲しい。
libdwarfを使用して割り当てたコードのソースファイルとその行番号を表示するためのものだが、現在機能しない。

未割り当て領域へのアクセス検出例

メモリを割り当てていない領域にアクセスする例を示す。
#include <malloc.h>
#include <stdio.h>

int main() {
 char* bytes = (char*)malloc(5);
 char* p = bytes - 1;
 char c = *p;
 free(bytes);
 return 0;
}

このプログラムは 5バイトの領域を割り当てるが、それよりも前のアドレスから読み出しを行おうとする。

$ ./Test3
not allocated memory access at 0xfadfffff from (0xfeee01bf)

HEAP REPORT
  SUMMARY
   total allocated: 5(bytes)  1
   memory leak: 5(bytes)  1

  DETAIL OF MEMORY LEAK
 no.     memory size(byte) created by
   1 0xfae00000          5
Abort (core dumped)

HEAPレポートよりも前にエラーメッセージとアクセスしたアドレス、およびそのとき実行していたコード付近のアドレスが表示される。

最後は Abortして終了する。コアダンプするかどうかは環境設定による。

この例では、割り当てた 5バイトよりも 1バイト小さいアドレスにアクセスしていてアンダーランが検出できたかのように見えるが、そうではない。
直前に別の用途のために割り当てた領域があれば、エラーは検出できない。

注:コアダンプする設定の場合、ダンプに時間が掛かる分 Abortが表示されてシェルに復帰するまで時間を要する。

二重解放の検出例

既に解放済みの領域をもう一度解放しようとしたらどうなるか。
#include <malloc.h>
#include <stdio.h>

int main() {
 char* bytes = (char*)malloc(5);
 free(bytes);
 free(bytes);
 return 0;
}

このプログラムでは、5バイトの領域を割り当てたあと、2回つづけて解放を行おうとする。

$ ./Test4
bad memory release.(already released.)

HEAP REPORT
  SUMMARY
   total allocated: 5(bytes)  1
   memory leak: 0(bytes)  0
Abort (core dumped)

HEAP REPORTよりも前にエラーメッセージが表示され、Abortする。

制約

下記のような制約がある。
  • 現バージョンでは、アンダーラン、オーバランの検出はできない。
  • MMUのメモリ保護機構を必要とする。
  • メモリ割り当て回数の上限は 256 * 1024回。(変更可)
  • ヒープのサイズは 64MB。(変更可)
  • 同じヒープサイズでも通常より早くメモリが枯渇する。
  • main関数が呼ばれる以前に別スレッドが起動された場合、動作は保証されない。

ライセンス (license)

このライブラリは MITライセンスで公開されている。

GPLとのマルチライセンスが計画されていたが、手続きの都合により保留され、とりあえず MITライセンス単独でのリリースとなった。

ダウンロード (download)(下载)

ライブラリのソースは下記からダウンロードできる。

lwd_malloc_1.0.tgz

Solarisと Linux用の静的ライブラリ(いづれも Intel 32bit版)も含まれている。