kqueueインタフェースを呼び出すサンプルコード

5473 ワード

詳細
インタフェースを理解するには、サンプルコードを直接テストすることが最善です.
コードはkqueue-NetBSD System Calls Manualから
このコードの主な機能は、指定されたファイルを監視し、受信したイベントメッセージを印刷することです.(ファイルはプログラムの最初の実行パラメータで指定されます)
 
 
monitor.h
 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
  int fd, kq, nev;
  struct kevent ev;
  static const struct timespec tout = { 1, 0 };

  if ((fd = open(argv[1], O_RDONLY)) == -1)
    err(1, "Cannot open `%s'", argv[1]);

  if ((kq = kqueue()) == -1)
    err(1, "Cannot create kqueue");

  EV_SET(&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
	 NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK|
	 NOTE_RENAME|NOTE_REVOKE, 0, 0);

  if (kevent(kq, &ev, 1, NULL, 0, &tout) == -1)
    err(1, "kevent");

  for (;;) {
    nev = kevent(kq, NULL, 0, &ev, 1, &tout);
    if (nev == -1)
      err(1, "kevent");
    if (nev == 0)
      continue;
    if (ev.fflags & NOTE_DELETE) {
      printf("deleted ");
      ev.fflags &= ~NOTE_DELETE;
    }
    if (ev.fflags & NOTE_WRITE) {
      printf("written ");
      ev.fflags &= ~NOTE_WRITE;
    }
    if (ev.fflags & NOTE_EXTEND) {
      printf("extended ");
      ev.fflags &= ~NOTE_EXTEND;
    }
    if (ev.fflags & NOTE_ATTRIB) {
      printf("chmod/chown/utimes ");
      ev.fflags &= ~NOTE_ATTRIB;
    }
    if (ev.fflags & NOTE_LINK) {
      printf("hardlinked ");
      ev.fflags &= ~NOTE_LINK;
    }
    if (ev.fflags & NOTE_RENAME) {
      printf("renamed ");
      ev.fflags &= ~NOTE_RENAME;
    }
    if (ev.fflags & NOTE_REVOKE) {
      printf("revoked ");
      ev.fflags &= ~NOTE_REVOKE;
    }
    printf("
"); if (ev.fflags) warnx("unknown event 0x%x
", ev.fflags); } }

 
コンパイルし、テスト用の監視対象ファイルを生成し、プログラムを実行します.
 
 
cc monitor.c -o monitor
touch zhongwei.log
./monitor zhongwei.log

 
ファイルに対して様々な操作を行い、出力を観察します.
 
 
echo "Hello kqueue" >> zhongwei.log
#  :
# extended 
# written 

touch zhongwei.log
#  :
# chmod/chown/utimes

mv zhongwei.log zhongwei2.log
#  :
# renamed 

rm zhongwei2.log 
#  :
# deleted hardlinked
 
監視効果がよく、強いです.コードを見てみましょう.
 
 
struct kevent ev;
 
この例では、構造体keventは、モニタリング対象ファイル(例えば、対応するfile descriptor、モニタリングが必要なイベント)を記述するために使用される.
 
 
struct kevent {
             uintptr_t ident;        /* identifier for this event */
             uint32_t  filter;       /* filter for event */
             uint32_t  flags;        /* action flags for kqueue */
             uint32_t  fflags;       /* filter flag value */
             int64_t   data;         /* filter data value */
             intptr_t  udata;        /* opaque user data identifier */
     };

 
構造体の初期化操作は?ここにいたのか:
 
 
EV_SET(&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
	 NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK|
	 NOTE_RENAME|NOTE_REVOKE, 0, 0);
 
EV_SETはkevent構造体の初期化コードを簡略化するマクロ定義である.
はいhにEVが見えるSETの定義、このファイルは(システム:Mac OS X 10.6.8)にあります.
 
$ find /System/ -name event.h
/System//Library/Frameworks/Kernel.framework/Versions/A/Headers/sys/event.h
  
#define EV_SET(kevp, a, b, c, d, e, f) do { \
    struct kevent *__kevp__ = (kevp);   \
    __kevp__->ident = (a);          \
    __kevp__->filter = (b);         \
    __kevp__->flags = (c);          \
    __kevp__->fflags = (d);         \
    __kevp__->data = (e);           \
    __kevp__->udata = (f);          \
} while(0)
 
構造体keventの各メンバーの意味(カッコ内はサンプルコードに入力された実際のパラメータ):
ident (fd)
イベントの識別は、通常file descriptorを使用して識別されます.
他にもEVFILT_AIO, EVFILT_SIGNALなど.
 
filter (EVFILT_VNODE)
イベントを処理するkernel filterを指定します.通常はシステムの事前定義kernel filterである.
EVFILT_VNODEは、fflagsで指定されたイベントタイプを監視するファイルを説明します.
 
flags  (EV_ADD | EV_ENABLE | EV_CLEAR)
Actions to perform on the event.
例:EV_ADDは、このイベントをkqueueに加えるものである.
EV_ENABLEは、kevent()関数がトリガーされるとイベントを返すことを許可します.
 
 
fflags (NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK|NOTE_RENAME|NOTE_REVOKE)
Filter-specific flags.
 
data  (0)
Filter-specific data value.
 
udata  (0)
Opaque user-defined value passed through the kernel unchanged.
 
詳細はman kqueueを表示すればいいです.
 
 
参照ドキュメント:
1.kqueue - NetBSD System Calls Manual