gcc の問題を報告しておく
報告する前に cvs からとって来た最新版を確認したら、かなり時間がかかってしまった
せっかく最新の gcc を作ったのだから ruby を作ってみるか、ということで試すと問題が増えている
% cat t.c #include <stdio.h> int f() { return -4; } int main(int argc, char **argv) { int c = f(); long i; if (c > 0) { for (i=0;i<c;i++) { f(); } } else { c = -c; printf("%d\n", c); for (i=0;i<c;i++) { printf("%d\n", i); } printf("%d\n", i); } return 0; } % gcc -v -O2 t.c Using built-in specs. Target: i686-pc-linux-gnu Configured with: ../gcc/configure --prefix=/home/src/gcc --enable-languages=c Thread model: posix gcc version 4.1.0 20050430 (experimental) /home/src/gcc/libexec/gcc/i686-pc-linux-gnu/4.1.0/cc1 -quiet -v t.c -quiet -dumpbase t.c -mtune=pentiumpro -auxbase t -O2 -version -o /tmp/ccfrK1hF.s ignoring nonexistent directory "/home/src/gcc/lib/gcc/i686-pc-linux-gnu/4.1.0/../../../../i686-pc-linux-gnu/include" #include "..." search starts here: #include <...> search starts here: /usr/local/include /home/src/gcc/include /home/src/gcc/lib/gcc/i686-pc-linux-gnu/4.1.0/include /usr/include End of search list. GNU C version 4.1.0 20050430 (experimental) (i686-pc-linux-gnu) compiled by GNU C version 4.1.0 20050430 (experimental). GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096 as -V -Qy -o /tmp/ccWrA4oh.o /tmp/ccfrK1hF.s GNU assembler version 2.15 (i386-linux) using BFD version 2.15 /home/src/gcc/libexec/gcc/i686-pc-linux-gnu/4.1.0/collect2 --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o /home/src/gcc/lib/gcc/i686-pc-linux-gnu/4.1.0/crtbegin.o -L/home/src/gcc/lib/gcc/i686-pc-linux-gnu/4.1.0 -L/home/src/gcc/lib/gcc/i686-pc-linux-gnu/4.1.0/../../.. /tmp/ccWrA4oh.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /home/src/gcc/lib/gcc/i686-pc-linux-gnu/4.1.0/crtend.o /usr/lib/crtn.o % ./a.out 4 0
うぅむ。
一応、報告しておく。
gcc の PR/21297 だが、報告で Component は c に指定した。 しかし、確認されたときに middle-end に修正された。 しかし、修正されたときにはさらに target に修正された。
PR/21332 も報告では c に指定した。 しかし、確認されたときに tree-optimization に修正された。
... 思うに、Component を報告者に設定させるのは間違いだと思う。 わかるかそんなもん
Linux の、socketpair でデータを読み込まないで close すると、相手の read で ECONNRESET になる?
% ruby -rsocket -e ' s1, s2 = UNIXSocket.pair s1.print "a" s2.close s1.read ' -e:5:in `read': Connection reset by peer (Errno::ECONNRESET) from -e:5
そのために、1.9 の双方向 popen で ECONNRESET が出る
% ruby -ve ' io = IO.popen("-", "r+") if io sleep 1 else print "a" STDERR.puts STDIN.gets end ' ruby 1.9.0 (2005-05-01) [i686-linux] -e:7:in `gets': Connection reset by peer - <STDIN> (Errno::ECONNRESET) from -e:7
FAM, the File Alteration Monitor, provides an API that applications can use to be notified when specific files or directories are changed.
dnotify と kqueue をちょっと調べてみる。
Gamin is a file and directory monitoring system defined to be a subset of the FAM (File Alteration Monitor) system.
inotify というものもあるようだ
dnotify.txt を参考にちょっと書いてみる。
#!/usr/bin/env ruby F_NOTIFY = 1026 DN_ACCESS = 0x00000001 DN_MODIFY = 0x00000002 DN_CREATE = 0x00000004 DN_DELETE = 0x00000008 DN_RENAME = 0x00000010 DN_ATTRIB = 0x00000020 DN_MULTISHOT = -0x80000000 trap(:SIGIO) { puts "changed" } open(".") {|d| d.fcntl(F_NOTIFY, DN_MODIFY|DN_CREATE|DN_MULTISHOT) loop { sleep } }
以前から考えていた、tail -f の親玉みたいなプログラムを書いてみた。
なお、dnotify も inotify も kqueue も使っていない。
Python Challenge に挑戦してみると、level 5 まで、6問解けた。 level 6 はわからない
level 4 までは python を使わずに ruby で済ましたことは告白しておく
level 6 は解けた。
結局、level 16 まで解いてしまった...
Python を少し使って、Python の print が嫌いだったことを思い出した。
LC2005 のプログラムが公開された。
6/2 に「Ruby I/O 機構の改善 -- stdio considered harmful --」というのを発表するのでプレゼンを作らないとな
codefest-japan が Web 上で案内された... と言って良いのだろうか。
そのうちもっと詳しく載る予定らしい。 (登録すれば今でも詳しい情報がわかるけれど)
% date; google-count stdio-considered-harmful Mon May 9 14:44:06 JST 2005 4 stdio-considered-harmful
64bit なシステムで、64bit 浮動小数点数を即値で扱うとしたら、どういうふうにして 浮動小数点数を区別するのが適切か?
おそらく、(Fixnum が 63bit 整数であるのと同様に) 64bit よりもちょっと小さい浮動小数点を定義することになる。 たぶん指数を削るのが適切だと思うが、他の選択肢はあるか?
指数を 1bit 削ると半分になる。
指数の上半分を削ると指数は常に負になって、±1 くらいの範囲しか扱えなくなっちゃう?
2bit 削ると?
そういう削りかたでは使いものにならないか。
上下それぞれ 1/4 を削る?
ふと、TCP_DEFER_ACCEPT と TCP_CORK を試してみる。
require 'socket' SOL_TCP = 6 TCP_DEFER_ACCEPT = 9 TCP_CORK = 3 s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) s.setsockopt(SOL_TCP, TCP_DEFER_ACCEPT, 3) s.setsockopt(SOL_TCP, TCP_CORK, 1) s.connect(Socket.pack_sockaddr_in(80, "www.ruby-lang.org")) s.send("GET / HTTP/1.0\r\n\r\n", 0) s.close_write p s.read
TCP_DEFER_ACCEPT と TCP_CORK を設定しないときは次のようになる。
15:29:19.189652 192.168.2.111.35503 > beryllium.ruby-lang.org.www: S 450066111:450066111(0) win 5840 <mss 1460,sackOK,timestamp 1484508 0,nop,wscale 0> (DF) 15:29:19.218844 beryllium.ruby-lang.org.www > 192.168.2.111.35503: S 507735494:507735494(0) ack 450066112 win 5792 <mss 1414,sackOK,timestamp 358448159 1484508,nop,wscale 0> (DF) 15:29:19.218875 192.168.2.111.35503 > beryllium.ruby-lang.org.www: . ack 1 win 5840 <nop,nop,timestamp 1484511 358448159> (DF) 15:29:19.219068 192.168.2.111.35503 > beryllium.ruby-lang.org.www: P 1:19(18) ack 1 win 5840 <nop,nop,timestamp 1484511 358448159> (DF) 15:29:19.219186 192.168.2.111.35503 > beryllium.ruby-lang.org.www: F 19:19(0) ack 1 win 5840 <nop,nop,timestamp 1484511 358448159> (DF) 15:29:19.247269 beryllium.ruby-lang.org.www > 192.168.2.111.35503: . ack 19 win 5792 <nop,nop,timestamp 358448162 1484511> (DF) 15:29:19.256939 beryllium.ruby-lang.org.www > 192.168.2.111.35503: P 1:322(321) ack 20 win 5792 <nop,nop,timestamp 358448163 1484511> (DF) 15:29:19.256941 beryllium.ruby-lang.org.www > 192.168.2.111.35503: F 322:322(0) ack 20 win 5792 <nop,nop,timestamp 358448163 1484511> (DF) 15:29:19.257053 192.168.2.111.35503 > beryllium.ruby-lang.org.www: . ack 322 win 6432 <nop,nop,timestamp 1484515 358448163> (DF) 15:29:19.257070 192.168.2.111.35503 > beryllium.ruby-lang.org.www: . ack 323 win 6432 <nop,nop,timestamp 1484515 358448163> (DF)
単方向にパケットが連続して送られていてよろしくないのでまとめたい。
TCP_DEFER_ACCEPT と TCP_CORK を設定すると次のように変わる。
15:29:27.219447 192.168.2.111.35504 > beryllium.ruby-lang.org.www: S 457583492:457583492(0) win 5840 <mss 1460,sackOK,timestamp 1485311 0,nop,wscale 0> (DF) 15:29:27.248219 beryllium.ruby-lang.org.www > 192.168.2.111.35504: S 515604740:515604740(0) ack 457583493 win 5792 <mss 1414,sackOK,timestamp 358448962 1485311,nop,wscale 0> (DF) 15:29:27.248390 192.168.2.111.35504 > beryllium.ruby-lang.org.www: FP 1:19(18) ack 1 win 5840 <nop,nop,timestamp 1485314 358448962> (DF) 15:29:27.285814 beryllium.ruby-lang.org.www > 192.168.2.111.35504: F 322:322(0) ack 20 win 5792 <nop,nop,timestamp 358448966 1485314> (DF) 15:29:27.285923 192.168.2.111.35504 > beryllium.ruby-lang.org.www: . ack 1 win 5840 <nop,nop,timestamp 1485318 358448962,nop,nop,sack sack 1 {322:323} > (DF) 15:29:27.286144 beryllium.ruby-lang.org.www > 192.168.2.111.35504: P 1:322(321) ack 20 win 5792 <nop,nop,timestamp 358448966 1485314> (DF) 15:29:27.286229 192.168.2.111.35504 > beryllium.ruby-lang.org.www: . ack 323 win 6432 <nop,nop,timestamp 1485318 358448966,nop,nop,sack sack 1 {322:323} > (DF)
設定すると、3 way handshake の最後の ack のところに実際のデータと fin を乗せるようになって、パケット数が減っている。
TCP_DEFER_ACCEPT が ack を遅らせて、 さらに TCP_CORK がデータ転送を遅らせることにより、 結局 shutdown まで遅らせてしまう。
CodeFest日本2005 の案内が出た。
第54回プログラミング研究会は 6/1 か。
まつもとさんの発表は 11:45-12:30 で、LC2005 は 13:00 から、と。ふむ。
とある本屋に 22時過ぎにいったら閉店間際であった。
もしかして閉店時刻は 22:03 とかなのだろうか、と変なことを考えつつ、一冊買う。
後でふとホームページを見て閉店時刻を調べてみると、21:30 となっていた。うぅむ。
3-way handshake の ack にデータを載せられるなら、さらに進めて syn-ack や syn に載せられるのだろうか、 と思って調べてみると、T/TCP というのがそういうかんじらしい。
FreeBSD で実装されているらしい。
詳解 TCP/IP Vol.3 に載っているようだが、Vol.3 は手元にない。
% date; google-count stdio-considered-harmful Thu May 12 14:30:59 JST 2005 6 stdio-considered-harmful
Shiro (2005/05/11 15:52:00 PDT): 「浮動小数点数でNaNになるビットパターンに他の型のオブジェクトを詰め込む」
たしかに、NaN の部分にはある程度余裕がある。
指数 11bit が全部 1 なもので NaN (SNaN, QNaN) と Inf (+Inf, -Inf) を表現しているから、 64-11=53bit で 2^53 個の値のうち、4つ以外は他の用途に使ってもいいというのは考えられる話ではある。
しかし、ポインタを 8byte align と仮定すれば、ポインタだけで 2^61個は使ってしまうわけで、 2^61 + (2^64-2^53) では 2^64 をへーきで越えてしまう。
というわけで、これをやるにはポインタを削んないといけない。
だとすれば、(仮想)メモリを 64bit フルに使えるようになる時代がいつ来るのかはわからないが、 もしそういう時代が来るとすればこれは足枷になる。
まぁ、現時点では無限にも思える 64bit 空間ではあるが、 32bit 空間になったときもやはり無限に思ったような覚えがあるので、 制限するのはちょっと気が進まない。
tamamo で rename を検出することを検討する。
inode の再利用はどのくらい現実的に起こるか?
% cat s touch a; ls -i a; rm a touch b; ls -i b; rm b touch c; ls -i c; rm c touch d; ls -i d; rm d touch e; ls -i e; rm e touch f; ls -i f; rm f touch g; ls -i g; rm g touch h; ls -i h; rm h touch i; ls -i i; rm i % sh s 35317 a 35317 b 35317 c 35317 d 35317 e 35317 f 35317 g 35317 h 35317 i
とても現実的に起こる感じである。
ついでに、open 中は再利用されないことを確認してみる。
% cat t touch a; ls -i a; sleep 1 < a& rm a touch b; ls -i b; sleep 1 < b& rm b touch c; ls -i c; sleep 1 < c& rm c touch d; ls -i d; sleep 1 < d& rm d touch e; ls -i e; sleep 1 < e& rm e touch f; ls -i f; sleep 1 < f& rm f touch g; ls -i g; sleep 1 < g& rm g touch h; ls -i h; sleep 1 < h& rm h touch i; ls -i i; sleep 1 < i& rm i % sh t 35317 a 35318 b 35319 c 35320 d 35321 e 35322 f 35323 g 35324 h 35325 i
% google-count codefest{,a} 18300 codefest 125 codefesta
CodeFest という名前ではなくても類似のイベントはいろいろあるように思うのだが、 そういうのを集めたリストはあるのだろうか。
EAGAIN が起きるところにつながった stdio の挙動を試すサンプルを作ってみる。
% cat t.c #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> int main() { int pipes[2], r, w, ret; long n; FILE *fp; char *buf; if (pipe(pipes) < 0) { perror("pipe"); exit(1); } r = pipes[0]; w = pipes[1]; if (fcntl(w, F_SETFL, O_NONBLOCK) < 0) { perror("F_SETFL"); exit(1); } if (fcntl(r, F_SETFL, O_NONBLOCK) < 0) { perror("F_SETFL"); exit(1); } n = 0; while (1) { if (write(w, "a", 1) < 0) { if (errno == EAGAIN) break; perror("write"); exit(1); } n += 1; } printf("pipe size: %d bytes\n", n); if ((fp = fdopen(w, "w")) == NULL) { perror("fdopen"); exit(1); } if (putc('b', fp) == EOF) { perror("putc"); exit(1); } if (fflush(fp) == EOF) { printf("fflush failed: %s\n", strerror(errno)); } if ((buf = malloc(n)) == NULL) { perror("malloc"); exit(1); } if ((ret = read(r, buf, n)) < 0) { perror("read"); exit(1); } if (ret != n) { puts("partial read"); exit(1); } putchar('['); while (1) { unsigned char ch; if (read(r, &ch, 1) < 0) { if (errno == EAGAIN) break; perror("read"); exit(1); } putchar(ch); } fputs("]\n", stdout); return 0; } % gcc t.c % ./a.out pipe size: 4096 bytes fflush failed: Resource temporarily unavailable [] %
% google-count {詰め,爪,積め,摘め,つめ,ツメ}が甘い 30000 詰めが甘い 4090 爪が甘い 1 積めが甘い 3 摘めが甘い 777 つめが甘い 9230 ツメが甘い
% date; google-count stdio-considered-harmful Thu May 19 18:00:22 JST 2005 10 stdio-considered-harmful
tmpreaper の話を読んでみる。
これは... うぅむ。
FileUtils.rm_rf は消すと決心した後にちゃんと消せるかという話なのだが、 これはそもそも消すと決心していいのかという問題を述べている。
いくら古くてもテンポラリファイルが不要になっていない可能性があって (というかそうしむけられることがあり得て)、 消しちゃうと消された場所に勝手な内容のファイルを作れて、 意図しない内容のテンポラリファイルを掴ませることができる、という話。
もちろん open しっぱなしであれば問題ないのだが、 複数回 open してしまうとだまされる可能性がある。
そして、dev/ino の検査では穴が残るというのも面白い。 ファイルは既に消えてしまっているので、 再利用されて同じ dev/ino になったファイルを使えるのだそうな。 てゆーか、つい最近 inode の再利用が簡単に起こることを確認したな。
そーか、hIsEOF だったのか。
feof, IO#eof? にひきつづき hIsEOF というわけで、 一般化して EOF かどうか判定するのをすべて嫌いになってみようか。
あるいは、もっといろんな言語のを調べてみようか。
見識があって素晴らしい
% google-count time-of-check-to-time-of-use time-to-check-to-time-to-use TOCTTOU TTCTTTU 464 time-of-check-to-time-of-use 8 time-to-check-to-time-to-use 639 TOCTTOU 0 TTCTTTU
% google-count {ウルー,うるー}秒 1 ウルー秒 0 うるー秒
とある日記の URI の推測に成功し (自分用未公開) アンテナに登録するがタイトルが抽出されないので調べたら open-uri のバグだったので直してみる。
ディレクトリが rmdir された後、. と .. はどうなるか?
% uname Linux % mkdir a % cd a % ruby -e 'p Dir.entries(".")' [".", ".."] % rmdir ../a % ruby -e 'p Dir.entries(".")' []
Linux では消える模様。
% uname NetBSD % mkdir a % cd a % ruby -e 'p Dir.entries(".")' [".", ".."] % rmdir ../a % ruby -e 'p Dir.entries(".")' -e:1:in `open': No such file or directory - .. (Errno::ENOENT) from -e:1:in `entries' from -e:1
NetBSD では Errno::ENOENT でディレクトリが open できない。 いわれてみれば、. がないのに open できる Linux のほうが奇妙だという気もしないでもない。
それはそれとして、消した後に open できないなら消す前に open しておけばいいわけで、そうやって試す。
% mkdir a % cd a % ruby -e 'Dir.open(".") {|d| sleep 10; p d.to_a }' & [1] 16426 % rmdir ../a % []
というわけで NetBSD でも消える模様
ディレクトリが rmdir された後、ファイルを作れるか?
% uname Linux % mkdir a % cd a % rmdir ../a % touch b touch: cannot touch `b': No such file or directory % mkdir b mkdir: cannot create directory `b': No such file or directory
というわけで無理らしい
root ならどうか
# touch b touch: cannot touch `b': No such file or directory # mkdir b mkdir: cannot create directory `b': No such file or directory
それでも無理らしい
NetBSD でも試すがやっぱり無理
ふむ。そこで rename というのは想定外ではある。
% google-count {赤い,青い,黄色い,白い,茶色い}月 39100 赤い月 17400 青い月 4650 黄色い月 14500 白い月 8 茶色い月
ここ数ヶ月 CFLAGS='-g -O3 -Wall' -march=pentium3 -mcpu=pentium3 として作った ruby で samidare を動かしていたのだが、 core を吐いたのは [ruby-dev:26113] の一回だけで、 それ以外は安定して動いている。
なんか予想外。
% google-count {が,ぎ,ぐ,げ,ご}す{が,ぎ,ぐ,げ,ご}すしい 59 がすがすしい 0 がすぎすしい 0 がすぐすしい 0 がすげすしい 0 がすごすしい 0 ぎすがすしい 49 ぎすぎすしい 0 ぎすぐすしい 0 ぎすげすしい 0 ぎすごすしい 0 ぐすがすしい 0 ぐすぎすしい 0 ぐすぐすしい 0 ぐすげすしい 0 ぐすごすしい 0 げすがすしい 0 げすぎすしい 0 げすぐすしい 0 げすげすしい 0 げすごすしい 0 ごすがすしい 0 ごすぎすしい 0 ごすぐすしい 0 ごすげすしい 0 ごすごすしい
openbsd での ruby 1.9 の autobuild がうまくいっていないようなので調べたところ、 あるディレクトリが削除できないことが原因であった。
openbsd36# ls -l total 2 drwxr-xr-x 2 autobuild autobuild 512 May 30 01:32 CVS openbsd36# ls -la CVS total 4 drwxr-xr-x 2 autobuild autobuild 512 May 28 23:53 . drwxr-xr-x 3 autobuild autobuild 512 May 30 01:32 .. openbsd36# rmdir CVS rmdir: CVS: Directory not empty
ディレクトリは空なのに、空でないために削除できない。
調べたところ、CVS は空なのだが、CVS/. は空でないらしい。
openbsd36# ls -la CVS/. total 12 drwxr-xr-x 2 autobuild autobuild 512 May 28 23:53 . drwxr-xr-x 3 autobuild autobuild 512 May 28 23:53 .. -rw-r--r-- 1 autobuild autobuild 329 May 28 23:53 Entries -rw-r--r-- 1 autobuild autobuild 28 May 28 23:53 Repository -rw-r--r-- 1 autobuild autobuild 42 May 28 23:53 Root -rw-r--r-- 1 autobuild autobuild 10 May 28 23:53 Tag
inode 番号を調べる。
openbsd36# ls -lia total 6 432769 drwxr-xr-x 3 autobuild autobuild 512 May 30 01:32 . 432768 drwxrwxrwt 3 root wheel 512 May 30 01:32 .. 65409 drwxr-xr-x 2 autobuild autobuild 512 May 30 01:32 CVS openbsd36# ls -lia CVS total 4 65396 drwxr-xr-x 2 autobuild autobuild 512 May 28 23:53 . 432769 drwxr-xr-x 3 autobuild autobuild 512 May 30 01:32 ..
CVS は 65409 なのに、CVS/. は 65396 らしい。
なんか file system が腐っているようだ。
single user mode で fsck して直す。 そのために、まず single user mode にする方法 (boot -s) を調べなければならなかった。
% google-count {FAX,MODEM}-over-{VoIP,Skype} 269 FAX-over-VoIP 0 FAX-over-Skype 123 MODEM-over-VoIP 7 MODEM-over-Skype
うぉ。ISBN が変わるのか。
[latest]