Login
Immutable PageDiscussionInfoAttachments
Diff for "clear/wm_devel/2013-03-02"

MMA
Differences between revisions 2 and 3
Revision 2 as of 2013-03-02 17:03:36
Size: 2652
Editor: clear
Comment:
Revision 3 as of 2013-03-02 17:06:41
Size: 2750
Editor: clear
Comment:
Deletions are marked like this. Additions are marked like this.
Line 43: Line 43:
                /* select(2)によるとエラー発生時のfdの中身は未定義になるらしい */                 /* Linuxのselect(2)のmanによるとエラー発生時のfdの中身は未定義になるらしい
                   FreeBSDではfdは変更されないとmanに書いてあった
*/

イベントループの改良

関連: clear/wm_devel/2012-11-12

これまで以下のようにイベントループを書いていた。

   1 volatile sig_atomic_t running = 1; /* 実行継続フラグ */
   2 xcb_connection_t *conn;            /* Xサーバとの接続 */
   3 
   4 /* ... */
   5 
   6 /* SIGTERMハンドラ */
   7 void handle_sigterm(int sig)
   8 {
   9     running = 0;
  10 }
  11 
  12 /* ... */
  13 
  14 /* イベントループ */
  15 xcb_generic_event_t *event;
  16 while (running && (event = xcb_wait_for_event(conn))) {
  17     /* イベント処理(とエラーハンドリング)を行う */
  18 }

xcb_wait_for_eventは、イベントが無い場合は来るまでブロックし続ける。そのため、WMがkillされて継続フラグが0になった場合でも、何かイベントが来ない限りそこで止まってしまい、WMがすぐに終了しないという問題がある。

そこで、xcb_poll_for_eventを用いてイベントループを次のように書き直した。

   1 /* イベントループ */
   2 xcb_generic_event_t *event;
   3 int xfd = xcb_get_file_descriptor(conn);
   4 fd_set fd;
   5 FD_ZERO(&fd);
   6 while (running) {
   7     if ((event = xcb_poll_for_event(conn))) {
   8         イベント処理(とエラーハンドリング)を行う
   9     } else {
  10         /* 何か来るまで待つ */
  11         FD_SET(xfd, &fd);
  12         if (select(xfd + 1, &fd, NULL, NULL, NULL) < 0) {
  13             if (errno == EINTR) {
  14                 /* Linuxのselect(2)のmanによるとエラー発生時のfdの中身は未定義になるらしい
  15                    FreeBSDではfdは変更されないとmanに書いてあった */
  16                 FD_ZERO(&fd);
  17             } else {
  18                 selectに失敗。エラーを出力して終了
  19             }
  20         }
  21     }
  22 }

xcb_poll_for_eventは、イベントが無い場合即座にNULLを返すので、killされた場合もループがすぐ回って即座に終了するようになる。しかし、これだけだとイベントが届かない限り全力でループが回り続けるので、CPU資源を食いつぶしてしまう。そこで、イベントが無かった場合はselectでXサーバから何かがやってくるのを待つ。select中に何らかのシグナルを受け取った場合(killされたときはSIGTERM)はselectが-1を返し、errnoEINTRとなるので、イベントループの実行を続ける1。そうでない場合は本当にselectが失敗しているのでエラーを吐いて終了する。

awesomeやi3(共にXCBで書かれている)は、libevを使ってイベントループを実装している。

  1. シグナルはSIGTERMだけとは限らない (1)

clear/wm_devel/2013-03-02 (last edited 2013-03-03 22:32:31 by clear)