poll()没有阻塞,立即返回

时间:2016-06-03 17:46:54

标签: c linux blocking polling sysfs

我正试图通过sysfs使用poll()在GPIO上捕获中断。我在第三个位置有-1,所以它可以阻止,但它似乎总是返回。我在SO上查了一些类似的帖子。值得注意的是this (1)this (2)this (3)

在(1)中,通过在调用read()之前放置一个虚拟poll()来解决它。如果我这样做(请参阅代码中注释的read())。我的代码在循环中运行一次,第二次在poll()上永久阻塞。

在(2)中,这可能是一个解释,但并没有真正解决我的问题。

在(3)中,我的lseek()

之前已经有read()

当gpio的poll()发生变化时,如何阻止此value阻止并仅在中断时返回?

以下是代码段:

int read_gpio(char *path, void (*callback)(int)){
    int fd;
    char buf[11];
    int res = 0;
    char c;
    int off;
    struct pollfd gpio_poll_fd = {
        .fd = fd,
        .events = POLLPRI,
        .revents = 0
    };
    for(;;){

        gpio_poll_fd.fd = open(path, O_RDONLY);
        if(fd == -1){
            perror("error opening file");
            return -1;
        }
//        char c;
//        read(fd,&c,1);
        LOGD("for begins");
        res = poll(&gpio_poll_fd,1,-1);
        LOGD("polling ended");
        if(res == -1){
            perror("error polling");
            break;
        }

        if((gpio_poll_fd.revents & POLLPRI)  == POLLPRI){
            LOGD("POLLPRI");
            off = lseek(fd, 0, SEEK_SET);
            if(off == -1) break;
            memset(&buf[0], 0, 11);
            size_t num = read(fd, &buf[0], 10*sizeof(char));
            LOGD("Before callback");
            callback(atoi(buf));
            LOGD("After Callback");
        }
        if((gpio_poll_fd.revents & POLLERR) == POLLERR) {
            //seems always to be true ..
            //LOGD("POLLERR");
        }
        close(fd);
        LOGD("for ends");

    }
    LOGD("for exits");

    return 0;
}

注意:我在Android JNI上这样做,我从LOGD()

获取调试信息

更新的 根据jxh评论中的建议,我已经安排了这样的结构,尽管现在它无限期地阻塞poll()。当值的内容从外部施加的电压改变时,POLLPRI不会变高,并且poll()不会返回:

int read_gpio(char *path, void (*callback)(int)){
    int fd = open(path, O_RDONLY);
    if(fd == -1){
        perror("error opening file");
        return -1;
    }
    char buf[11];
    int res, off;
    char c;
    struct pollfd pfd = {
            .fd = fd,
            .events = POLLPRI,
            .revents = 0
    };
    for(;;){
        LOGD("for begins");
//        dummy read causes poll never to run
//        lseek() alone here cause poll never to run
//        read(fd, &buf[],1);
//        lseek(fd, 0, SEEK_SET);
        res = poll(&pfd,1,-1);
        LOGD("polling ended");
        if(res == -1){
            perror("error polling");
            break;
        }

        if((pfd.revents & POLLPRI)  == POLLPRI){
            LOGD("POLLPRI");
            off = lseek(fd, 0, SEEK_SET);
            if(off == -1) break;
            memset(&buf[0], 0, 11);
            read(fd, &buf[0], 10*sizeof(char));
//            These two lines will cause it to poll constantly
//            close(fd);
//            fd = open(path, O_RDONLY);
            LOGD("Before callback");
            callback(atoi(buf));
            LOGD("After Callback");
        }
        LOGD("for ends");
    }
    close(fd);
    LOGD("for exits");

    return 0;
}

1 个答案:

答案 0 :(得分:4)

在您的代码中,fd未初始化。

当您打开文件时,您直接分配到gpio_poll_fd.fd,而不使用fd,因此fd仍然未初始化。

尝试:

gpio_poll_fd.fd = fd = open(path, O_RDONLY);

正如评论中所指出的,根据GPIO manual(我在仔细阅读这些评论之后才读到),GPIO sysfs界面有点特别:

  

如果引脚可以配置为产生中断的中断           如果它已配置为生成中断(请参阅           “edge”的描述,你可以{i}在那个文件上           只要中断被触发,poll(2)就会返回。如果           您使用poll(2),设置事件poll(2)POLLPRI。如果你           使用POLLERR,在select(2)中设置文件描述符。后           exceptfds poll(2)返回lseek(2)的开头sysfs           文件并读取新值或关闭文件并重新打开它           阅读价值。

所以,虽然它不是典型的poll()习语,但你的结束和重新开放的结构是正确的。但是,我会选择保持文件描述符处于打开状态。所以,我将如何构建您的代码:

int read_gpio(char *path, void (*callback)(int)){
    char buf[11];
    int fd, res, off;
    struct pollfd pfd;
    if((pfd.fd = fd = open(path, O_RDONLY)) == -1){
        perror("path");
        return -1;
    }
    LOGD("First read");
    res = read(fd, buf, 10);
    assert(res == 10);
    LOGD("Before callback");
    callback(atoi(buf));
    LOGD("After Callback");
    pfd.events = POLLPRI|POLLERR;  // poll(2) says setting POLLERR is
                                   // unnecessary, but GPIO may be
                                   // special.
    for(;;){
        LOGD("for begins");
        if((res = poll(&pfd,1,-1)) == -1){
            perror("poll");
            break;
        }
        LOGD("polling ended");
        if((pfd.revents & POLLPRI) == POLLPRI){
            LOGD("POLLPRI");
            off = lseek(fd, 0, SEEK_SET);
            if(off == -1) break;
            memset(buf, 0, 11);
            res = read(fd, buf, 10);
            assert(res == 10);
            LOGD("Before callback");
            callback(atoi(buf));
            LOGD("After Callback");
        } else {
            // POLLERR, POLLHUP, or POLLNVAL
            break;
        }
        LOGD("for ends");
    }
    close(fd);
    LOGD("for exits");

    return 0;
}