有一个文件,我想用poll()
检查它的内容已经改变。
在Raspi上有一个名为gpio值的文件,如果该值改变poll()
是由POLLPRI触发的,我想用普通文件做同样的事情。
这里是我用来检查GPIO文件的代码:
int gpio_fd = gpio_fd_open(); int timeout = POLL_TIMEOUT; struct pollfd fdset; int nfds = 1; char *buf[MAX_BUF]; int len; int rc; fdset.fd = gpio_fd; fdset.events = POLLPRI | POLLERR | POLLHUP | POLLNVAL; // POLLIN | | POLLOUT unsigned int c1, c2, c3; do{ rc = poll(&fdset, 1, timeout);
和gpio_fd_open函数:
int gpio_fd_open() { printf("opening File: " SYSFS_GPIO_DIR "\n"); int fd, len; char buf[MAX_BUF]; len = snprintf(buf, sizeof (buf), SYSFS_GPIO_DIR); fd = open(buf, O_RDONLY | O_NONBLOCK); if (fd < 0) { perror("gpio/fd_open"); } return fd; }
在Linux中,不像你的特殊的GPIO文件,你不能轮询fd到一个打开的普通文件。
要观察文件的更改,可以使用inotify
函数族。 他们方便地使用一个文件描述符,它可以和你的GPIO文件描述符一起传递给poll()
,所以你可以同时观察两者。
所以,你的代码的一些小的增加/改变:
int fw_fd = file_watch_fd("/some/file/to/watch"); struct pollfd fdset[2]; int nfds = 2; int rc; fdset[0].fd = gpio_fd; fdset[0].events = POLLPRI | POLLERR | POLLHUP | POLLNVAL; fdset[1].fd = fw_fd; fdset[1].events = POLLIN; do { rc = poll(fdset, nfds, timeout);
您正在对inotify fd进行轮询,您读取的内容会返回一个发生的事件。 由于这个代码只能看一个事件的一个文件,所以我们很确定这个事件是什么,但是我们仍然需要从fd中读取它,然后我们才可以读取这个文件。
if (fdset[1].revents & POLLIN) { if (ready(fw_fd)) { /* file has changed, read it */ } }
这是file_watch_fd()函数:
int file_watch_fd ( const char * filename ) { static int inot = ERR; static int iflags = IN_CLOEXEC | IN_NONBLOCK; static uint32_t mask = IN_MODIFY; int watch; if (inot == ERR) { inot = inotify_init1(iflags); if (inot == ERR) return ERR; } watch = inotify_add_watch(inot, filename, mask); if (watch == ERR) return ERR; return inot; }
这里是ready()函数:
int ready ( int inot ) { uint64_t buffer[8192]; ssize_t nr; char * p; size_t n; struct inotify_event * evP; int ready = 0; while ((nr = read(inot, (char *)buffer, sizeof(buffer))) > 0) { for (p = buffer; p < buffer + nr; p += n) { evP = (struct inotify_event *)p; if (evP->mask & IN_MODIFY) ready = 1; n = sizeof(struct inotify_event) + evP->len; } } return ready; }
(人们在使用inotify的经验会注意到,我对它的功能粗心大意,以保持这个例子尽可能简单)