반응형


poll()은 소켓 전용이 아니라 "이벤트를 기다릴 수 있는 모든 fd" 에 사용 가능합니다.  (즉, inotify fd도 pollfd 배열에 넣을 수 있다.)
inotify fd + eventfd 동시 poll 예제

소스코드

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/eventfd.h>
#include <sys/inotify.h>
#include <poll.h>
#include <errno.h>

#define WATCH_PATH "/tmp"
#define EVENT_BUF_SIZE (1024 * (sizeof(struct inotify_event) + 16))

typedef struct {
    int inotify_fd;
    int efd;        // eventfd (종료 신호용)
} ThreadArgs;

// -----------------------------------------------
// Thread A: poll로 inotify_fd + eventfd 동시 감시
// -----------------------------------------------
void *watcher_thread(void *arg) {
    ThreadArgs *args = (ThreadArgs *)arg;
    char buf[EVENT_BUF_SIZE];

    struct pollfd pfds[2];

    pfds[0].fd     = args->inotify_fd;
    pfds[0].events = POLLIN;

    pfds[1].fd     = args->efd;
    pfds[1].events = POLLIN;

    printf("[Watcher] 시작 - \"%s\" 감시 중...\n", WATCH_PATH);

    while (1) {
        int ret = poll(pfds, 2, -1);
        if (ret < 0) {
            perror("[Watcher] poll 실패");
            break;
        }

        // 종료 신호 확인 (우선 체크)
        if (pfds[1].revents & POLLIN) {
            uint64_t val;
            read(args->efd, &val, sizeof(val));
            printf("[Watcher] 종료 신호 수신, 스레드 종료\n");
            return NULL;
        }

        // inotify 이벤트 확인
        if (pfds[0].revents & POLLIN) {
            ssize_t len = read(args->inotify_fd, buf, sizeof(buf));
            if (len < 0) {
                perror("[Watcher] inotify read 실패");
                break;
            }

            // 이벤트 파싱
            char *ptr = buf;
            while (ptr < buf + len) {
                struct inotify_event *event = (struct inotify_event *)ptr;

                if (event->mask & IN_CREATE)
                    printf("[Watcher] 파일 생성: %s\n", event->name);
                if (event->mask & IN_DELETE)
                    printf("[Watcher] 파일 삭제: %s\n", event->name);
                if (event->mask & IN_MODIFY)
                    printf("[Watcher] 파일 수정: %s\n", event->name);

                ptr += sizeof(struct inotify_event) + event->len;
            }
        }
    }
    return NULL;
}

// -----------------------------------------------
// Thread B: 8초 후 종료 신호 전송
// -----------------------------------------------
void *stopper_thread(void *arg) {
    ThreadArgs *args = (ThreadArgs *)arg;

    printf("[Stopper] 8초 후 종료 신호 전송 예정...\n");
    sleep(8);

    uint64_t val = 1;
    write(args->efd, &val, sizeof(val));
    printf("[Stopper] 종료 신호 전송 완료\n");
    return NULL;
}

int main() {
    // 1. inotify 초기화
    int inotify_fd = inotify_init1(IN_NONBLOCK);  // nonblock 권장
    if (inotify_fd < 0) {
        perror("inotify_init1 실패");
        return 1;
    }

    // 2. 감시 경로 등록
    int wd = inotify_add_watch(inotify_fd, WATCH_PATH,
                               IN_CREATE | IN_DELETE | IN_MODIFY);
    if (wd < 0) {
        perror("inotify_add_watch 실패");
        return 1;
    }

    // 3. eventfd 생성
    int efd = eventfd(0, 0);
    // eventfd(0, EFD_CLOEXEC);는 fork()/exec() 시 다르게 처리하고 싶을 때 사용한다
    
    if (efd < 0) {
        perror("eventfd 실패");
        return 1;
    }

    // 4. 스레드 인자 구성
    ThreadArgs args = {
        .inotify_fd = inotify_fd,
        .efd        = efd,
    };

    // 5. 스레드 생성
    pthread_t watcher, stopper;
    pthread_create(&watcher, NULL, watcher_thread, &args);
    pthread_create(&stopper, NULL, stopper_thread, &args);

    // 6. 메인: 테스트용 파일 생성/삭제
    sleep(2);
    system("touch /tmp/test_file_a.txt");
    sleep(2);
    system("touch /tmp/test_file_b.txt");
    sleep(2);
    system("rm /tmp/test_file_a.txt");

    // 7. 스레드 종료 대기
    pthread_join(stopper, NULL);
    pthread_join(watcher, NULL);

    // 8. 리소스 정리
    inotify_rm_watch(inotify_fd, wd);
    close(inotify_fd);
    close(efd);

    printf("[Main] 정상 종료\n");
    return 0;
}

 

 

빌드 및 실행

gcc -o inotify_example inotify_example.c -lpthread
./inotify_example

 

예상 출력

[Watcher] 시작 - "/tmp" 감시 중...
[Stopper] 8초 후 종료 신호 전송 예정...
[Watcher] 파일 생성: test_file_a.txt
[Watcher] 파일 생성: test_file_b.txt
[Watcher] 파일 삭제: test_file_a.txt
[Stopper] 종료 신호 전송 완료
[Watcher] 종료 신호 수신, 스레드 종료
[Main]    정상 종료



poll()은 "커널이 이벤트를 알려줄 수 있는 fd" 라면 종류에 상관없이 배열에 혼합해서 넣을 수 있다.

따로 분리할 필요가 없다.

반응형