分类: C/C++
2013-11-29 22:42:42
man 7 inotify 有下面这样一段描述:
Since Linux 2.6.25, signal-driven I/O notification is available for inotify file descriptors; see the discussion of F_SETFL (for setting the
O_ASYNC flag), F_SETOWN, and F_SETSIG in fcntl(2). The siginfo_t structure (described in sigaction(2)) that is passed to the signal handler has
the following fields set: si_fd is set to the inotify file descriptor number; si_signo is set to the signal number; si_code is set to POLL_IN;
and POLLIN is set in si_band.
我们使用下面的程序来验证一下:
点击(此处)折叠或打开
- #define _GNU_SOURCE
- #include <string.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <aio.h>
- #include <errno.h>
- #include <sys/inotify.h>
- #include <signal.h>
- #include <fcntl.h>
- #include <sys/epoll.h>
- #define errmsg_exit do {\
- fprintf(stderr, "%s: -------- err msg:%s\n", __FUNCTION__, strerror(errno));\
- exit(-1);\
- }while(0);
- #define ENTER do {\
- fprintf(stderr, "######### enter %s \n", __FUNCTION__);\
- }while(0);
- #define LEAVE do {\
- fprintf(stderr, "######### leave %s \n", __FUNCTION__);\
- }while(0);
- void sig_io(int signo, siginfo_t *siginfo, void *context)
- {
- ENTER;
- LEAVE;
- }
- struct inotify_event* event;
- int buf_len;
- void do_read(int fd)
- {
- memset(event, 0, buf_len);
- while ( read(fd, event, buf_len) != -1 )
- {
- {
- if( event->mask & IN_OPEN)
- fprintf(stdout, "有一个文件在目录下被打开, 文件名为:%s.\n", event->name);
- if( event->mask & IN_CREATE)
- fprintf(stdout, "有一个文件在目录下创建, 文件名为:%s.\n", event->name);
- if( event->mask & IN_DELETE)
- fprintf(stdout, "有一个文件在目录下删除, 文件名为:%s.\n", event->name);
- if( event->mask & IN_MOVE_SELF)
- fprintf(stdout, "目录本身被删除了...\n");
- if( event->mask & IN_MOVED_FROM)
- fprintf(stdout, "有一个文件移出目录, 文件名为:%s.\n", event->name);
- if( event->mask & IN_MOVED_TO)
- fprintf(stdout, "有一个文件移进目录, 文件名为:%s.\n", event->name);
- if( event->mask & IN_CLOSE_WRITE)
- fprintf(stderr, "有一个文件已经关闭写操作, 文件名为:%s.\n", event->name);
- }
- memset(event, 0, buf_len);
- }
- }
- int main(int argc, char *argv[])
- {
- // 创建监控对象
- int fd_inotify = inotify_init1(IN_NONBLOCK);
- if (fd_inotify == -1)
- {
- fprintf(stderr, "不能创建监控对象,系统提示错误信息为:%s.\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
- const char *dir_path = argv[1];
- // 把由命令行专递进来的目录加入到监控对象的监控列表中
- int inotify_a_fd = inotify_add_watch(fd_inotify, dir_path, IN_OPEN | IN_DELETE | IN_DELETE_SELF | IN_CREATE | IN_CLOSE_WRITE | IN_MOVED_FROM | IN_MOVED_TO);
- if (inotify_a_fd == -1)
- {
- fprintf(stderr, "不能向监控对象的监控列表上添加对象,系统提示错误信息为:%s.\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
- int old_errno = errno;
- int file_name_max;
- if ( (file_name_max = pathconf(dir_path, _PC_NAME_MAX)) == -1 )
- {
- if (errno == old_errno)
- {
- file_name_max = 1024; // 无法从系统得到当前目录所支持的最大文件名,所有只好猜测最大路径名为1024个字节
- }
- else
- {
- fprintf(stderr, "不能从系统上读取目录 %s 下的最大文件名长度,系统提示错误信息为:%s.\n", dir_path, strerror(errno));
- exit(EXIT_FAILURE);
- }
- }
- buf_len = sizeof(*event) + file_name_max + 1;
- event = malloc(buf_len);
- memset(event, 0, buf_len);
- //int fd_n = epoll_create(1);
- //if (fd_n == -1)
- //{
- // fprintf(stderr, "main: can not allocate an notify instance, err msg: %s\n", strerror(errno));
- //}
- //
- //struct epoll_event en;
- //en.data.fd = fd_inotify;
- //en.events = EPOLLIN | EPOLLET;
- //if (epoll_ctl(fd_n, EPOLL_CTL_ADD, fd_inotify, &en) != 0)
- //{
- // fprintf(stderr, "main: epoll_ctl failed, err msg: %s\n", strerror(errno));
- // exit(EXIT_FAILURE);
- //}
- //fprintf(stdout, "************* Get ready to notify .....\n");
- //struct epoll_event rt_en;
- //int n_en;
- //while ((n_en = epoll_wait(fd_n, &rt_en, 1, -1)) != -1)
- //{
- // if (rt_en.data.fd == fd_inotify)
- // {
- // do_read(fd_inotify);
- // }
- //}
- struct sigaction act;
- act.sa_sigaction = sig_io;
- act.sa_flags = SA_SIGINFO;
- sigemptyset(&act.sa_mask);
- if (sigaction(SIGIO, &act, NULL) != 0)
- {
- errmsg_exit;
- }
- if (fcntl(fd_inotify, F_SETFL, O_ASYNC) != 0)
- {
- errmsg_exit;
- }
- if (fcntl(fd_inotify, F_SETSIG, SIGIO) != 0)
- {
- errmsg_exit;
- }
- if (fcntl(fd_inotify, F_SETOWN, getpid()) != 0)
- {
- errmsg_exit;
- }
- while (1);
- exit(EXIT_SUCCESS);
- }
当被监控对象上有相应的动作发生, SIGIO 信号被没有发出。具体原因先看看 open 函数的另一段描述:
O_ASYNC
Enable signal-driven I/O: generate a signal (SIGIO by default, but this can be changed via fcntl(2)) when input or output becomes possi-
ble on this file descriptor. This feature is only available for terminals, pseudo-terminals, sockets, and (since Linux 2.6) pipes and
FIFOs. See fcntl(2) for further details.
红色部分能说明原因。哎, Linux 下的 man 也有错误的时候,所以当我们在查阅文档时,最好自己动手测试。