重复timerfd事件适用于epoll而不是poll

bud*_*888 3 c linux timer polling

我正在使用timerfd 实现一个计时器。这是一个相对计时器,我只需要按照设置的速率永远重复。我想对这个事件进行轮询,最初尝试使用轮询。当我这样做时,我会第一次看到计时器事件,然后就再也看不到了。但是,当我更改为使用 epoll(timerfd 的设置方式完全没有改变)时,它按预期工作。

这是带有轮询的代码:

#include <sys/timerfd.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>

int main(int ac, char *av[])
{
    struct pollfd p;
    int timerfd;
    struct itimerspec timerValue;

    /* clear pollfd */
    bzero(&p, sizeof(p));

    /* set timerfd */
    timerfd = timerfd_create(CLOCK_REALTIME, 0);
    if (timerfd < 0) {
        printf("failed to create timer fd\n");
        exit(1);
    }
    bzero(&timerValue, sizeof(timerValue));
    timerValue.it_value.tv_sec = 1;
    timerValue.it_value.tv_nsec = 0;
    timerValue.it_interval.tv_sec = 1;
    timerValue.it_interval.tv_nsec = 0;

    /* set events */
    p.fd = timerfd;
    p.revents = 0;
    p.events = POLLIN;

    /* start timer */
    if (timerfd_settime(timerfd, 0, &timerValue, NULL) < 0) {
        printf("could not start timer\n");
        exit(1);
    }

    /* wait for events */
    while (1) {
        int numEvents = poll(&p, 1, -1);
        if (numEvents > 0) {
            int timersElapsed = 0;
            (void) read(p.fd, &timersElapsed, 8);
            printf("timers elapsed: %d\n", timersElapsed);
        }
    }

    exit(0);
}
Run Code Online (Sandbox Code Playgroud)

这是 epoll 的代码:

#include <sys/timerfd.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>

int main(int ac, char *av[])
{
    struct epoll_event epollEvent;
    struct epoll_event newEvents;
    int timerfd;
    int epollfd;
    struct itimerspec timerValue;

    /* set timerfd */
    timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
    if (timerfd < 0) {
        printf("failed to create timer fd\n");
        exit(1);
    }
    bzero(&timerValue, sizeof(timerValue));
    timerValue.it_value.tv_sec = 1;
    timerValue.it_value.tv_nsec = 0;
    timerValue.it_interval.tv_sec = 1;
    timerValue.it_interval.tv_nsec = 0;

    /* set events */
    epollfd = epoll_create1(0);
    epollEvent.events = EPOLLIN;
    epollEvent.data.fd = timerfd;
    epoll_ctl(epollfd, EPOLL_CTL_ADD, timerfd, &epollEvent);

    /* start timer */
    if (timerfd_settime(timerfd, 0, &timerValue, NULL) < 0) {
        printf("could not start timer\n");
        exit(1);
    }

    /* wait for events */
    while (1) {
        int numEvents = epoll_wait(epollfd, &newEvents, 1, 0);
        if (numEvents > 0) {
            int timersElapsed = 0;
            (void) read(epollEvent.data.fd, &timersElapsed, 8);
            printf("timers elapsed: %d\n", timersElapsed);
        }
    }

    exit(0);
}
Run Code Online (Sandbox Code Playgroud)

知道我在民意调查中可能做错了什么吗?也许它不适合与timerfd一起使用?谢谢。

小智 5

好吧,这是一个老问题,但无论如何。问题出在这几行代码上:

   int timersElapsed = 0;
   (void) read(p.fd, &timersElapsed, 8);
   printf("timers elapsed: %d\n", timersElapsed);
Run Code Online (Sandbox Code Playgroud)

int timersElapsed是4个字节。读取 8 个字节会导致堆栈溢出,从而产生不可预测的行为。

更改timersElapsed为 along int并修复 printf 对我来说很有效。

   long int timersElapsed = 0;
   (void) read(p.fd, &timersElapsed, 8);
   printf("timers elapsed: %ld\n", timersElapsed);
Run Code Online (Sandbox Code Playgroud)