2010年8月10日火曜日

squeeze amd64 環境内で i386 の環境を schrootで作成

開発環境を squeeze に入れ替えた。
build は i386 なので、schroot の環境を作成


$ sudo aptitude install cdebootstrap schroot



$ sudo cdebootstrap --arch=i386 --flavour=build squeeze squeeze-i386 \ http://ftp.jp.debian.org/debian



$ sudo groupadd pnuts

自分をpnuts グループに追加


[sarge-i386]
# Optional. The chroot with alias 'default' is used if you just type
# 'schroot' without the -c option.
aliases=testing,default
# Whatever you like
description=Debian sarge
# Relative to what was /mnt until a moment ago
location=/sarge-i386
# Below here is standard for all the chroots
# Adjust according to the space available and size of builds you'll do
lvm-snapshot-options=--size 2G
device=/dev/デバイス
type=lvm-snapshot
priority=3
groups=pnuts,root
root-groups=pnuts,root
source-groups=pnuts,root
source-root-groups=root


$ sudo schroot -c squeeze-i386-source
(squeeze-i386-source)root@debian:~# apt-get upgrade
(squeeze-i386-source)root@debian:~# apt-get install devscripts vim-tiny sudo \ fakeroot aptitude build-essential
(squeeze-i386-source)root@debian:~# apt-get clean


ここから、pnut 用の環境作成

デフォルトの設定をコピー

$ cd /etc/schroot
$ sudo cp -a defaults pnut

schroot.conf を編集して、

script-config=pnut/config

を追加。
pnut/config を編集

FSTAB="/etc/schroot/pnut/fstab"
COPYFILES="/etc/schroot/pnut/copyfiles"


pnut/fstab に次の行を追加

/mnt/src /mnt/src none rw,rbind 0 0

(適当にbind でマウントする.)

pnut/copyfiles も適当に追加

2010年3月13日土曜日

Amazon AWS また 最初から

新しいノートパソコンがきたので、AWS用の環境設定のやり直し

ElasticFox を再インストール

2010年1月10日日曜日

erlangの非同期ドライバーでのタームの扱い

非同期ドライバーは非同期スレッドで使いたくてやっているわけだが、
erl_interfaceは使えない。

すべて、eiライブラリだけでやりとりする必要がある。よって、ETERMも使えない。
この結論にいたるまでずいぶんと無駄をした。

それで、前回のコードをeiを使用して書いてみた。

まずは、erlang側のコード

注意点や前回との違いは

erl_ddll:load_driver(".", SharedLib) はspawn してから行う
open_portは binary でオープンする(use_stdioがあるとデバックに便利)
データを渡すときは、term_to_binary、受けとるときは、binary_to_termを使う
サンプルは、整数を扱っているのでリストではなくタプルで渡す。
(サンプルの場合、リストで渡すと、C側で-1と255の区別ができない)


start(SharedLib) ->
spawn(?MODULE, init, [SharedLib]).

init(SharedLib) ->
register(complex, self()),
erl_ddll:load_driver(".", SharedLib),
Port = open_port({spawn_driver, SharedLib}, [binary, use_stdio]),
loop(Port).

stop() ->
complex ! stop.

foo(X) ->
call_port({foo, X}).
bar(Y) ->
call_port({bar, Y}).

call_port(Msg) ->
complex ! {call, self(), Msg},
receive
{complex, Result} ->
Result
end.

loop(Port) ->
receive
{call, Caller, Msg} ->
%Port ! {self(), {command, encode(Msg)}},
Port ! {self(), {command, term_to_binary(encode(Msg))}},
receive
{Port, {data, Data}} ->
Caller ! {complex, decode(Data)}
end,
loop(Port);
stop ->decode([Int]) -> IC側のコードnt;
decode(Res) when is_binary(Res)->
binary_to_term(Res).

Port ! {self(), close},
receive
{Port, closed} ->
exit(normal)
end;
{'EXIT', Port, Reason} ->C側のコード
io:format("~p ~n", [Reason]),
exit(port_terminated)
end.

encode({foo, X}) -> {1, X};
encode({bar, Y}) -> {2, Y}.

decode([Int]) -> Int;
decode(Res) when is_binary(Res)->
binary_to_term(Res).


examplebar.cも変更

C側のコード

long bar(int a) {
return a+1;
}

long foo(int b) {
return b*2;
}

ドライバーの方は抜粋。
いろいろ大変だったが、何とか動いた。
ei_decode_XXX を行う度にindexが書き換わる。


...

typedef struct {
char fn;
int arg;
long res;
} our_async_data;

...

static void example_drv_foobar(void * async_data)
{
our_async_data* d = (our_async_data*)async_data;

if (d->fn == 1) {
d->res = foo(d->arg);
} else if (d->fn == 2) {
d->res = bar(d->arg);
}else{
d->res = 0;
}
}

static void example_drv_error(void * async_data){
our_async_data* d = (our_async_data*)async_data;
d->res = 255;
}

static void example_drv_output(ErlDrvData handle, char* buff, int bufflen)
{
example_data* d = (example_data*)handle;
our_async_data* a = (our_async_data*)malloc(sizeof(our_async_data));
int i, ver, size, type, arity;
int val;
long long_val;
unsigned char str[3];
// indexの初期化を忘れないように
i = 0;
if(0 != ei_decode_version(buff, &i, &ver))printf("error\n\r");
// printf("version is %d.\n\r", ver);
ei_get_type(buff, &i, &type, &size);
printf("term type is %d,(%c).\n\r", type,type);
printf("size is %d.\n\r", size);

if( type == ERL_SMALL_TUPLE_EXT ){
ei_decode_tuple_header(buff, &i, &arity);
printf("list size is %d .\n\r", arity);
ei_get_type(buff, &i, &type, &size);
printf("i1 type is %d,(%c).\n\r", type,type);
if( type == ERL_SMALL_INTEGER_EXT){
ei_decode_char(buff, &i, str);
printf("function is %d\n\r",str[0]);
a->fn = str[0];
ei_get_type(buff, &i, &type, &size);
printf("i2 type is %d,(%c).\n\r", type,type);
if( type == ERL_SMALL_INTEGER_EXT){
ei_decode_char(buff, &i, str);
a->arg = (unsigned int)*str;
printf("arg is %d\n\r",a->arg);
driver_async(d->port, NULL, example_drv_foobar, a, free);
}else if( type == ERL_INTEGER_EXT){
ei_decode_long(buff, &i, &val);
a->arg = val;
printf("arg is %d\n\r",val);

driver_async(d->port, NULL, example_drv_foobar, a, free);
}else{
driver_async(d->port, NULL, example_drv_error, a, free);
}
}else{
driver_async(d->port, NULL, example_drv_error, a, free);
}
}

static void ready_async(ErlDrvData handle, ErlDrvThreadData async_data)
{
ei_x_buff x_buff;
ei_x_new_with_version(&x_buff);
example_data* d = (example_data*)handle;
our_async_data* a = (our_async_data*)async_data;

if( a->res <>res >= 0 ){
ei_x_encode_char(&x_buff, a->res);
}else{
ei_x_encode_long(&x_buff, a->res);
}

driver_output(d->port, x_buff.buff, x_buff.index);
/* not thread safe */
// driver_output_term(d->port, bin, sizeof(bin)/sizeof(bin[0]));
ei_x_free(&x_buff);

free(a);
}

...

2009年12月26日土曜日

erlangのR13B03から erl_nif が追加されたみたいだが、まだ、experimental
http://www.erlang.org/doc/man/erl_nif.html

これとは違うのかな?
http://www.erlang.org/eeps/eep-0007.html

2009年11月29日日曜日

erlangの非同期ドライバーのコードを追う

http://groups.google.co.jp/group/simple_index/web/091128--index23 のコピペと続き

1. 初期化
1-1. DRIVER_INIT - erl_ddll:load_driver/2

DRIVER_INIT は erl_ddll:load_driver/2 を読んだときに、初期化のために呼ばれる。ライブラリの関数のエントリポイントを返す。
DRIVER_INIT(example_drv) /* must match name in driver_entry */
{
return &example_driver_entry;
}


ErlDrvEntryには、関数ポインタがセットされている。

* init: load_driverで呼び出される。
* start: open_portで呼び出される。
* stop: close_port で呼び出される。
* output: データをportに送ったときに呼ばれる。

erlang側では Port ! {self(), {command, Data}}, または port_command/2 を使う。
-----
This is called when an erlang process has sent data to the port. The data is pointed to by buf, and is len bytes. Data is sent to the port with Port ! {self(), {command, Data}}, or with port_command/2. Depending on how the port was opened, it should be either a list of integers 0...255 or a binary. See open_port/3 and port_command/2.
----

* ready_async: C側から driver_asyncを実行するとready_asyncに結果が渡される。

参考:
http://www.erlang.org/doc/man/driver_entry.html

1-2. start - open_port

以下の例では、spawn したプロセス内でportをオープンし、ループに入っている。
Portは startで作成したErlDrvDataのhandleを保持している。

init(SharedLib) ->
register(complex, self()),
Port = open_port({spawn, SharedLib}, []),
loop(Port).

2.関数呼び出し

サンプルだと static void example_drv_output(ErlDrvData handle, char* buff, int bufflen) に

Port ! {self(), {command, Data}}

からメッセージを渡す。

C側では Data をbuffにセットしてoutputにセットされた関数が呼び出される。

static void example_drv_output(ErlDrvData handle, char* buff, int bufflen)
{
example_data* d = (example_data*)handle;
our_async_data* a = (our_async_data*)malloc(sizeof(our_async_data));
a->fn = buff[0];
a->arg = buff[1];
driver_async(d->port, NULL, example_drv_foobar, a, free);
}


最後にhandleをexample_dataにキャストし、portを取り出し、実行する関数と引数をセットしてdriver_asyncを実行している。

drive_asyncについて詳細はこちら
http://www.erlang.org/doc/man/erl_driver.html

long driver_async (ErlDrvPort port, unsigned int* key, void (*async_invoke)(void*), void* async_data, void (*async_free)(void*))

これは、erlangのエミュレータとは別のthreadで実行される。erlangはデフォルトではスレッドプールなしで起動されるので、スレッドプールの数を指定するときは、+Aの引数でスレッド数を指定してエミュレータを起動する。

key がNULLだとスレッドはラウンドロビンで使われるが、keyを指定すると同じkeyの場合は同じスレッドが使用される。

これの、async_invokeで指定された関数が終了すると、ready_async にセットした関数が呼び出される。
async_freeはasyncの処理がキャンセルされたときに呼び出される。

ready_asyncにはhandleとdataが渡されるのでそれぞれキャストしてportと結果をそれぞれ取り出しdriver_outputで結果をerlangに返す。


static void ready_async(ErlDrvData handle, ErlDrvThreadData async_data)
{
example_data* d = (example_data*)handle;
our_async_data* a = (our_async_data*)async_data;

driver_output(d->port, &(a->res), 1);
free(a);
}


---------
以下はerlang側のコード

-module(complex5).
-export([start/1, stop/0, init/1]).
-export([foo/1, bar/1]).

start(SharedLib) ->
case erl_ddll:load_driver(".", SharedLib) of
ok -> ok;
{error, already_loaded} -> ok;
_ -> exit({error, could_not_load_driver})
end,
spawn(?MODULE, init, [SharedLib]).

init(SharedLib) ->
register(complex, self()),
Port = open_port({spawn, SharedLib}, []),
loop(Port).

stop() ->
complex ! stop.

foo(X) ->
call_port({foo, X}).
bar(Y) ->
call_port({bar, Y}).

call_port(Msg) ->
complex ! {call, self(), Msg},
receive
{complex, Result} ->
Result
end.

loop(Port) ->
receive
{call, Caller, Msg} ->
Port ! {self(), {command, encode(Msg)}},
receive
{Port, {data, Data}} ->
Caller ! {complex, decode(Data)}
end,
loop(Port);
stop ->
Port ! {self(), close},
receive
{Port, closed} ->
exit(normal)
end;
{'EXIT', Port, Reason} ->
io:format("~p ~n", [Reason]),
exit(port_terminated)
end.

encode({foo, X}) -> [1, X];
encode({bar, Y}) -> [2, Y].

decode([Int]) -> Int.

2009年10月12日月曜日

IPnutsでKVM

ここの続き
http://groups.google.co.jp/group/simple_index/web/090926-index21


x86dではなくて v86dの誤り。

パッケージを作った。

# lrp_load -ab v86d

# mkdir /disk
# mount /dev/sdb1 /disk
# cd /disk/kvm
# kvm -k ja -hda winxp.img -boot c -m 512

fbsetでframebufferの解像度も変えられる。

# lrp_load -ab fbset
# fbset -xres 1024 -yres 768 -depth 24

いつもどおり設定変更
# save_conf

windowsは、起動してから解像度を変更できた。

2009年7月1日水曜日

シェルのスクリプトに--dry-runのオプションを追加

ロングオプションをシェルに追加するときのメモ

--dry-runのオプションだけつけたかったのだが、getoptに' -o ""'がないとちゃんと動作しなかった。


#!/bin/sh

args=`getopt -o "" -l dry-run -- $@`
DRYRUN=

eval set -- "$args"

until test $1 = "--"
do
case $1 in
--dry-run)
DRYRUN="--dry-run"
;;
esac
shift
done

if test "$DRYRUN" ;then
echo "starting XXXXX(y/N):"
else
echo "dry-run XXXXX(y/N):"
fi

read a
if [ "x$a" = xy -o "x$a" = xY ] ;then
:
else
exit
fi

...(実際の動作)