天泣記

2004/09/01

#1

まぁ、validator はなんとか動いた。

validator に与える仕様は HTML の form そのものとしたので、 たいした検査は出来ないのだが、 仕様をあらためて書かなくていいのはいいかも知れない。

#2

session について考える。

ふむ。(validator で form を parse するために) HTree を必須にしてしまったので、 URL rewriting を扱ってもいいかも。

2004/09/03

#1

pty から tty 側のプロセスにどうやって signal を送るか調べる。

「詳解 UNIX プログラミング」には、TIOCSIG ないし TIOCSIGNAL で出来るとあるが、 Linux には見当たらない。

おや?

... そーか。SIGINT などは、pty 側から ^C を 1byte 送れば発生できるのか。

2004/09/05

#1
% google-count 毛深い機能
2       毛深い機能
#2
% google-count 'CGI インストール' 'CGI 設置'
363     CGI インストール
29700   CGI 設置

2004/09/08

#1

webapp で、WEBrick も扱うようにしてみた。

でも、servlet を定義するファイルをどこかに置くとそれが load されるという形の標準的な方法がないようで、自前で定義せざるを得なかった。 このため、サーバ側に require をひとつ追加しないと動かなくて残念。

2004/09/09

#1

どうも Content-Type を設定するのが面倒臭い。

... というわけで出力の内容から auto detection することにした。 ついでに、XML 宣言があってそれに encoding が入っていれば、charset もつける。

2004/09/10

#1

backtrace をログに出すかクライアントに返すかの選択を(するための情報のひとつを) 環境変数で指定しようかと思ったのだが、 suEXEC が任意の環境変数は通してくれないためうまくいかなかった。

2004/09/13

#1

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 で構成することは出来たっけ?

#2

/foo/bar/xxx.cgi が実行可能な CGI スクリプトだとして、

ScriptAlias / "/foo/bar/xxx.cgi/"

とすれば動くようだ。

でも、これって意図された動作なのかなぁ?

あとは CGI じゃなくて、FastCGI や mod_ruby だとどうだろう?

2004/09/14

#1

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/"
#2

気のせいだった。mod_ruby もそれで動いた。

#3

ScriptAlias / ... という書き方を他にしている人はいるだろうか?

だが、残念ながら google で / を探すことは出来ない。

しばらく考えて、"ScriptAlias usr" で探すことを思いつく。

うが。 Apache のドキュメントに書いてあるではないか。

Apache HTTP Server Version 1.3 Apache HOWTO documentation

2004/09/15

#1

では、Alias / ... という書き方は他で行なわれているか。

探してみると、Using MoinMoin with apache + mod_python というのがあるか?

2004/09/16

#1
% google-count {そもそも,もそもそ}  
1620000 そもそも
21500   もそもそ
#2
% google-count まそまそ みそみそ むそむそ めそめそ もそもそ
75      まそまそ
848     みそみそ
23      むそむそ
8070    めそめそ
21500   もそもそ

2004/09/20

#1

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 だけが実行される、と。

#2

まぁ、変だとは感じてましたが、バグでしたか。

2004/09/21

#1

ついでに、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) が出て来ないな。

#2

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 でさらに例外を起こすとプロセスが死ぬか。

2004/09/24

#1

new PickAxe をくれるというので、もらっておくことにする。

(いつ届くのかは知らない)

2004/09/25

#1

ふと、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);
#2

ついでに、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);

2004/09/26

#1
% grep 'static data' **/*(.)|wc                            
     83    1003    9415

2004/09/27

#1

このままいけば、

% ./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 の長さを変えずにコードを好きにいじくるためである。

2004/09/28

#1

「のだめカンタービレ」をいっきに読む。

5巻までは古本、それ以降の 10巻までは新刊。

2004/09/29

#1

bison では、終端記号として "..." という形式の文字列を使える。 つまり、"==" などと書けるわけで、名前をつけなくて良くて、 また対象の言語とのギャップが減るはずである。

で、実際に使ってみた。

... うぅむ。 名前をつけないでやるには yytname を使わないといけないのだが、 まぁ、べつに難しいわけじゃないのだが最初の障壁がちょっと高いか。


[latest]


田中哲