2013-04-05 3 views
6

イベントがkqueueに登録されている場合、そのイベントに関連するIDは タイプが提供されます。例えば、ファイルディスクリプタは私もとの競合を避けるために他のイベントタイプ我々はたkqueueの新しい インスタンスを必要とするような信号に応答する必要がある場合は、今すぐkqueueを使用して複数のイベントタイプに応答する

int kq; 
struct kevent ke; 

kq = kqueue(); 
fd = open(argv[1], O_RDONLY); 
EV_SET(&ke, fd, EVFILT_VNODE, EV_ADD, NOTE_DELETE | NOTE_RENAME, 0, NULL); 
kevent(kq, &ke, 1, NULL, 0, NULL); 

while (1) { 
    kevent(kq, NULL, 0, &ke, 1, NULL); 
    /* respond to file system event */ 
} 

を見 にファイルを識別するために使用されますidentの引数は kevent()です。複数のイベント・タイプを見

kq_sig = kqueue(); 
struct kevent ke_sig; 

/* set the handler and ignore SIGINT */ 
signal(SIGINT, SIG_IGN); 
EV_SET(&ke_sig, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); 
kevent(kq_sig, &ke_sig, 1, NULL, 0, NULL); 
while (1) { 
    kevent(kq_sig, NULL, 0, &ke_sig, 1, NULL); 
    /* respond signals */ 
} 

は共有状態に 行為は(信号を受信する 例えばファイル記述子を閉じることができる)ことは、複数のスレッドを必要とするように見えます。

kqueueを使用してあるスレッドから別のスレッドにメッセージを送信するためのより一般的なメカニズムがありますか?場合によっては、フィルタを有効または無効にする方法として、別のkeventをエッジトリガーする手段として と考えることもできます。

+0

IDは一意ではないため、同じイベントqでさまざまなイベントタイプを混在させることができますか?それともあなたの質問が間違っていますか? – dhein

+0

まさに正しい。 kevent構造体がイベントタイプを格納しないため、IDは一意でなければなりません。 1つのイベントタイプに応答するのは、kevent()でブロックする非常に簡単なループですが、スレッド(またはプロセス)間の調整が必要と思われるので、複数のイベントタイプ(私の例ではVNODE&SIGNAL)を処理することはかなり困難です。 – eradman

+0

ええ、私は残念です...しかし、私は未来にもこのことが必要です....私は、IDがシステム内で一意であるため、複数のスレッドやプロセスで何の問題もないと思ったばかりです範囲。しかし、私はこれに従うつもりです。 – dhein

答えて

7

のkevent構造体は、実際に発生したイベントに関する情報を提供しています。

struct kevent { 
     uintptr_t  ident;   /* identifier for this event */ 
     int16_t   filter;   /* filter for event */ 
     uint16_t  flags;   /* general flags */ 
     uint32_t  fflags;   /* filter-specific flags */ 
     intptr_t  data;   /* filter-specific data */ 
     void   *udata;   /* opaque user data identifier */ 
}; 

あなたが興味を持っている必要があります。あなたのケースでfdまたはSIGINTのいずれかを返すこと

  • ident
  • filter(あなたの場合でも)EVFILT_VNODEまたはEVFILT_SIGNALのいずれかを返します。
  • fflagEVFILT_VNODEには、ファイル記述子イベントがNOTE_DELETEまたはNOTE_RENAMEであるかどうかが表示されます。

単一のキューに2つのkevent構造体を登録し、これらの構造体メンバを使用して、イベントがファイル記述子または信号に関連していたかどうかを判断できます。ここで我々は道、より効率的で、ユーザ空間には、さらに、同期を必要としないシングルスレッドを使用し

#include <stdlib.h> 
#include <stdio.h> 
#include <fcntl.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/event.h> 
#include <sys/time.h> 

int 
main(int argc, char** argv) 
{ 
    /* A single kqueue */ 
    int kq = kqueue(); 
    /* Two kevent structs */ 
    struct kevent *ke = malloc(sizeof(struct kevent) * 2); 

    /* Initialise one struct for the file descriptor, and one for SIGINT */ 
    int fd = open(argv[1], O_RDONLY); 
    EV_SET(ke, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_DELETE | NOTE_RENAME, 0, NULL); 
    signal(SIGINT, SIG_IGN); 
    EV_SET(ke + 1, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); 

    /* Register for the events */ 
    if(kevent(kq, ke, 2, NULL, 0, NULL) < 0) 
     perror("kevent"); 

    while(1) { 
     memset(ke, 0x00, sizeof(struct kevent)); 
     if(kevent(kq, NULL, 0, ke, 1, NULL) < 0) 
      perror("kevent"); 

     switch(ke->filter) 
     { 
      /* File descriptor event: let's examine what happened to the file */ 
      case EVFILT_VNODE: 
       printf("Events %d on file descriptor %d\n", ke->fflags, (int) ke->ident); 

       if(ke->fflags & NOTE_DELETE) 
        printf("The unlink() system call was called on the file referenced by the descriptor.\n"); 
       if(ke->fflags & NOTE_WRITE) 
        printf("A write occurred on the file referenced by the descriptor.\n"); 
       if(ke->fflags & NOTE_EXTEND) 
        printf("The file referenced by the descriptor was extended.\n"); 
       if(ke->fflags & NOTE_ATTRIB) 
        printf("The file referenced by the descriptor had its attributes changed.\n"); 
       if(ke->fflags & NOTE_LINK) 
        printf("The link count on the file changed.\n"); 
       if(ke->fflags & NOTE_RENAME) 
        printf("The file referenced by the descriptor was renamed.\n"); 
       if(ke->fflags & NOTE_REVOKE) 
        printf("Access to the file was revoked via revoke(2) or the underlying fileystem was unmounted."); 
       break; 

      /* Signal event */ 
      case EVFILT_SIGNAL: 
       printf("Received %s\n", strsignal(ke->ident)); 
       exit(42); 
       break; 

      /* This should never happen */ 
      default: 
       printf("Unknown filter\n"); 
     } 
    } 
} 

注:ここでは

は、これを実行する方法を示して完全な例です。

関連する問題