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版)も含まれている。

2013年12月3日火曜日

bash-completion

softies projectの開発環境は Solarisと Ubuntuを使用しているが、先日、Ubuntuを 10.04→ 12.04に変えたところ、何やらいろいろと拙いことが発生し始めた。

makeが通らない

ちょっとした実験をする Main.cというソースがあったとしよう。たとえば次のようなもの。
#include 

int main() {
 printf("Hello, world.\n");
 return 0;
}

これだけなら、わざわざ makefile(や build.xml, pom.xml)を作らなくとも、
$ make Main
cc     Main.c   -o Main

の様にビルドが通る。これはデフォルトで定義されているサフィックスルールだけで何とかなる場合だからだ。

しかし、Ubuntu 12.04にしたところ、
$ make Main
make: *** ターゲット 'Main' を make するルールがありません. 中止.

と表示されてしまう。

makeコマンドで補完ができない

まだ可笑しい所がある。
シェルでmake Mのあと、Tabキーを押しても補完されない。
make Main.cが出ることを期待していたのだが。
使っているシェルが悪いのかと psしてみたが、bashである。
試しに echoとか、lsとか、catとかのあとに Mに続けて Tabキーを押すとちゃんと補完される。
Tabキーの接触不良でもないようだ。
また誰か余計な機能を発明したようだ。

理由は bash-completion

ネットで調べてみると出てきたのは bash-completionという機能。
makeや gitなど、使用するコマンドによって補完の推測方法を変えているようだ。
makeでは、makefileのターゲットを調べ、あるものしか入力できない。
makefile無しの場合のターゲットの推測までは頭が回ってないようだ。
中途半端なヤツ。
bas-completionが有効になってるかどうかは、次のように complete -pを実行して completeルールがゾロゾロと出てくるかどうかで確かめることができる。
$ complete -p
 :
 :
complete -F _route route
complete -o default -o dirnames -F _mount mount
complete -F _badblocks badblocks
complete -F _filedir_xspec lyx
complete -F _filedir_xspec rgvim
complete -F _filedir_xspec timidity
complete -F _filedir_xspec dvitype
complete -F _filedir_xspec dviselect
complete -F _filedir_xspec xdvi
complete -o default -F _longopt uniq
complete -F _root_command sudo
complete -F _command tsocks
complete -a unalias


bash-completionを無効にする

この機能を無効にするには、
sudo apt-get remove bash-completion

とやってアンインストールすれば良いのだが、それだと他のユーザまで影響してしまうので、つぎのようにしてローカルにアンインストールすれば良い。
$ complete -r

アンインストールがうまく行っていれば、
$ complete -p

でなにも出てこない。

bash-completionを無効にすると、makefileにないターゲットや makefile自体が無い状態での補完ができるようになる。

なお、makeでは無効にしたいが、gitでは有効にしておきたいということもできるようだ。



先輩、暮らす図って何ですか?