【发布时间】:2018-04-21 14:20:26
【问题描述】:
我有一个程序,它使用timerfd_create() 创建一个计时器,并指定了一个时间间隔,以便定期通知进程。然后这个定时器注册到epoll。在处理程序中执行read()时,错误是Invalid argument,errno是22。当我在我的Raspberry 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/cc 内cc.c 和main.c。
除了关于这个问题的建议之外,如果有关于如何在这种情况下调试的建议,那就太好了。谢谢!
【问题讨论】:
-
您可能会将 64 字节读入一个 8 字节变量(
sizeof(exp) == 8不是 64)。通常最好做这样的事情read(tfd, &exp, sizeof(exp))来避免这种错误。 -
@jszakmeister 对不起。我在问题中修复了该行,但实际上我的原始程序对此是正确的。当我将其粘贴到此处时,我出于某种愚蠢的原因更改了该行并犯了这个错误。不过谢谢指出。
read()的错误不是因为这个。 -
不用担心,但是上面的代码仍然是错误的。 :-) 你在
sizeof(exp)之后缺少一个括号。 -
另外,你确定你的u64实际上是8字节吗? timerfd_create() 的手册页说,如果缓冲区太小,您可以获得
EINVAL(这就是您所看到的)。我可以在您的原始代码中看到您将 u64 键入unsigned long int。但是,如果您的 Pi 是 32 位处理器,则sizeof(u64)是 4,而不是 8。您必须在 32 位平台上将其 typedef 为unsigned long long int。考虑使用 stdint.h 来避免这些问题并改用 uint64_t ——它已经完成了弄清楚如何正确 typedef 的艰苦工作。 :-)