6

イベントが登録されたとき、kqueueそのイベント タイプに関連する ID が提供されます。たとえば、ファイル記述子は、監視するファイルを識別するために使用されます

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引数との競合を避けるために、kqueue の新しいインスタンスが必要です 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 をエッジ トリガーする手段としてフィルターを有効または無効にすることを考えることができます。

4

1 に答える 1

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 */
 };

あなたが興味を持っている必要があります:

  • identfdあなたの場合、またはのいずれかを返しますSIGINT
  • filterEVFILT_VNODEそれは(あなたの場合でも)またはのいずれかを返しますEVFILT_SIGNAL;
  • fflagEVFILT_VNODEファイル記述子イベントがNOTE_DELETEまたはであったかどうかがわかりますNOTE_RENAME

2 つの kevent 構造体を 1 つのキューに登録し、これらの構造体メンバーを使用して、イベントがファイル記述子またはシグナルに関連していたかどうかを判断できます。

これを行う方法を示す完全な例を次に示します。

#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");
        }
    }
}

ここでは単一のスレッドを使用していることに注意してください。これははるかに効率的であり、ユーザー空間でさらに同期する必要はありません。

于 2013-08-28T11:09:01.083 に答える