Reputation: 76
I have a program that creates a timer using timerfd_create()
and the timer is specified with an interval so that the process is notified regularly. Then this timer is registered to epoll
. The error is Invalid argument when executing read()
in the handler, and the errno
is 22. This error appears when I run this program on my Raspberry Pi (Raspbian, Linux 4.9.80), but everything is fine when I run it on my laptop (Arch, Linux 4.15.15).
The related codes are pasted below. Any help is very much appreciated.
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);
}
}
}
The complete program is hosted on https://github.com/iamlazynic/centralized_wlan/tree/master/cc inside cc.c and main.c.
Except for suggestion on this problem, it would be great if there is advice on how to debug in the situation. Thanks!
Upvotes: 0
Views: 1089
Reputation: 47032
After working through this, we discovered that the typedef for a u64
was wrong and the code was attempting to read to few bytes, which will result in an EINVAL
error code. The typedef was:
typedef unsigned long int u64;
But on a 32-bit system, this is likely on 4 bytes in size. Instead, we used stdint.h and the uint64_t
type (which takes care to typedef things a little more carefully for the platform you're using) and now has the correct size.
Upvotes: 1
Reputation: 11
The following is the synopsis of read function.
ssize_t read(int fildes, void *buf, size_t nbyte);
The second is the buf pointer and the third is the size to read. You set the size to 64 bytes. But the pointer is the address of exp(8bytes) which is assigned at stack. I think it can corrupt the stack.
Upvotes: 1