来自timerfd的read()时参数无效

时间:2018-04-21 14:20:27

标签: c linux debugging

我有一个使用timerfd_create()创建计时器的程序,并且定时器被指定为一个间隔,以便定期通知进程。然后此计时器注册到epoll。误差的无效的参数执行时read()在处理程序,和errno是22,当我在我的覆盆子PI(Raspbian,Linux的4.9运行此程序,将出现此错误.80),但是当我在笔记本电脑上运行时,一切都很好(Arch,Linux 4.15.15)。

相关代码粘贴在下面。非常感谢任何帮助。

void epset_reg(int epfd, int fd, u32 events)
{
    struct epoll_event ev;

    memset(&ev, 0, sizeof(ev));
    ev.data.fd = fd;
    ev.events = events;
    if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) < 0)
        handle_err("epoll_ctl");
}

int init_timer(u32 interval)
{
    int tfd;
    struct itimerspec tspec;

    /* specify the timer */
    tspec.it_value.tv_sec = 1;
    tspec.it_value.tv_nsec = 0;
    tspec.it_interval.tv_sec = interval;
    tspec.it_interval.tv_nsec = 0;

    /* create timerfd */
    if ((tfd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0)
        handle_err("timerfd_create");

    /* arm (start) the periodic timer */
    if (timerfd_settime(tfd, TFD_TIMER_ABSTIME, &tspec, NULL) < 0)
        handle_err("timerfd_settime");

    return tfd;
}

void handler(int tfd)
{
    u64 exp;

    /* THE ERROR ! */
    if (read(tfd, &exp, sizeof(exp)) < 0)
        handle_err("read");

    /* irrelevant parts */
}

int main()
{
    int epfd, tfd, sock, nfds, i;
    struct epoll_event events[MAX_EVENTS];

    /* create new epoll instance */
    if ((epfd = epoll_create1(0)) < 0)
        handle_err("epoll_create1");

    /* obtain timerfd */
    tfd = init_timer(TIMER_INTERVAL);
    /* obtain socket to listen */
    sock = init_socket(CC_PORT);

    /* register sock and tfd to epoll set */
    epset_reg(epfd, tfd, EPOLLIN);
    epset_reg(epfd, sock, EPOLLIN | EPOLLET);

    for (;;) {
        if ((nfds = epoll_wait(epfd, events, MAX_EVENTS, -1)) < 0)
            handle_err("epoll_wait");

        for (i = 0; i < nfds; ++i) {
            if ((events[i].events & EPOLLERR) ||
                (events[i].events & EPOLLHUP) ||
                (!(events[i].events & EPOLLIN))) {
                fprintf(stderr, "epoll\n");
                close(events[i].data.fd);
                continue;
            }

            if (events[i].data.fd == tfd)
                handler(tfd);
            else if (events[i].data.fd == sock)
                accept_conn(sock, epfd);
            else
                handle_message(events[i].data.fd);
        }
    }
}

完整的程序位于https://github.com/iamlazynic/centralized_wlan/tree/master/cccc.c内的main.c

除了有关这个问题的建议外,如果有关于如何在这种情况下进行调试的建议,那将会很棒。谢谢!

2 个答案:

答案 0 :(得分:1)

以下是读取功能的概要。

ssize_t read(int fildes,void * buf,size_t nbyte);

第二个是buf指针,第三个是要读取的大小。您将大小设置为64字节。但是指针是在堆栈处分配的exp(8字节)的地址。我认为它可以破坏堆栈。

答案 1 :(得分:1)

完成此操作后,我们发现u64的typedef错误,代码尝试读取几个字节,这将导致EINVAL错误代码。 typedef是:

typedef unsigned long int u64;

但是在32位系统上,这可能是4个字节的大小。相反,我们使用了stdint.h和uint64_t类型(它会为您正在使用的平台更加谨慎地键入dede)并且现在具有正确的大小。