udev: finish the kqueue code path so the BSDs no longer need libepoll-shim

udev_input.c had a half-written kqueue alternative to epoll behind a
"#if 1 / TODO" that hard-selected epoll everywhere, which is why the
FreeBSD games/retroarch port has to link the udev input driver against
libepoll-shim (UDEV_LIB_DEPENDS/UDEV_CFLAGS/UDEV_LDFLAGS in the port).

Complete it: on FreeBSD, OpenBSD, NetBSD, DragonFly and macOS the evdev
fds are registered with EV_SET(EVFILT_READ, EV_ADD, udata = device)
(the placeholder referenced an undefined LISTENSOCKET), the poll uses a
zero timespec like the epoll_wait(..., 0) it mirrors (the placeholder
referenced an undefined `timeout`), and the event loop tests
filter == EVFILT_READ && !(flags & EV_ERROR) instead of the epoll-only
`events & EPOLLIN`.  kqueue is level-triggered by default so the
drain-until-EAGAIN read loop is unchanged, and closing a device fd
removes it from the kqueue just as it does from the epoll set.
NetBSD's kevent.udata is intptr_t rather than void *, hence the
UDEV_KQ_UDATA cast.

Linux still uses epoll; that object is unchanged.  The kqueue variant
was compiled with libkqueue's <sys/event.h> to catch type errors.

CI: the FreeBSD job now fails if the linked retroarch binary still
imports any epoll_* symbol.
This commit is contained in:
LibretroAdmin authored and libretroadmin committed 2026-09-27 18:34:07 +02:00
1 parent 422ed61c9d
commit 4e1eb70caa
2 files changed
+25 -14

No files matched your search

+5
View File
@@ -71,6 +71,11 @@ jobs:
gmake -j$NCPU clean
gmake -j$NCPU info all
./retroarch --version
# udev input must multiplex with kqueue here, so the binary
# must not need libepoll-shim's epoll_* at all.
if nm -u retroarch | grep -q 'epoll_'; then
echo "retroarch still references epoll (libepoll-shim)"; exit 1
fi
# With v4l_compat the V4L2 camera and video processor core
# must still compile; only those two objects are rebuilt.
+20 -14
View File
@@ -14,18 +14,12 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
/* TODO/FIXME - set this once the kqueue codepath is implemented and working properly,
* also remove libepoll-shim from the Makefile when that happens. */
#if 1
#define HAVE_EPOLL
#else
#ifdef __linux__
#define HAVE_EPOLL 1
#endif
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__)
/* Linux multiplexes the evdev fds with epoll; the BSDs and macOS use
* kqueue natively so no libepoll-shim is needed there. */
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
#define HAVE_KQUEUE 1
#endif
#else
#define HAVE_EPOLL 1
#endif
#include <stdint.h>
@@ -43,6 +37,13 @@
#include <sys/epoll.h>
#elif defined(HAVE_KQUEUE)
#include <sys/event.h>
#include <sys/time.h>
/* NetBSD declares kevent.udata as intptr_t, everyone else as void *. */
#if defined(__NetBSD__)
#define UDEV_KQ_UDATA(ptr) ((intptr_t)(ptr))
#else
#define UDEV_KQ_UDATA(ptr) ((void*)(ptr))
#endif
#endif
#include <poll.h>
@@ -3295,7 +3296,7 @@ static int udev_input_add_device(udev_input_t *udev,
fd, strerror(errno));
}
#elif defined(HAVE_KQUEUE)
EV_SET(&event, fd, EVFILT_READ, EV_ADD, 0, 0, LISTENSOCKET);
EV_SET(&event, fd, EVFILT_READ, EV_ADD, 0, 0, UDEV_KQ_UDATA(device));
if (kevent(udev->fd, &event, 1, NULL, 0, NULL) == -1)
{
RARCH_ERR("[udev] Failed to add FD (%d) to kqueue list (%s).\n",
@@ -3540,8 +3541,9 @@ static void udev_input_poll(void *data)
ret = epoll_wait(udev->fd, events, ARRAY_SIZE(events), 0);
#elif defined(HAVE_KQUEUE)
{
/* Zero timeout: drain what is pending, never block the frame. */
struct timespec timeoutspec;
timeoutspec.tv_sec = timeout;
timeoutspec.tv_sec = 0;
timeoutspec.tv_nsec = 0;
ret = kevent(udev->fd, NULL, 0, events,
ARRAY_SIZE(events), &timeoutspec);
@@ -3550,8 +3552,12 @@ static void udev_input_poll(void *data)
for (i = 0; i < ret; i++)
{
/* TODO/FIXME - add HAVE_EPOLL/HAVE_KQUEUE codepaths here */
#if defined(HAVE_EPOLL)
if (events[i].events & EPOLLIN)
#elif defined(HAVE_KQUEUE)
if ( events[i].filter == EVFILT_READ
&& !(events[i].flags & EV_ERROR))
#endif
{
int j, len;
struct input_event input_events[32];