= 2013年1月 = * あけました == 01/01 == stdinから与えられた文字列をひたすらウィンドウに表示するツール<>が欲しくなったので作ろうとしている(xcbで書いてる)が、Xのイベントを捌きつつstdinからの入力を処理する必要がある。しばらく前からいくつかの方法を試しているが中々上手く行かなかった。 * stdin(0番)とXのfd(`xcb_get_file_descriptor()`で取れる)をselectする * これが一番真っ当な方法に思えるが、やってみるとイベントを適切なタイミングで拾えない(`MapNotify`直後の`Expose`とか、`DestroyNotify`とか<リプライとかと一緒に届いてイベントキューに入る->selectでは適切なタイミングで拾えない?)>>) * `xev`や`xmon`などのツールで確認したところ、サーバからイベントは届いている(が、上手く取得できていない) * イベントをポーリング(`xcb_poll_for_event`)して、イベントが来てないときは標準入力を読む * Windowsでよくある`PeekMessage`を使う方法と同じ発想。Unix的ではない? * 普通にやると`read`がブロックしてイベントを拾えなくなるので、待ち時間0で`select`する * このままだと全力で回り続けるのでCPUを100%食う * `sched_yield`で残りタイムスライスを放棄できるらしい(Windows APIで言うところの`Sleep(0)`)。これを使ってみたが、依然としてそれなりに(手元のマシンで5%ほど)CPUを食う * もっと長くスリープすればCPU使用率は下がるだろうが、イベント処理が遅れる可能性がある * イベントを取りこぼす問題は起こらない まだ試していないのはマルチスレッド化(Xイベント処理/入力処理の2スレッド)だがあまりやりたくない。最初の方法でイベントを上手く拾えない原因を突き止めたいところ。 * もしかして: イベントキューに入ってる * イベントがソケットのバッファから読み出されてXCBのイベントキューに入ってしまえば、`select`では検知不能 * この場合--(select + キューにイベントがあるかの確認を行えば)--キューにイベントがあるかを確認して、イベントがあれば処理し、無ければ`select`すれば良さそう * `xcb_poll_for_queued_event()`という非常にそれっぽい関数を発見した * FreeBSDのportsにあるlibxcbはバージョンが古く、この関数がない * 自分で最新のxcbをビルドして試したところ期待通りに動いたので、仮説は正しかった模様 最終的にはこうなった。 {{{#!highlight c xcb_connection_t *conn; xcb_generic_event_t *event; // ... int fd_x = xcb_get_file_descriptor(conn); for (;;) { if (event = xcb_poll_for_queued_event(conn)) { eventを処理 } else { 0とfd_xをselect if (FD_ISSET(fd_x, ...)) { event = xcb_wait_for_event(conn); eventを処理 } else if (FD_ISSET(0, ...)) { stdinからの入力を処理 } } } }}} 03/01追記: xcb_poll_for_queued_eventはlibxcb 1.8以降でないと使えない。