Let's start Scheme

2015-10-18

カスタムポートとソケットとバッファポート

「と」で繋げるとなんとなくアニメとかのタイトルっぽい感じがするなぁ。

Sagittariusは0.6.9でポート周りにかなりバグを混入した(弄った)のだが、頭を悩ませるバグが顕在化した。それが表題のポートである。どこで使われているかといえばTLSである。

何が問題か?いくつかの問題が合わさってるのではあるんだが、一つはget-bytevector-nとカスタムポートの相性。カスタムポートは要求されたバイト(文字数)を返す必要はないので、例えば1バイトずつ返して呼び出し元に判断させるということができる。例えば以下のようなの
(import (rnrs))

(let* ([pos 0]
       [p (make-custom-binary-input-port
           "custom in"
           (lambda (bv start count)
             (if (= pos 16)
                 0
                 (begin
                   (set! pos (+ 1 pos))
                   (bytevector-u8-set! bv start pos)
                   1)))
           (lambda () pos)
           (lambda (p) (set! pos p))
           (lambda () 'ok))])
  (get-bytevector-n p 3))
;;-> #vu8(1 2 3)
R6RSテストスイーツからの抜粋なのだが、read!手続きは1バイトずつ処理しget-bytevector-nが最終的に何を返すか決定するという形である。カスタムポートが扱うのが有限のデータなら特に問題ないのだが、ソケットのようにいつEOFがくるか分からないものだと割と困るのである。例えばread!の部分がrecvを使っていたとして、あるソケットは要求の半分のデータを受信したする。そうするとget-bytevector-nは残りの半分を取得するためにもう一回read!を呼び、処理はブロックされる。

不定長のデータを扱うのにget-bytevector-nなんて使うなという話なのだが、本当の問題は別のところにある。0.6.9からバッファポートを導入したのだが、こいつとカスタムポートの相性が悪い。何が悪いかと言えば、バッファを埋めるのにget-bytevector-n相当のことがされているのである。カスタムポートを実装したときに、あまり何も考えずにポート側でバイト数を数えるようにしてしまったので複数回の呼び出しが起きるという話なのではある。

解決方法は多分2つくらいあって、
  1. バッファを埋める処理を別枠にする
  2. 現状ポート側でやってることをget-bytevector-nに移す
1.はそこそこadhocな感じがして嫌だなぁ。2.は(99.99%ないけど)別のところに影響が出る可能性がある(もしくは考慮漏れによるバグの混入)。でも2かなぁ、どう考えても。それでとりあえずはバッファの問題は解決するし。

2 comments:

Shiro Kawai said...

buffer-modeがlineの時、下請けポートからの読み出しをたかだか1回だけにするってのはどうですか。ちょっとlineという名前が紛らわしいですがもともとそういう含みを持たせてたはず ("or other implementation-dependent behavior")。Gaucheでは出力ポートでのline bufferingに相当するフラグを入力ポートではmodest bufferingと呼んでてそういう動作になってます。確かr6rsのI/Oの議論の時に「ソケットとかで使うならこういうモードがいるよ」って話を出して、何やかやの結果としてじゃあlineモードをそういう目的に使えればいいじゃんって話になったような気がします。

実際、入力バッファポートがline endingでバッファリングを切る意味って全く無いので (get-lineすればいいのだから)、その意味ではあの文言は不適切だったかも。

kei said...

なるほど、それはありかも。ただ、現状の設計でバッファポートを除く全てのポートはバッファを持たないようにしてるので(transcoded-portみたいにbuffered-portで不可逆変換)、そのままは使えなさそうですね。ポート自体にそういうフラグを持たせるかなぁ。

lineの文言は確かに言い回しとして理解しづらいかも。完全に行指向だと理解してました。o

Post a Comment