linux fcntl+F_NOTIFY 没有按预期工作:当有变化时,没有触发
linux fcntl+F_NOTIFY not working as expected: when there's change, nothing triggered
我正在使用内核 2.6.32 的 RHEL5。尝试查看 fcntl+F_NOTIFY 是否可以监视目录或文件更改。我搜索了 google 并找到了这个文件:
#define _GNU_SOURCE
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static volatile int event_fd;
static void handler(int signum, siginfo_t *si, void *data){
event_fd = si->si_fd;
printf("info size:%d, data:%d/n", sizeof(siginfo_t), sizeof(data));
}
int main(int argc, char **argv){
struct sigaction action;
int fd;
action.sa_sigaction = handler;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_SIGINFO;
sigaction(SIGRTMIN+1, &action, NULL);
fd = open("test", O_RDONLY);
fcntl(fd, F_SETSIG, SIGRTMIN+1);
fcntl(fd, F_NOTIFY, DN_MODIFY | DN_CREATE | DN_MULTISHOT);
fd = open(".", O_RDONLY);
fcntl(fd, F_SETSIG, SIGRTMIN+1);
fcntl(fd, F_NOTIFY, DN_MODIFY | DN_CREATE | DN_MULTISHOT);
while(1){
pause();
printf("got event on fd=%d/n", event_fd);
}
}
我编译成./a.out.
在另一个终端中,我创建了一个名为 "test.txt" 的空文件。然后我开始./a.out。现在不管我如何更改“.”下的 "test.txt" 或 touch/remove 文件。 ./a.out
没有输出
我理解错了吗?我希望当我更改 "test.txt" 或更改当前目录的任何操作时,它应该触发我的 "handler" 函数并打印出一些东西。
有什么解释吗?
感谢安德鲁的解释,是的,是plus和asyn打错了,更正如下:
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
static volatile int event_fd;
static void handler(int signum, siginfo_t *si, void *data){
event_fd = si->si_fd;
char msg[100];
sprintf(msg, "info size:%d, data:%d\n", sizeof(siginfo_t), sizeof(data));
write(STDOUT_FILENO, msg, strlen(msg));
}
int main(int argc, char **argv){
struct sigaction action;
int fd;
action.sa_sigaction = handler;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_SIGINFO;
sigaction(SIGRTMIN+1, &action, NULL);
fd = open("./test.txt", O_RDONLY);
fcntl(fd, F_SETSIG, SIGRTMIN+1);
fcntl(fd, F_NOTIFY, DN_MODIFY | DN_CREATE | DN_MULTISHOT);
fd = open(".", O_RDONLY);
fcntl(fd, F_SETSIG, SIGRTMIN+1);
fcntl(fd, F_NOTIFY, DN_MODIFY | DN_CREATE | DN_MULTISHOT);
while(1){
pause();
char msg[100];
sprintf(msg, "got event on fd=%d\n", event_fd);
write(STDOUT_FILENO, msg, strlen(msg));
}
}
所以它起作用了。非常感谢。
首先,在信号处理程序中调用 printf()
是不安全的。 只有 异步信号安全函数可以从信号处理程序中安全调用。可以在 http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04
找到 POSIX 指定的异步信号安全函数列表
请注意 printf()
不是异步信号安全函数之一。
其次,您的 printf()
函数调用可能是行缓冲的,并且您没有使用换行符终止输出:
printf("info size:%d, data:%d/n", sizeof(siginfo_t), sizeof(data));
请注意,字符串以 "/n"
结尾,这是一个正斜杠 '/'
后跟字符 'n'
,而不是换行符,后者是反斜杠 '\'
后跟 'n'
,或 "\n"
。假设您的 stdout
流是 Linux 默认行缓冲,在输出缓冲区已满(可能为 4 或 8 kB)之前不会发出任何输出。如果它可以正常工作并且不会死锁,因为 printf()
是一个异步信号-unsafe 函数。
我正在使用内核 2.6.32 的 RHEL5。尝试查看 fcntl+F_NOTIFY 是否可以监视目录或文件更改。我搜索了 google 并找到了这个文件:
#define _GNU_SOURCE
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static volatile int event_fd;
static void handler(int signum, siginfo_t *si, void *data){
event_fd = si->si_fd;
printf("info size:%d, data:%d/n", sizeof(siginfo_t), sizeof(data));
}
int main(int argc, char **argv){
struct sigaction action;
int fd;
action.sa_sigaction = handler;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_SIGINFO;
sigaction(SIGRTMIN+1, &action, NULL);
fd = open("test", O_RDONLY);
fcntl(fd, F_SETSIG, SIGRTMIN+1);
fcntl(fd, F_NOTIFY, DN_MODIFY | DN_CREATE | DN_MULTISHOT);
fd = open(".", O_RDONLY);
fcntl(fd, F_SETSIG, SIGRTMIN+1);
fcntl(fd, F_NOTIFY, DN_MODIFY | DN_CREATE | DN_MULTISHOT);
while(1){
pause();
printf("got event on fd=%d/n", event_fd);
}
}
我编译成./a.out.
在另一个终端中,我创建了一个名为 "test.txt" 的空文件。然后我开始./a.out。现在不管我如何更改“.”下的 "test.txt" 或 touch/remove 文件。 ./a.out
没有输出我理解错了吗?我希望当我更改 "test.txt" 或更改当前目录的任何操作时,它应该触发我的 "handler" 函数并打印出一些东西。
有什么解释吗?
感谢安德鲁的解释,是的,是plus和asyn打错了,更正如下:
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
static volatile int event_fd;
static void handler(int signum, siginfo_t *si, void *data){
event_fd = si->si_fd;
char msg[100];
sprintf(msg, "info size:%d, data:%d\n", sizeof(siginfo_t), sizeof(data));
write(STDOUT_FILENO, msg, strlen(msg));
}
int main(int argc, char **argv){
struct sigaction action;
int fd;
action.sa_sigaction = handler;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_SIGINFO;
sigaction(SIGRTMIN+1, &action, NULL);
fd = open("./test.txt", O_RDONLY);
fcntl(fd, F_SETSIG, SIGRTMIN+1);
fcntl(fd, F_NOTIFY, DN_MODIFY | DN_CREATE | DN_MULTISHOT);
fd = open(".", O_RDONLY);
fcntl(fd, F_SETSIG, SIGRTMIN+1);
fcntl(fd, F_NOTIFY, DN_MODIFY | DN_CREATE | DN_MULTISHOT);
while(1){
pause();
char msg[100];
sprintf(msg, "got event on fd=%d\n", event_fd);
write(STDOUT_FILENO, msg, strlen(msg));
}
}
所以它起作用了。非常感谢。
首先,在信号处理程序中调用 printf()
是不安全的。 只有 异步信号安全函数可以从信号处理程序中安全调用。可以在 http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04
请注意 printf()
不是异步信号安全函数之一。
其次,您的 printf()
函数调用可能是行缓冲的,并且您没有使用换行符终止输出:
printf("info size:%d, data:%d/n", sizeof(siginfo_t), sizeof(data));
请注意,字符串以 "/n"
结尾,这是一个正斜杠 '/'
后跟字符 'n'
,而不是换行符,后者是反斜杠 '\'
后跟 'n'
,或 "\n"
。假设您的 stdout
流是 Linux 默认行缓冲,在输出缓冲区已满(可能为 4 或 8 kB)之前不会发出任何输出。如果它可以正常工作并且不会死锁,因为 printf()
是一个异步信号-unsafe 函数。