SBCLのnon-blocking I/O

SBCLでnon-blocking I/Oを使いたくなったので少し調べてみた。

serve-eventというものが利用可能らしい。
SBCL自体のマニュアルにはこれに関数詳しい説明はなく、CMUCLのドキュメント(CMUCL User's Manual: Event Dispatching with SERVE-EVENT)を参照する必要がある。

以下、簡単な使用例。

;; non-bloking I/O を使って、ファイルの内容を出力するコード
(let ((input (open "/path/to/file"))  ; 対象ファイル
      (handler nil))

  ;; 対象ファイル(FD)とイベントコールバック関数を登録
  ;; コールバック関数は、対象ファイルが 読み込み可能 or 書き込み可能 になった際に呼び出される。
  (setf handler
        (sb-sys:add-fd-handler (sb-sys:fd-stream-fd input) #| 対象ファイルディスクリプタ |# 
                               :input                      #| 入力イベントをハンドル |#
                               (lambda (fd)                #| コールバック関数: 行を一つ読み込んで出力する |#
                                 (declare (ignore fd))
                                 (if (not (listen input))  ; EOF判定: 読み込み可能なデータない場合はEOFと判断する  ※ この方法が適切かどうかは不明
                                     (progn (print :eof)
                                            (sb-sys:remove-fd-handler handler)  ; 読み込みが終了したので登録解除
                                            (close input))                         ; ファイルクローズ
                                   (print (read-line input))))))

  ;; 全てのイベントが処理されるのを待機
  (sb-sys:serve-all-events))

ローカルファイルに対して使ってもほとんど意味がないけど、ソケット通信と組み合わせると便利そう。