天泣記

2008-07-04 (Fri)

#1

Japan Linux Conference 2008 の〆切がそろそろなのだが、今年はどんな投稿がくるかなぁ。

(〆切は来週月曜。なにか出せるものがあるひとがいたら出してほしい。)

2008-07-05 (Sat)

#1

FreeBSD で、uname -m をごまかすのは環境変数で UNAME_m=i386 などと設定するだけでいいようだ。

2008-07-06 (Sun)

#1

〆切については尋ねてみるといいかもしれない。

#2

へー、FreeBSD の telldir ってこんな動作なんだ。

% ruby -ve 'd = Dir.open("."); 10.times { p d.tell }'
ruby 1.8.6 (2007-09-24 patchlevel 111) [amd64-freebsd6]
1
2
3
4
5
6
7
8
9
10

2008-07-08 (Tue)

#1

ここしばらく、Ruby の正規表現での \G の用途を考えていたのだが、複数行のタブ展開に使えるかもしれない

text.gsub(/(?:^|\G)([^\t\n]{8}*([^\t\n]{0,7}))\t/) {
  $1 + " " * (8 - $2.length)
}

こっちのほうがわかりやすいか

text.gsub(/(?:^|\G)([^\t\n]*)\t/) {
  $1 + " " * (8 - $1.length % 8)
}

2008-07-09 (Wed)

#1

\G を探していて、るびまに例があることに気がついた。

Rubyist Magazine - 標準添付ライブラリ紹介【第 13 回】正規表現 (2)

str = "1 * 2 + 3"
str.scan(/\G\s*(?:(\w+)|([^\s\w]+))/) do
  if $1
    puts "w:#{$1}"
  elsif $2
    puts "W:#{$2}"
  else
    raise "unexpected input"
  end
end

これって raise にたどりつくことはあるのかね?

#2

タブ展開に \G はいらないか

text.gsub(/([^\t\n]*)\t/) {
  $1 + " " * (8 - $1.length % 8)
}

まぁ、\G を使った方が効率はいい気がするが

2008-07-11 (Fri)

#1

まぁ、Japan Linux Conference 2008 の〆切は月末 (7/28) までのびた。

Linux と名前についていますが、自由ソフトウェアの話なら幅広く対象なので、ネタのあるひとはぜひ。

2008-07-15 (Tue)

#1

環境によって、ruby のテストがハングすることがある。chkbuild はそういうときにタイムアウトまで待つのだが、これが 1時間とかなり長い。だが、コマンドによっては (make test-all とか、マシンにもよるが) それくらいかかってもおかしくない場合もあるので、このタイムアウトを短くするわけにはいかない。

しかし、ハングすると、意味もなく 1時間近く待つことになり、場合によってはブランチの数だけそれが繰り返されることもあり、どうにかしたいと思っていた。

ここで、人間がログを見ると、ハングしているのはだいたい分かる。出力が止まっていれば、だいたいハングである。

というわけで、10分間出力がなければハングしているとみなして中断するようにしてみよう。

ここで、10分間を測定するのは、標準出力・標準エラー出力をファイルにつなげておき、そのファイルの mtime で検出することにする。

さて、いままではコマンドを起動したときに何を待つ必要があるかというと、

というふたつで、このふたつのどちらが先に起きるかは分からないが、先に起きたものに対し、それに応じた処理をする必要がある。これはふたつの非同期イベントを待つというわけで、対象が I/O であれば即座に select の出番であるが、今回は I/O ではないので select は使えない。

ハングの検出は上記のふたつに加えて、以下を待つ必要があるということである。

いままでは、おおざっぱにいえば、

pid = fork { exec ... }
timeout(3600) { Process.wait pid }

としていた。TimeoutError が起こればタイムアウトしたということだし、そうでなく普通に終わればコマンドが自然に終わったということである。

しかし、これだとハングを検出するコードを入れる余地がない。

しかも、timeout と wait にはレースコンディションがある。もし、wait が終わった後、timeout のブロックを抜ける前にタイムアウトしたら、wait が行われたにもかかわらず TimeoutError になるかもしれない。それに、どうせ wait は行うので、wait を中断する必然性もない。(wait しないとゾンビができてしまう)

というわけで timeout を捨てたいなぁと思いつつ調べていくと、Thread#join に引数をつけられることに気がついた。Thread#join の引数はタイムアウトの秒数である。

これを使うと、timeout を捨てて書けそうなのでそうしてみた。おおざっぱにいえば、以下のような構造である。

pid = fork { exec ... }
wait_thread = Thread.new { Process.wait pid }
while true
  if コマンド開始後1時間経過している then タイムアウト検出 end
  if 最後の出力から10分経過している then ハング検出 end
  if wait_thread.join(コマンド開始1時間後と最後の出力の10分後の近い方までの時間)
    正常終了
    break
  end
end

これで、スレッドを kill するようなあぶないことをせずに目的を実現できた。(タイムアウトやハングを検出したときに、子プロセスを殺すことはあるが、スレッドは殺さない。wait_thread は子プロセスを殺すことに成功すれば自然に終わるので、放っておいていい)

#2

さて、Ruby レベルではこれで解決した気分になれたわけであるが、一段下がって、C レベルだとどうであろうか。

まず、Ruby 1.8 は C レベルではシングルスレッドなので、wait しつつタイムアウトというのはなかなか難しい。実際には WNOHANG で polling しているようだ。(SIGCHLD を使って polling を避ける実装は可能だろうか?)

Ruby 1.9 では Ruby レベルのスレッドが OS のスレッドに対応するので、wait は WNOHANG なしでちゃんとブロックしているようだ。ただ、タイマースレッドが頻繁に起きるので、完全に休むというようにはいかない。

2008-07-18 (Fri)

#1

3not をしばらく考えてみる。

が、わからなかったので全解探索して解を見つける。

解を変形して理屈が分かった。

2008-07-19 (Sat)

#1

せっかく全解探索したので、4not とか問題を大きくできるかな、と思って試してみる。

が、問題が大きくなりすぎて、終わるまで待てそうにないのであきらめる。

3入力 1出力の論理回路は 256種類しかないが、4入力になると 65536種類で、増えすぎである。

まじめに効率の良い探索を考えればできるかもしれないが、3not 用に乱暴に作ったのではうまくない。

2008-07-20 (Sun)

#1

4not じゃなくて 6not なら、3not の結果をふたつ並べれば 4つで済む。一般に 3n 入力 3n 出力の not は内部に 2n 個の (1入力 1出力の) not があればできる。

自明でないのはそれ以下で済むか、というところ。あと、3の倍数でない場合にどうなるか。

2008-07-23 (Wed)

#1

用もなく本屋に寄る癖があるのだが、今日も歩いていた道沿いにあった本屋に寄ってみた。

まぁ、ふつうは文庫やまんがの新刊を眺めるのであるが、その本屋は政府刊行物サービスセンターだったので、そういうものはなかった。

で、官報の実物をはじめて見た。

あと、おみやげとしてお札タオルを売っていた。

2008-07-24 (Thu)

#1

MacOS X のファイル名の話を調べていて、Undocumented Mac OS X の記事をいくつか読む。


[latest]


田中哲