Linux의 파일 설명자에서 신호 인터럽트를 생성하는 방법은 무엇입니까?

Linux의 파일 설명자에서 신호 인터럽트를 생성하는 방법은 무엇입니까?

Linux의 파일 설명자에서 신호 인터럽트를 생성하는 방법은 무엇입니까?

동기는 마이크로컨트롤러에서처럼 사용자 영역에서 인터럽트를 생성하는 것입니다. I/O 파일 디스크립터가 있고 상태가 변경될 때 인터럽트를 생성하고 싶습니까?

누군가 나에게 말해 줄 수 있습니까? 가능하다면 예를 들어주세요.

답변1

Linux는 파일 시스템 이벤트를 모니터링하기 위한 두 가지 메커니즘을 제공합니다.dnotify그리고inotify.

둘 중 오래된 것이 dnotify커널 버전 2.4.0에 도입되었습니다. 이를 통해 애플리케이션은 다음을 통해 디렉터리 변경에 대한 알림을 받도록 등록할 수 있습니다.fcntl()상호 작용. 알림 자체는 신호를 통해 전달됩니다. 이 dnotify메커니즘은 디렉터리의 변경 사항을 모니터링하는 것으로 제한되며 개별 파일을 모니터링하는 것은 허용하지 않습니다. 또한 모니터링되는 디렉터리에 대한 열린 파일 설명자를 유지해야 합니다. 이 dnotify메커니즘은 inotify2.6.13에 도입되었을 때 더 이상 사용되지 않습니다.

새로운 프로그램은 inotify디렉터리와 개별 파일의 모니터링을 지원하는 이 메커니즘을 사용해야 합니다. 그러나 이는 신호를 기반으로 하지 않습니다. 인스턴스 inotify는 파일 설명자와 연결됩니다. 이 파일 설명자에서 이벤트 알림을 읽을 수 있습니다.

두 메커니즘의 한계는 디렉토리를 재귀적으로 감시할 수 있는 옵션이 없다는 것입니다. 이는 모니터링할 하위 트리의 각 디렉터리에 대해 모니터링을 개별적으로 설정해야 함을 의미합니다.


예( dnotify):

#define _GNU_SOURCE
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

/* For error handling */
#include <stdlib.h>
#include <errno.h>
#include <error.h>

static volatile int event_fd;

static void handler(int sig, siginfo_t *si, void *data)
{
    event_fd = si->si_fd;
}

int main(int argc, char *argv[])
{
    struct sigaction sa;
    int fd;

if(argc < 2)
    error(EXIT_FAILURE, 0, "missing argument");

    sa.sa_sigaction = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_SIGINFO;
    sigaction(SIGRTMIN + 1, &sa, NULL);

    if((fd = open(argv[1], O_RDONLY)) < 0)
        error(EXIT_FAILURE, errno, "failed to open '%s'", argv[1]);

    if(fcntl(fd, F_SETSIG, SIGRTMIN + 1) < 0)
         error(EXIT_FAILURE, errno, "failed to set dnotify signal");

    if(fcntl(fd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_DELETE|DN_MULTISHOT))
    error(EXIT_FAILURE, errno, 
              "failed to register notification for '%s'", argv[1]);

    while (1) {
        pause();
        printf("event occured for fd=%d\n", event_fd);
    }
}

설명하다:

fcntl(fd, F_SETSIG, SIGRTMIN + 1)

알림 이벤트가 발생했을 때 전송될 시그널을 설정합니다. 0 값은 SIGIO전송됨(기본값)을 의미합니다. 다른 값( 포함 SIGIO)은 전송될 신호로 해석됩니다. 후자의 경우 신호 처리기는 siginfo_t두 번째 인수로 구조를 수신하고 si_fd이 구조의 필드에는 이벤트를 생성한 파일 설명자가 포함됩니다.

알림을 위해 실시간 신호( >= SIGRTMIN)를 사용하는 경우 동일한 신호 번호(사용 가능한 메모리에 따라 다름)를 사용하여 여러 I/O 이벤트를 대기열에 넣을 수 있습니다. 특히 사용할 때는 실시간 신호를 사용해야 합니다 DN_MULTISHOT.

fcntl(fd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_DELETE|DN_MULTISHOT)

fd가 참조하는 디렉토리나 여기에 포함된 파일이 변경될 때 알림을 발생시키는 이벤트를 설정합니다. 사용 가능한 이벤트 유형은 다음과 같습니다.

  • DN_ACCESS 파일에 액세스합니다.
  • DN_MODIFY 파일이 수정되었습니다.
  • DN_CREATE 파일을 만듭니다.
  • DN_DELETE 파일의 링크가 해제되었습니다.
  • DN_RENAME 디렉토리에서 파일 이름이 변경됩니다.
  • DN_ATTRIB 파일의 속성이 변경되었습니다.

알림은 일반적으로 일회성입니다. 즉, 추가 알림을 받으려면 애플리케이션을 다시 등록해야 합니다. 지정된 경우 DN_MULTISHOT알림은 명시적으로 제거될 때까지 계속 적용됩니다.


예( inotify):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/inotify.h>

/* For PATH_MAX */
#include <limits.h>

/* For error handling */
#include <errno.h>
#include <error.h>

int main(int argc, char *argv[]) {
    int fd, wd, len, i;
    char buf[sizeof(struct inotify_event) + PATH_MAX];

    if (argc < 2)
        error(EXIT_FAILURE, 0, "missing argument");

    if ((fd = inotify_init()) < 0)
        error(EXIT_FAILURE, errno, "failed to initialize inotify instance");

    for (i = 1; i < argc; i++) {
         if ((wd = inotify_add_watch (fd, argv[i], 
                                      IN_MODIFY | IN_CREATE | IN_DELETE)) < 0)
             error(EXIT_FAILURE, errno,
                   "failed to add inotify watch for '%s'", argv[i]);
    }

     while ((len = read(fd, buf, sizeof(buf))) > 0) {
         i = 0;
             while (i < len) {
                 struct inotify_event *ie = (struct inotify_event*) &buf[i];

                 printf("event occured for '%s': ", argv[ie->wd]);
                 if (ie->mask & IN_MODIFY)
                     printf("%s was modified\n", ie->len ? ie->name : "file");
                 else if (ie->mask & IN_CREATE)
                     printf("%s was created\n",  ie->name);
                 else if (ie->mask & IN_DELETE)
                     printf("%s was deleted\n",  ie->name);
                 else
                     printf("unexpected event\n");

                 i += sizeof(struct inotify_event) + ie->len;
             }
     }

    error(EXIT_FAILURE, len == 0 ? 0 : errno, "failed to read inotify event");
}

설명하다:

fd = inotify_init()

inotify인스턴스를 초기화합니다. 반환 값은 새로 생성된 이벤트 큐와 관련된 파일 설명자입니다 inotify. 기본적으로 파일 설명자는 차단됩니다.

wd = inotify_add_watch (fd, argv[i], IN_MODIFY | IN_CREATE | IN_DELETE)

감시 목록(관찰이라고도 함)의 새 항목이 추가됩니다 inotify_add_watch(). 세 번째 매개변수는 inotify모니터링할 이벤트를 나타내는 비트마스크입니다 . 사용 가능한 이벤트 유형은 다음과 같습니다.

  • IN_ACCESS 파일에 액세스됩니다.
  • IN_ATTRIB 파일의 속성이 변경되었습니다.
  • IN_CLOSE_WRITE 쓰기 위해 열린 파일이 닫혔습니다.
  • IN_CLOSE_NOWRITE 읽기 전용으로 열린 파일이 닫혔습니다.
  • IN_CREATE watch 디렉터리에 파일이나 디렉터리가 생성됩니다.
  • IN_DELETE 감시 디렉터리에서 파일이나 디렉터리가 삭제되었습니다.
  • IN_DELETE_SELF 모니터링 중인 파일 또는 디렉터리가 삭제되었습니다.
  • IN_MODIFY 파일이 수정되었습니다.
  • IN_MOVE_SELF 모니터링 중인 파일 또는 디렉터리가 이동되었습니다.
  • IN_MOVED_FROM 파일이 감시 디렉토리 밖으로 이동되었습니다.
  • IN_MOVED_TO 파일이 watch 디렉토리로 이동됩니다.
  • IN_OPEN 파일이 열려 있습니다.
  • IN_ALL_EVENT 무엇보다도.
  • IN_MOVE 동등하다IN_MOVED_TO|IN_MOVED_FROM
  • IN_CLOSE 동등하다IN_CLOSE_WRITE|IN_CLOSE_NOWRITE

마스크 매개변수에서 다음 옵션을 설정할 수도 있습니다 inotify_add_watch().

  • IN_DONT_FOLLOW 심볼릭 링크를 따르지 마세요.
  • IN_EXCL_UNLINK 한때 watch 디렉토리에 있었던 링크 해제된 파일에 대해서는 이벤트를 생성하지 마십시오.
  • IN_MASK_ADD 모니터링이 이미 존재하는 경우 모니터링 이벤트가 누적되어 추가됩니다.
  • IN_ONESHOT 이벤트가 발생한 후 자동으로 시계에서 시계를 제거합니다.
  • IN_ONLYDIR 경로 이름만 봅니다(디렉토리인 경우).

반환된 값은 표시된 인스턴스 inotify_add_watch()에서 감시되고 있는 파일 시스템 객체와 관련된 감시 설명자 입니다. 지정된 객체가 이미 모니터링되고 있는 경우 기존 감시의 설명자를 반환합니다.inotifyfd

while ((len = read(fd, buf, sizeof(buf))) > 0) {
    i = 0;
    while (i < len) {
        struct inotify_event *ie = (struct inotify_event*) &buf[i];
        /* ... */
        i += sizeof(struct inotify_event) + ie->len;
    }
}

read()인스턴스와 연결된 파일 설명자의 각 성공은 다음 필드가 포함된 inotify하나 이상의 구조를 반환합니다 .inotify_event

  • int wd 트리거된 시계에 대한 시계 설명자입니다.
  • uint32_t mask 감시를 트리거한 이벤트에 대한 마스크입니다.
  • uint32_t cookie 관련 이벤트와 관련된 고유 쿠키입니다.
  • uint32_t len 이름 필드의 크기입니다.
  • char name[] 이벤트를 트리거한 감시 디렉터리에 있는 파일의 선택적 null 종료 이름입니다.

에 전달된 이벤트 유형에 해당하는 비트 외에도 inotify_add_watch()마스크 필드는 다음 상태 비트를 설정할 수도 있습니다.

  • IN_IGNORED 감시가 제거되었습니다( inotify_rm_watch()연결 해제 경로, 경로 이름 등).
  • IN_ISDIR 디렉터리에 의해 트리거되는 이벤트입니다.
  • IN_Q_OVERFLOW이벤트 큐가 오버플로되었습니다. 또한 wd는 -1로 설정됩니다.
  • IN_UNMOUNT watch 경로 이름을 포함하는 파일 시스템이 마운트 해제됩니다.

inotify_event각 구조의 길이는 sizeof(inotify_event) + len가변 길이 name필드에 따라 다릅니다.

커널 버전 2.6.21 이전에는 전달된 버퍼가 read()너무 작아서 다음 이벤트를 저장할 수 없는 경우 read()가 0을 반환했습니다. 2.6.21부터 read()실패하고 errno로 설정됩니다 EINVAL.

답변2

파일이 변경되었다는 신호를 받는 것이 불가능하다고 생각합니다. 그러나 inotify, 도 1에 도시된 바와 같이.위키피디아 페이지, 파일이 변경될 때 이벤트를 수신하는 프로그램을 작성할 수 있어야 합니다.

이 웹사이트에 관한 좋은 기사가 있습니다 inotify. 또한 현재 디렉터리의 이벤트를 모니터링하는 예도 있습니다.

관련 정보