2017-01-12 11 views
0

Я собираюсь использовать epoll для проверки timerfd и запускать некоторые действия. Код раздув:timerfd не будет готов к чтению при использовании epoll

#include <time.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <sys/timerfd.h> 
#include <stdint.h> 
#include <unistd.h> 
#include <sys/epoll.h> 

int main(int argc, char const *argv[]) 
{ 
    struct timespec now; 
    clock_gettime(CLOCK_MONOTONIC, &now); 
    int timerfd; 
    timerfd = timerfd_create(CLOCK_MONOTONIC, 0); 
    struct itimerspec new_value; 
    new_value.it_value.tv_sec = 1; 
    new_value.it_interval.tv_sec = 1; 
    timerfd_settime(timerfd, 0, &new_value, NULL); 
    // uint64_t buff; 
    // while(true) { 
    // read(timerfd, &buff, sizeof(uint64_t)); 
    // printf("%s\n", "ding"); 
    // } 

    // code above works fine. 

    struct epoll_event ev, events[10]; 
    int epollfd; 
    epollfd = epoll_create1(0); 
    if (epollfd == -1) { 
     perror("epoll_create1"); 
     exit(EXIT_FAILURE); 
    } 
    ev.events = EPOLLIN; 
    ev.data.fd = timerfd; 

    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, timerfd, &ev) == -1) { 
     perror("epoll_ctl: timerfd"); 
     exit(EXIT_FAILURE); 
    } 
    int num; 
    printf("start\n"); 
    while(true) { 
     num = epoll_wait(epollfd, events, 10, -1); 
     printf("%d\n", num); 
     uint64_t buff; 
     read(timerfd, &buff, sizeof(uint64_t)); 
     printf("%s\n", "ding"); 
    } 
    return 0; 
} 

При использовании timerfd отдельно, она отлично работает. Каждая секунда будет печатать «ding». Но, добавляя epoll для наблюдения timerfd, прогром будет блокироваться на epoll_wait навсегда. Я попробовал использовать EPOLLET, но отметил, что изменился. Что случилось с этим кодом?

ответ

3

Ваш itimerspec не был правильно инициализирован, поэтому в зависимости от того, какие конкретные значения мусора он содержит, timerfd_settime() может потерпеть неудачу. Для того, чтобы обнаружить, что делать проверку на наличие ошибок:

if (timerfd_settime(timerfd, 0, &new_value, NULL) != 0) { 
     perror("settime"); 
     exit(-1); 
} 

Другой способ отладки это запустить программу под, программы strace, и вы увидите, какие, если таковые имеются, системные вызовы, которые не удается.

Релевантном структур выглядит следующим образом:

struct timespec { 
    time_t tv_sec; 
    long tv_nsec; 
}; 

struct itimerspec { 
    struct timespec it_interval; 
    struct timespec it_value; 
}; 

Вы должны инициализировать оба эти элементы полностью, и ваша программа будет работать надежно:

new_value.it_value.tv_sec = 1; 
new_value.it_value.tv_nsec = 0; 
new_value.it_interval.tv_sec = 1; 
new_value.it_interval.tv_nsec = 0; 
+0

Почему это downvoted без комментариев? Это почти наверняка правильный ответ. Неинициализированный мусор в tv_nsec, превышающий миллиард, определенно приведет к наблюдаемому поведению (я только что протестировал), а при правильной инициализации он заставит код работать. Кроме того, добавление большего количества кода, вероятно, приведет к перестановке стека и изменению неинициализированных значений в таймерах. – Art

+0

Этот ответ действительно правильный ответ, я заплатил щедрость. Но даже я использую предложение переписать код, я не знаю, зачем использовать чтение без полностью инициализированных работ, кто-нибудь может сказать мне, почему? – reavenisadesk

+0

@reavenisadesk Вероятно, потому что в этом случае переменные содержали значения мусора, которые все еще были действительными значениями, в то время как небольшое изменение кода, и мусор мог измениться и был вне допустимого диапазона для 'tv_nsec' – nos