まぁ、validator はなんとか動いた。
validator に与える仕様は HTML の form そのものとしたので、 たいした検査は出来ないのだが、 仕様をあらためて書かなくていいのはいいかも知れない。
session について考える。
ふむ。(validator で form を parse するために) HTree を必須にしてしまったので、 URL rewriting を扱ってもいいかも。
pty から tty 側のプロセスにどうやって signal を送るか調べる。
「詳解 UNIX プログラミング」には、TIOCSIG ないし TIOCSIGNAL で出来るとあるが、 Linux には見当たらない。
おや?
... そーか。SIGINT などは、pty 側から ^C を 1byte 送れば発生できるのか。
% google-count 毛深い機能 2 毛深い機能
% google-count 'CGI インストール' 'CGI 設置' 363 CGI インストール 29700 CGI 設置
webapp で、WEBrick も扱うようにしてみた。
でも、servlet を定義するファイルをどこかに置くとそれが load されるという形の標準的な方法がないようで、自前で定義せざるを得なかった。 このため、サーバ側に require をひとつ追加しないと動かなくて残念。
どうも Content-Type を設定するのが面倒臭い。
... というわけで出力の内容から auto detection することにした。 ついでに、XML 宣言があってそれに encoding が入っていれば、charset もつける。
backtrace をログに出すかクライアントに返すかの選択を(するための情報のひとつを) 環境変数で指定しようかと思ったのだが、 suEXEC が任意の環境変数は通してくれないためうまくいかなかった。
WebApp でサイト全体を構成することを考えてみる。
とりあえず WebApp で書いたものを WEBrick servlet として使い、 WEBrick で / に mount するというのはできた。
webapp/webrick-servlet.rb に ($0 == __FILE__ でくくって) そのコードをしこんだので、 次のようにして起動できる。
% ruby .../webapp/webrick-servlet.rb .../xxx.webrick
こうすると、URL には xxx.webrick というファイル名は出て来なくなり、 http://host/path_info?query というように、abs_path 全体が path_info になる。
webrick-servlet.rb という名前はあまり良くないか。
それはそれとして、 Apache でサイト全体を単一の CGI で構成することは出来たっけ?
/foo/bar/xxx.cgi が実行可能な CGI スクリプトだとして、
ScriptAlias / "/foo/bar/xxx.cgi/"
とすれば動くようだ。
でも、これって意図された動作なのかなぁ?
あとは CGI じゃなくて、FastCGI や mod_ruby だとどうだろう?
FastCGI は次のようにして出来た。
<Directory "/home/src/apache/ht"> Options ExecCGI SetHandler fastcgi-script </Directory> Alias / "/home/src/apache/ht/ht.fcgi/"
これで動くんなら mod_ruby でも同じだろうと思って次のを試したが、 どうも動かない。 なんでだろ?
<Directory "/home/src/apache/ht"> Options ExecCGI SetHandler ruby-object RubyRequire apache/ruby-run RubyHandler Apache::RubyRun.instance </Directory> Alias / "/home/src/apache/ht/ht.rbx/"
気のせいだった。mod_ruby もそれで動いた。
ScriptAlias / ... という書き方を他にしている人はいるだろうか?
だが、残念ながら google で / を探すことは出来ない。
しばらく考えて、"ScriptAlias usr" で探すことを思いつく。
うが。 Apache のドキュメントに書いてあるではないか。
では、Alias / ... という書き方は他で行なわれているか。
探してみると、Using MoinMoin with apache + mod_python というのがあるか?
% google-count {そもそも,もそもそ}
1620000 そもそも
21500 もそもそ
% google-count まそまそ みそみそ むそむそ めそめそ もそもそ 75 まそまそ 848 みそみそ 23 むそむそ 8070 めそめそ 21500 もそもそ
Gauche の dynamic-wind と例外についてちょっと調べる。
% bin/gosh
gosh> (define k2 ())
k2
gosh> (define (tst) 1)
tst
gosh> (call/cc
(lambda (k)
(dynamic-wind
(lambda ()
(display "a")
(tst))
(lambda ()
(call/cc
(lambda (kk)
(set! k2 kk)
(display "b"))))
(lambda ()
(display "c")))))
abc#<undef>
gosh> (k2)
ac#<undef>
gosh> (define (tst) (raise 'ex))
tst
gosh> (k2)
*** ERROR: unhandled exception: ex
Stack Trace:
_______________________________________
acgosh>
ふむ。in-guard で例外が起きると対応する out-guard が実行されるか。
... う、SRFI 18 に載ってるのか?
gosh> (define (tst) 1)
tst
gosh> (define k2 '())
k2
gosh> (dynamic-wind
(lambda ()
(write '(ig))
(tst))
(lambda ()
(dynamic-wind
(lambda () (write '(ig2)))
(lambda ()
(call/cc
(lambda (k)
(set! k2 k)
1)))
(lambda () (write '(og2)))))
(lambda ()
(write '(og))))
(ig)(ig2)(og2)(og)1
gosh> (define (tst) (raise '(ex)))
tst
gosh> (k2)
*** ERROR: unhandled exception: (ex)
Stack Trace:
_______________________________________
(ig)(og2)(og)gosh>
ふむ。継続で突入しようとしたときに途中の in-guard で例外が起きると、 内側の out-guard も起動されるようだ。
gosh> (dynamic-wind
(lambda () (write '(ig1)))
(lambda ()
(dynamic-wind
(lambda () (write '(ig2)) (raise '(ex)))
(lambda ()
(dynamic-wind
(lambda () (write '(ig3)))
(lambda () 1)
(lambda () (write '(og3)))))
(lambda () (write '(og2)))))
(lambda ()
(write '(og1))))
*** ERROR: unhandled exception: (ex)
Stack Trace:
_______________________________________
(ig1)(ig2)(og1)gosh>
それに対し、call/cc を使わず普通に入っていくときには、 in-guard の例外は外側の out-guard だけが実行される、と。
まぁ、変だとは感じてましたが、バグでしたか。
ついでに、out-guard での例外も試してみる。
% gosh
gosh> (define kk #f)
kk
gosh> (dynamic-wind
(lambda () (write '(i1)))
(lambda ()
(dynamic-wind
(lambda () (write '(i2)))
(lambda ()
(dynamic-wind
(lambda () (write '(i3)))
(lambda () (call/cc (lambda (k) (set! kk k))))
(lambda () (write '(o3)))))
(lambda () (write '(o2)))))
(lambda () (write '(o1))))
(i1)(i2)(i3)(o3)(o2)(o1)#<subr continuation>
gosh> (dynamic-wind
(lambda () (write '(i4)))
(lambda ()
(dynamic-wind
(lambda () (write '(i5)))
(lambda ()
(dynamic-wind
(lambda () (write '(i6)))
(lambda ()
(kk))
(lambda () (write '(o6)))))
(lambda () (write '(o5)) (raise 'ex))))
(lambda () (write '(o4))))
*** ERROR: unhandled exception: ex
Stack Trace:
_______________________________________
(i4)(i5)(i6)(o6)(o5)(o3)(o2)(o1)gosh>
継続に入っている(継続を作ったところの外側の) out-guard が実行される。
おや、例外を起こしたところの外側の out-guard (o4) が出て来ないな。
call/cc を間違えて callcc と書いたら... おや、shell まで戻ってしまう?
% gosh gosh> (dynamic-wind (lambda () #f) (lambda () (raise 'ex1)) (lambda () (raise 'ex2))) *** ERROR: unhandled exception: ex1 Stack Trace: _______________________________________ *** ERROR: unhandled exception: ex2 Stack Trace: _______________________________________ zsh: exit 70 gosh %
ふむ。例外発生中の out-guard でさらに例外を起こすとプロセスが死ぬか。
new PickAxe をくれるというので、もらっておくことにする。
(いつ届くのかは知らない)
ふと、freelist の長さを測るメソッドを書いてみた。
Index: gc.c
===================================================================
RCS file: /src/ruby/gc.c,v
retrieving revision 1.185
diff -u -p -r1.185 gc.c
--- gc.c 24 Sep 2004 05:53:42 -0000 1.185
+++ gc.c 25 Sep 2004 02:45:49 -0000
@ -1406,6 +1406,20 @@ rb_gc_start()
return Qnil;
}
+VALUE
+numfree()
+{
+ RVALUE *f = freelist;
+ long num = 0;
+
+ while (f != 0) {
+ f = f->as.free.next;
+ num += 1;
+ }
+ printf("numfree:%ld\n", num);
+ return Qnil;
+}
+
void
Init_stack(addr)
VALUE *addr;
@ -1894,6 +1908,7 @@ Init_GC()
rb_define_module_function(rb_mObSpace, "undefine_finalizer", undefine_final, 1);
rb_define_module_function(rb_mObSpace, "_id2ref", id2ref, 1);
+ rb_define_module_function(rb_mObSpace, "numfree", numfree, 0);
rb_gc_register_address(&rb_mObSpace);
rb_global_variable(&finalizers);
ついでに、malloc_increase, malloc_limit も出す。
--- gc.c 2004-09-24 14:53:20.000000000 +0900
+++ gc.c 2004-09-25 17:05:28.000000000 +0900
@ -1406,6 +1406,20 @@
return Qnil;
}
+VALUE
+numfree()
+{
+ RVALUE *f = freelist;
+ long num = 0;
+
+ while (f != 0) {
+ f = f->as.free.next;
+ num += 1;
+ }
+ printf("numfree:%ld\tmalloc_increase:%lu\tmalloc_limit:%lu\n", num, malloc_increase, malloc_limit);
+ return Qnil;
+}
+
void
Init_stack(addr)
VALUE *addr;
@ -1894,6 +1908,7 @@
rb_define_module_function(rb_mObSpace, "undefine_finalizer", undefine_final, 1);
rb_define_module_function(rb_mObSpace, "_id2ref", id2ref, 1);
+ rb_define_module_function(rb_mObSpace, "numfree", numfree, 0);
rb_gc_register_address(&rb_mObSpace);
rb_global_variable(&finalizers);
% grep 'static data' **/*(.)|wc
83 1003 9415
このままいけば、
% ./ruby -rstringio -e '
def fin(&block) ObjectSpace.define_finalizer(Object.new, &block) end
s = "abcdef\n" * 10
io = StringIO.new(s)
fin { eval "p :fin; s.clear" }
6313.times { Object.new }
Object.new
ObjectSpace.numfree
io.gets
ObjectSpace.numfree
eval "p io.pos"
'
numfree:0 malloc_increase:142822 malloc_limit:8000000
:fin
numfree:6331 malloc_increase:301 malloc_limit:8000000
135507671というように StringIO で pos を狂わせたり、
% ./ruby -e '
def fin(&block) ObjectSpace.define_finalizer(Object.new, &block) end
a = (1..10000).to_a
a.shift
fin { eval "p :fin; a.replace((1..1000000).to_a)" }
"a" * 7690000
ObjectSpace.numfree
a.delete_at(0)
ObjectSpace.numfree
eval ""
'
numfree:6446 malloc_increase:7998304 malloc_limit:8000000
:fin
-e:8: [BUG] Segmentation fault
ruby 1.9.0 (2004-09-24) [i686-linux]というように delete_at で segv したり、
% ./ruby -e '
def fin(&block) ObjectSpace.define_finalizer(Object.new, &block) end
a = (1..10000).to_a
a.shift
fin { eval "p :fin; a.replace((1..1000000).to_a)" }
"a" * 7690000
ObjectSpace.numfree
a[0] = 1
ObjectSpace.numfree
eval ""
'
numfree:6444 malloc_increase:7998298 malloc_limit:8000000
:fin
-e:8: [BUG] Segmentation fault
ruby 1.9.0 (2004-09-24) [i686-linux]というように []= で segv したり、
% ./ruby -e '
def fin(&block) ObjectSpace.define_finalizer(Object.new, &block) end
a = (1..100).to_a
fin { eval "p :fin; a.clear; a.compact!" }
6448.times { Object.new }
Object.new
ObjectSpace.numfree
b = a.collect
ObjectSpace.numfree
eval "p b"
'
numfree:0 malloc_increase:141811 malloc_limit:8000000
:fin
numfree:6451 malloc_increase:833 malloc_limit:8000000
(eval):1: [BUG] Segmentation fault
ruby 1.9.0 (2004-09-24) [i686-linux]というように collect で segv したり、
% ./ruby -e '
def fin(&block) ObjectSpace.define_finalizer(Object.new, &block) end
a = []
fin { eval "p :fin; a.concat((0..1000).to_a)" }
6453.times { Object.new }
Object.new
ObjectSpace.numfree
b = a.reverse
ObjectSpace.numfree
eval "1000.times {|i| i.to_s }; p [a.length, b.length]"
'
numfree:0 malloc_increase:141008 malloc_limit:8000000
:fin
numfree:6447 malloc_increase:18978 malloc_limit:8000000
-e: [BUG] Segmentation fault
ruby 1.9.0 (2004-09-24) [i686-linux]というように reverse で segv したり、
% ./ruby -e '
def fin(&block) ObjectSpace.define_finalizer(Object.new, &block) end
a = (0..100).to_a
fin { eval "p :fin; a.clear; a.compact!" }
6445.times { Object.new }
Object.new
ObjectSpace.numfree
b = a[1,90]
ObjectSpace.numfree
p b
'
numfree:0 malloc_increase:141798 malloc_limit:8000000
:fin
numfree:6447 malloc_increase:433 malloc_limit:8000000
-e:10:in `inspect': method `inspect' called on terminated object (0x401a501c) (NotImplementedError)
from -e:10:in `p'
from -e:10というように [] で called on terminated object したり、
% ./ruby -e '
def fin(&block) ObjectSpace.define_finalizer(Object.new, &block) end
ary = (1..100).to_a
fin { ary.clear; ary.compact! }
6445.times { Object.new }
Object.new
ObjectSpace.numfree
r = ary.first(100)
ObjectSpace.numfree
p r
'
numfree:0
numfree:6461
-e:10:in `inspect': method `inspect' called on terminated object (0x401a501c) (NotImplementedError)
from -e:10:in `p'
from -e:10というように first で called on terminated object したりするのは 一気に出来なくなるであろう。
ちなみに eval を使っているのは、 freelist の長さを変えずにコードを好きにいじくるためである。
「のだめカンタービレ」をいっきに読む。
5巻までは古本、それ以降の 10巻までは新刊。
bison では、終端記号として "..." という形式の文字列を使える。 つまり、"==" などと書けるわけで、名前をつけなくて良くて、 また対象の言語とのギャップが減るはずである。
で、実際に使ってみた。
... うぅむ。 名前をつけないでやるには yytname を使わないといけないのだが、 まぁ、べつに難しいわけじゃないのだが最初の障壁がちょっと高いか。
[latest]