ログイン
編集不可のページディスカッション情報添付ファイル
"clear/note/2013-01"の差分

MMA
5と10のリビジョン間の差分 (その間の編集: 5回)
2013-01-01 17:13:14時点のリビジョン5
サイズ: 2921
編集者: clear
コメント:
2013-03-01 00:49:12時点のリビジョン10
サイズ: 3749
編集者: clear
コメント:
削除された箇所はこのように表示されます。 追加された箇所はこのように表示されます。
行 5: 行 5:
stdinから与えられた文字列をひたすらウィンドウに表示するツール<<FootNote(時計とかバッテリ残量を表示したい。xtermで良くないか、という説がある(実際今はそうしている)が、端末は入力フォーカスを受け取ってしまうので何かの拍子にフォーカスがてしまいがちなのが難点)>>が欲しくなったので作ろうとしている(xcbで書いてる)が、Xのイベントを捌きつつstdinからの入力を処理する必要がある。しばらく前からいくつかの方法を試しているが中々上手く行かなかった。 stdinから与えられた文字列をひたすらウィンドウに表示するツール<<FootNote(時計とかバッテリ残量を表示したい。xtermで良くないか、という説がある(実際今はそうしている)が、端末は入力フォーカスを受け取ので何かの拍子に入力してしまいがちなのが難点)>>が欲しくなったので作ろうとしている(xcbで書いてる)が、Xのイベントを捌きつつstdinからの入力を処理する必要がある。しばらく前からいくつかの方法を試しているが中々上手く行かなかった。
行 7: 行 7:
  * これが一番真っ当な方法に思えるが、やってみるとイベントを適切なタイミングで拾えない(`MapNotify`直後の`Expose`とか、`DestroyNotify`とか)   * これが一番真っ当な方法に思えるが、やってみるとイベントを適切なタイミングで拾えない(`MapNotify`直後の`Expose`とか、`DestroyNotify`とか<<FootNote(後から考えたが、この手のイベントはリクエスト(`MapWindow`とか`DestroyWindow`)に反応して発生する->リプライとかと一緒に届いてイベントキューに入る->selectでは適切なタイミングで拾えない?)>>)
行 19: 行 19:
   * この場合--(select + キューにイベントがあるかの確認を行えば)--まずキューにイベントがあるかを確認して、イベントがあれば処理し、その後`select`すれば良さそう    * この場合--(select + キューにイベントがあるかの確認を行えば)--キューにイベントがあるかを確認して、イベントがあれば処理し、無ければ`select`すれば良さそう
行 23: 行 23:
最終的にはこうなった。
{{{#!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以降でないと使えない。

2013年1月

  • あけました

01/01

stdinから与えられた文字列をひたすらウィンドウに表示するツール1が欲しくなったので作ろうとしている(xcbで書いてる)が、Xのイベントを捌きつつstdinからの入力を処理する必要がある。しばらく前からいくつかの方法を試しているが中々上手く行かなかった。

  • stdin(0番)とXのfd(xcb_get_file_descriptor()で取れる)をselectする

    • これが一番真っ当な方法に思えるが、やってみるとイベントを適切なタイミングで拾えない(MapNotify直後のExposeとか、DestroyNotifyとか2)

      • xevxmonなどのツールで確認したところ、サーバからイベントは届いている(が、上手く取得できていない)

  • イベントをポーリング(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をビルドして試したところ期待通りに動いたので、仮説は正しかった模様

最終的にはこうなった。

   1 xcb_connection_t *conn;
   2 xcb_generic_event_t *event;
   3 // ...
   4 int fd_x = xcb_get_file_descriptor(conn);
   5 for (;;) {
   6     if (event = xcb_poll_for_queued_event(conn)) {
   7         eventを処理
   8     } else {
   9         0fd_xselect
  10         if (FD_ISSET(fd_x, ...)) {
  11            event = xcb_wait_for_event(conn);
  12            eventを処理
  13         } else if (FD_ISSET(0, ...)) {
  14            stdinからの入力を処理
  15         }
  16     }
  17 }

03/01追記: xcb_poll_for_queued_eventはlibxcb 1.8以降でないと使えない。

  1. 時計とかバッテリ残量を表示したい。xtermで良くないか、という説がある(実際今はそうしている)が、端末は入力フォーカスを受け取るので何かの拍子に入力してしまいがちなのが難点 (1)

  2. 後から考えたが、この手のイベントはリクエスト(MapWindowとかDestroyWindow)に反応して発生する->リプライとかと一緒に届いてイベントキューに入る->selectでは適切なタイミングで拾えない? (2)

clear/note/2013-01 (最終更新日時 2013-03-01 00:49:12 更新者 clear)