You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
196 lines
4.1 KiB
C
196 lines
4.1 KiB
C
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <sys/epoll.h>
|
|
#include <sys/timerfd.h>
|
|
|
|
#include "eventloop_platform.h"
|
|
#include "public/io.h"
|
|
|
|
struct tlsl_event_platform {
|
|
int epoll_registered_fd;
|
|
bool epoll_fd_owned;
|
|
};
|
|
|
|
struct tlsl_eventloop_platform {
|
|
int epoll_fd;
|
|
};
|
|
|
|
int tlsl_platform_el_init(struct tlsl_eventloop *el) {
|
|
TLSL_DEFINE_PLATFORM_EVENTLOOP_DATA(el, elp);
|
|
|
|
if ((elp->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
void tlsl_platform_el_cleanup(struct tlsl_eventloop *el) {
|
|
TLSL_DEFINE_PLATFORM_EVENTLOOP_DATA(el, elp);
|
|
|
|
close(elp->epoll_fd);
|
|
}
|
|
|
|
void tlsl_platform_el_event_remove(struct tlsl_eventloop *el, struct tlsl_event *e) {
|
|
TLSL_DEFINE_PLATFORM_EVENTLOOP_DATA(el, elp);
|
|
TLSL_DEFINE_PLATFORM_EVENT_DATA(e, ep);
|
|
|
|
epoll_ctl(elp->epoll_fd, EPOLL_CTL_DEL, ep->epoll_registered_fd, NULL);
|
|
}
|
|
|
|
void tlsl_platform_el_event_cleanup(struct tlsl_eventloop *el, struct tlsl_event *e) {
|
|
TLSL_DEFINE_PLATFORM_EVENT_DATA(e, ep);
|
|
|
|
(void)el;
|
|
|
|
if (ep->epoll_fd_owned && (ep->epoll_registered_fd >= 0)) {
|
|
close(ep->epoll_registered_fd);
|
|
ep->epoll_registered_fd = -1;
|
|
}
|
|
}
|
|
|
|
static int clear_timerfd(int fd) {
|
|
uint64_t tfd_buf;
|
|
ssize_t res;
|
|
|
|
do {
|
|
res = read(fd, &tfd_buf, sizeof(tfd_buf));
|
|
} while ((res < 0) && (errno == EINTR));
|
|
|
|
if (res < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int tlsl_platform_el_event_clear(struct tlsl_eventloop *el, struct tlsl_event *e) {
|
|
TLSL_DEFINE_PLATFORM_EVENT_DATA(e, ep);
|
|
int res;
|
|
|
|
(void)el;
|
|
|
|
if ((e->id.source == TLSL_EVENT_SOURCE_TIMER) && (ep->epoll_registered_fd >= 0)) {
|
|
if ((res = clear_timerfd(ep->epoll_registered_fd)))
|
|
return res;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int tlsl_platform_el_wait(
|
|
struct tlsl_eventloop *el,
|
|
tlsl_event_id_t *id_out,
|
|
uint32_t *flags_out,
|
|
int timeout_ms)
|
|
{
|
|
TLSL_DEFINE_PLATFORM_EVENTLOOP_DATA(el, elp);
|
|
struct epoll_event ev;
|
|
struct tlsl_event *e;
|
|
int res;
|
|
|
|
if (timeout_ms < 0)
|
|
timeout_ms = -1;
|
|
|
|
do {
|
|
res = epoll_pwait(elp->epoll_fd, &ev, 1, timeout_ms, NULL);
|
|
} while ((res < 0) && (errno == EINTR));
|
|
|
|
if (res <= 0) {
|
|
if (!res)
|
|
errno = ETIMEDOUT;
|
|
return -1;
|
|
}
|
|
|
|
e = (struct tlsl_event *)ev.data.ptr;
|
|
|
|
*id_out = e->id;
|
|
*flags_out = 0;
|
|
|
|
if (ev.events & EPOLLIN)
|
|
*flags_out |= TLSL_EVENT_READABLE;
|
|
if (ev.events & EPOLLOUT)
|
|
*flags_out |= TLSL_EVENT_WRITABLE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int el_epoll_add(
|
|
struct tlsl_eventloop *el,
|
|
struct tlsl_event *e,
|
|
int fd,
|
|
enum tlsl_event_source source,
|
|
uint32_t events,
|
|
bool owned)
|
|
{
|
|
TLSL_DEFINE_PLATFORM_EVENTLOOP_DATA(el, elp);
|
|
TLSL_DEFINE_PLATFORM_EVENT_DATA(e, ep);
|
|
struct epoll_event ev;
|
|
|
|
memset(&ev, 0, sizeof(ev));
|
|
ev.events = events;
|
|
ev.data.fd = fd;
|
|
ev.data.ptr = e;
|
|
|
|
if (epoll_ctl(elp->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
|
|
return -1;
|
|
|
|
e->id.obj = (uintptr_t)fd;
|
|
e->id.source = source;
|
|
ep->epoll_registered_fd = fd;
|
|
ep->epoll_fd_owned = owned;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int tlsl_platform_el_add_timer(
|
|
struct tlsl_eventloop *el,
|
|
struct tlsl_event *e,
|
|
uint64_t millis,
|
|
bool oneshot)
|
|
{
|
|
FD_SCOPED(tfd);
|
|
struct itimerspec spec;
|
|
struct timespec ts;
|
|
int res;
|
|
|
|
ts.tv_sec = (long)(millis / 1000);
|
|
ts.tv_nsec = (long)((millis % 1000) * 1000000);
|
|
|
|
memset(&spec, 0, sizeof(spec));
|
|
spec.it_value = ts;
|
|
if (!oneshot)
|
|
spec.it_interval = ts;
|
|
|
|
if ((tfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC)) < 0)
|
|
return -1;
|
|
|
|
if (timerfd_settime(tfd, 0, &spec, NULL))
|
|
return -1;
|
|
|
|
if ((res = el_epoll_add(el, e, tfd, TLSL_EVENT_SOURCE_TIMER, EPOLLIN, true)))
|
|
return res;
|
|
|
|
FD_RELEASE(&tfd);
|
|
return 0;
|
|
}
|
|
|
|
int tlsl_platform_el_add_fd(
|
|
struct tlsl_eventloop *el,
|
|
struct tlsl_event *e,
|
|
int fd,
|
|
uint32_t flags)
|
|
{
|
|
uint32_t events;
|
|
|
|
events = 0;
|
|
if (flags & TLSL_EVENT_READABLE)
|
|
events |= EPOLLIN;
|
|
if (flags & TLSL_EVENT_WRITABLE)
|
|
events |= EPOLLOUT;
|
|
|
|
return el_epoll_add(el, e, fd, TLSL_EVENT_SOURCE_FD, events, false);
|
|
}
|