a_loop_{add,mod,del}_fd
These functions can fail, however, they are declared void, so there is no good way to get error information from the functions.
This is the internal code of these functions:
void a_loop_add_fd(int epfd, int fd, uint32_t events)
{
if (fd < 0) {
L_WARNING("Tried to add invalid fd to epoll: %d", fd);
return;
} else if (fd == 0) {
L_WARNING("Adding fd 0 to epoll. This is usually stdin.");
}
static struct epoll_event ev;
ev.events = events;
ev.data.fd = fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev);
}
void a_loop_del_fd(int epfd, int fd)
{
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
}
void a_loop_mod_fd(int epfd, int fd, uint32_t events)
{
static struct epoll_event ev;
ev.events = events;
ev.data.fd = fd;
epoll_ctl(epfd, EPOLL_CTL_MOD, ev.data.fd, &ev);
}
epoll_ctl
may return -1 and set errno, but that is lost for the caller.
We recommend to use epoll_ctl
directly, or using wrappers that return the
status of the function call, e.g.:
int a_loop_add_fd(int epfd, int fd, uint32_t events)
{
if (fd == 0) {
L_WARNING("Adding fd 0 to epoll. This is usually stdin.");
}
static struct epoll_event ev;
ev.events = events;
ev.data.fd = fd;
return epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev);
}
int a_loop_del_fd(int epfd, int fd)
{
return epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
}
int a_loop_mod_fd(int epfd, int fd, uint32_t events)
{
static struct epoll_event ev;
ev.events = events;
ev.data.fd = fd;
return epoll_ctl(epfd, EPOLL_CTL_MOD, ev.data.fd, &ev);
}
a_timer_create
This function may clobber errno and takes the struct itimerspec
by value, it
also returns a non-standard negative value on error (-2).
This is the internal code of the function:
int a_timer_create(struct itimerspec ts)
{
int timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
if (timer_fd == -1) {
L_ERROR("timerfd_create() failed: errno=%d", errno);
return -1;
}
if (timerfd_settime(timer_fd, 0, &ts, NULL) < 0) {
L_ERROR("timerfd_settime() failed: errno=%d", errno);
close(timer_fd);
return -2;
}
return timer_fd;
}
close
can clobber the errno value, not taking the struct itimerspec
by
const reference involves an implicit memcpy each call.
We recommend to use timerfd_create
and timerfd_settime
directly, or
using a wrapper that takes the struct itimerspec
by const reference, and
preserves errno:
int a_timer_create(const struct itimerspec* ts)
{
int timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
if (timer_fd == -1) {
L_ERROR("timerfd_create() failed: errno=%d", errno);
return -1;
}
if (timerfd_settime(timer_fd, 0, ts, NULL) < 0) {
int saved_errno = errno;
L_ERROR("timerfd_settime() failed: errno=%d", errno);
close(timer_fd);
errno = saved_errno;
return -1;
}
return timer_fd;
}