2009年3月25日水曜日

外部コマンドを実行し、その実行結果をパイプで受け取る方法

早い話が、perlで、open("command |");というのをLimiboでやりたいのです。
ネットで調べてもずばりの情報が無く試行錯誤しました。
間違っているかもしれませんが、とりあえず現時点での解を示したいと思います。

なお、どう書く.orgにもタイムリーなお題が出ていたので、投稿しておきました。
http://ja.doukaku.org/242/

まずは外部コマンドの呼び出しです。
*.disをモジュールとしてロードしinitを呼ぶ、というのがよくある方法のようです。

hdl := Command "/dis/ls.dis"; # ls の例

その後、

hdl->init(ctx, nil); # ctxはメイン関数の第一引数を渡せばよい、第二引数はコマンドの引数リスト

としてやればコマンドが実行される。

spawn hdl->init(ctx, args);

といった感じで別プロセスでの実行も出来るようだ。

この方法とは別に、Shのsystemメソッドを使う方法もある。

sh := load Sys Sys->PATH;
sh->system(ctx, "command");

とするだけでよさそう。簡単。

次にどちらの方法でも良いが、立ち上げた外部プロセスとのパイプライン通信を考える。

Sys->pipeメソッドを使うとパイプからオープン済みのファイルデスクリプタが取得できる。
つまり、標準入出力をファイルI/Oに置き換えることが可能。

fds := array[2] of ref Sys->FD;
sys->pipe(fds);

とすると、fdsという配列が得られ、2つのパイプが得られる。
fds[0]に書き込むとfds[1]からそのデータが読まれ、
fds[1]に書き込むとfds[0]からそのデータが読めるようだ。

なので、外部プロセス実行前に標準出力をどちらかのパイプに結び付けてやり、
もう一方のパイプから読み出せば外部プロセスの出力結果が得られる。
それにはSys->dupを使用する。
Sys->dupの第一引数は結びつけるファイルデスクリプタ、第二引数は結びつける標準入出力の番号(0: stdin, 1: stdout, 2: stderr)。

以上をコードにすると、

sys = load Sys Sys->PATH; # sysのロード
c := load Command "/dis/ls.dis"; # 外部コマンドのロード

fds := array[2] of ref Sys->FD;
sys->pipe(fds); # パイプの取得

sys->dup(fds[0].fd, 1); # パイプ0に標準出力を出す

spawn c->init(ctx, nil); # コマンド実行


buf := array[64] of byte;
n := sys->read(fds[1], buf, len buf); # パイプ1から読み込むとコマンドの出力が得られる



上記コードはエラー処理がまったく入っていないのでよろしくない。

2009年3月21日土曜日

SSHを試みるも失敗

limboでのSSHの実装があるそうです。
http://www.ueber.net/code/r/ssh

コンパイルは問題なさそう。

が、実行に失敗しました。
まずはsshkeysとかいうファイルがないとかで失敗。

ソースをいじってサーバー認証をスキップしたところ、
nousernameという別のエラー。

どこかに認証情報を書いておかなければならないのかも。

とりあえず保留。

2009年3月19日木曜日

JIT

InfernoはJITに対応しているそうです。
just in timeコンパイル。
中間コードを解釈しながら実行するのではなく、起動時にコンパイルして
実行するもの(間違ってたらすみません)。

Infernoも対応していると各所で書かれているのですが、はて?どう使うものか。

で、調べたところ、おそらく次の手順でいけるはず。
実行時に切り替えられるっぽい。

echo 1 > /dev/jit

とするとON。

echo 0 > /dev/jit

とするとOFF。簡単。
現在の状態を見たければ、
cat /dev/jit

これであっているか確証は無いのですが、
ちょっと動作速度を計ってみました。

OFFのとき
; echo 0 > /dev/jit
; time ls
0.002l 0.031r 0.033t

ONのとき
; echo 1 > /dev/jit
; time ls
0.004l 0.027r 0.031t

ONにするとLoad Timeが増えて、Real Timeが減る。
で、この条件ではTotal Timeは減る。
なんかそれっぽく動いてますね。

/dev/jitに関するソースコードを見ようと思ったのですが、見つからず。
あれ?

2009年3月15日日曜日

macでinferno

mac osxでinfernoを動かしてみて分かったことを。

・インストール
どうやってインストールしたか忘れた。
オフィシャルサイトからツリーを持ってきて、osx 用のバイナリパッケージを
加えたんだったかも。
google codeから持っていった方が良いと思う。

・カーネルビルド
セルフコンパイルはまだやっていない。やるべし。
クロスコンパイルは特にハマった点はなし。

・wm/wm

マウスボタンが一つしかないのでタッチパッドでacmeは無理かと思いましたが、いけそうです。

左クリック: 普通にクリック
中クリック: option+クリック
右クリック: 指2本でクリック(OSの機能だと思うが)

ちなみにUSBスクロールマウスは普通に3ボタンマウスとして使えました。

Infernoでリモートのファイルシステムをマウント

懸案だったファイルシステムのマウントです。
listen, mountを使った方法はなにげにできていましたが、
認証を利用した方法はできていませんでした。

参考にしたサイトは
http://my.opera.com/csant/blog/show.dml/152654
です。
このページによると、インストールドキュメントに書いてあるとのこと。
まさかそんな所に情報があるとは。

・目的
リモートのInferno(serverとする)のファイルシステムを認証付きで
もう一方のInferno(clientとする)にマウントする。

・手順

- サーバー初回のみ

認証用のパスワード作成
% auth/createsignerkey [名前]
※名前、は何かのIDのようだが、なんなんでしょう。ユーザー名っぽいのをいれてみたが。

認証サービス起動?
% svc/auth
初回でキーを設定するようなので、任意のパスワードを入力

ユーザー作成
% auth/changelogin ユーザー
secretには秘密のパスワードを設定。
expiresには有効期限を。
※expireの書き込みでエラーが発生。無理やり回避した(後述)。

サーバーキー作成
% getauthinfo default
signer: localhost
user: ユーザー名
password: パスワード。たぶんさっきのsecret
save in file: yes

- サーバー運用時

ネットワークサービス起動
% svc/net

認証サービス起動
% svc/auth
初回の時に設定したキーを入力するはず

- クライアント毎回

謎の処理(たぶん接続する時に必須のサービス起動)
% ndb/cs

認証
% getauthinfo tcp!サーバーのIP
signer: サーバーのIP
user: ユーザー
password: secret
save in file: yes (保存すると次回からgetauthinfoしなくて良さそう)

マウント
% mount tcp!サーバーのIP /n/remote
tcp!いらないみたい。

・バッドノウハウ

先ほどの、changeloginでexpireが書き込めない件、力業で乗り切った。

手順
auth/changelogin ユーザー
expiresにpermanentを指定して、とりあえず正常終了させる
 (ただし、expireの書き込みには失敗)

/mnt/keys/ユーザー/expireに適当な数値文字列を書き保存

もう一度auth/changelogin ユーザー
expiresで正しいexpireを指定。たぶん正しい数値がファイルにかかれるはず。

2009年3月11日水曜日

Limboでネットワークプログラミング

なさけないことにARM上でinfernoは未だ挫折中です。
気分を変えてlimboでプログラミングをすることにしました。

ネットワークプログラミングの基本を学びました。
TCPソケット通信のやり方がなんとなく分かりましたので、公開します。

ネットで調べてもいまいちよく分からなかった所ですが、
httpdのソースを見ることでなんとなく分かりました。
付属のソースを取っ掛かりにするのはおすすめです。

以下ソースコードです。
これは、tcp通信のスループットを測るためのソフトを意図しています。
ttcpという既存のソフトウェアとの相互通信ができ、
ゆくゆくは完全互換のソフトになるのが目標です。
まだ作りかけですが、tcpでセッションを張り、データの受信はできています。

やってることは、
1. announce (ポートのopen?select?)
2. listen (着信待ち)
3. remoteのopen、read (相手のIPアドレス、ポートの取得、必須ではない)
4. dataのopen、read (データ受信)
です。

実行
- Inferno
このソフトを起動すると、待ち状態になるのでそのまま放置。

- 通信相手(Windowsとかunixとか)
ttcp またはwsttcp(Windows)を持ってきて
ttcp -t [InfernoのIPアドレス]
とする

こうすると通信相手からInfernoに対してtcpのセッションを張り、
データの通信が行われます。


# usage: ttcp [-t|-r]
# -t: send (not implemented)
# -r: receive

implement ttcp;

include "sys.m";
include "draw.m";

sys: Sys;

ttcp: module{
init: fn(ctx: ref Draw->Context, argv: list of string);
};

init(ctx: ref Draw->Context, argv: list of string)
{
buf :=array[64] of byte;

sys = load Sys Sys->PATH;

(ok, c):=sys->announce("tcp!*!5001");

if(ok < 0){
exit;
}

(ok2, nc):=sys->listen(c);

if(ok2 < 0){
exit;
}

l:=sys->open(nc.dir+"/remote", sys->OREAD);
n:=sys->read(l, buf, len buf);

sys->print("%s", string buf[0:n]);

b:=sys->open(nc.dir+"/data", sys->OREAD);
n=sys->read(b, buf, len buf);
sys->print("%s", string buf[0:n]);
}

※書きかけかつ詳細を理解していないので正直よろしくないコードです。
 各関数の意味を調べた上で書き直す予定ですのでご容赦を。


いい感じです。
直感的に書けるのでバグになりにくいかもしれませんね。
複数セッションをサポートする場合はスレッドを作りチャンネルでセッション情報を
渡せば良いのかもしれません。

ソースコード共有サイト(なのかな?)どう書く.org で細々とコードを書いているのですが、
最近あるブログにて私のエントリーを引用していただきました。
結構緊張しますが、励みにもなります。
どう書く.orgを勝手に自分用のコード置き場にしてしまっていましたが(テンプレート代わりに自分の投稿を使ってたりします。雛形を覚えられないのです。)、
少しは他の方の役に立てればうれしいです。

・今後の予定
ttcpを完成させ、スループットを評価する
グリッドコンピューティングを試してみる

2009年3月7日土曜日

audioについて

armadilloへのポーティングはタイマー割り込みが入るところまではいけましたが、
その際のプリエンプション処理でおかしくなるらしく、頓挫中です。へこむー

audioについて試してみました。
どうやらon MAC, on Linuxではaudioデバイスをサポートしていないようで、
on Windows, on FreeBSD では試せそうです。

emu/の下に各ホストOS用のemuのソースがありますが、
audio.cがあり、かつemuファイルに/dev/audioをサポートする旨書かれているのは
Win, BSDのみでした。
BSDがいけるならOSXにもポーティングできないものか?

それはさておき、Inferno日記を参考に、音を出してみました。
Windows XP上のemuで試しました。

(参考: http://www.ntl.co.jp/2/product/inferno/beginners/008.html いつもお世話になっております)

・オーディオデバイスのバインド

bind -a '#A' /dev

とすると/dev/audio, /dev/audioctlが現れました。
bindの意味はよくわかっていませんが。

・データの用意

付属のプレーヤーではwavファイルそのままでは再生できず、変換の必要があるそうです。
/appl/cmdに変換プログラムのソースがあるようで
cd /appl/cmd
limbo wav2iaf.b
として、生成したwav2iaf.disをどっかにコピー。
ひとまず/tmpにコピーしておいた。

wavを/tmpにおいて
wav2iaf test.wav > test.iaf
などと変換。
wavファイルはCDからEACというソフトで取り出しました。
EACおすすめ。CCCDもいける。

・再生
auplay test.iaf
とすると音が鳴りました。すばらしい!

ちなみにテスト音源はTOTOのFalling in Between。なかなか良い。