まぁ、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]