From 1f3ddd372768ccdddfe0a49f944d1f3320bde25a Mon Sep 17 00:00:00 2001 From: Dridi Boukelmoune Date: Fri, 13 Jun 2025 11:54:16 +0200 Subject: [PATCH 1/3] vefd: Thin emulation layer over eventfd This is a minimal API not attempting to keep track of the eventfd counter, and only caring about threads signalling progress on one end, and another thread being able to notice that progress can be made. This is an alternative to condvars when waiting for progress will content with polling concurrently waiting for progress elsewhere. Since locks/condvars don't compose well with file descriptors, the VEFD API offers an alternative that can integrate an existing poll on other file descriptors. --- include/Makefile.am | 1 + include/vefd.h | 50 +++++++++++++++++ lib/libvarnish/Makefile.am | 1 + lib/libvarnish/vefd.c | 109 +++++++++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 include/vefd.h create mode 100644 lib/libvarnish/vefd.c diff --git a/include/Makefile.am b/include/Makefile.am index 347724d70a8..a44b32ccbd5 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -95,6 +95,7 @@ nobase_noinst_HEADERS = \ vcs_version.h \ vct.h \ vcurses.h \ + vefd.h \ venc.h \ vend.h \ vev.h \ diff --git a/include/vefd.h b/include/vefd.h new file mode 100644 index 00000000000..5f41bada1e7 --- /dev/null +++ b/include/vefd.h @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2025 Varnish Software AS + * All rights reserved. + * + * Author: Dridi Boukelmoune + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +struct vefd { + unsigned magic; +#define VEFD_MAGIC 0x1548c1a6 + int poll_fd; + int priv_fd; +}; + +#define VEFD_INIT(vefd) \ + do { \ + INIT_OBJ(vefd, VEFD_MAGIC); \ + (vefd)->poll_fd = -1; \ + (vefd)->priv_fd = -1; \ + } while (0) + +int VEFD_Open(struct vefd *); +int VEFD_Signal(struct vefd *); +int VEFD_Clear(struct vefd *); +int VEFD_Close(struct vefd *); diff --git a/lib/libvarnish/Makefile.am b/lib/libvarnish/Makefile.am index 22109111070..1e7e984b8bd 100644 --- a/lib/libvarnish/Makefile.am +++ b/lib/libvarnish/Makefile.am @@ -23,6 +23,7 @@ libvarnish_la_SOURCES = \ vcli_serve.c \ vct.c \ venc.c \ + vefd.c \ version.c \ vev.c \ vfil.c \ diff --git a/lib/libvarnish/vefd.c b/lib/libvarnish/vefd.c new file mode 100644 index 00000000000..05860e1004e --- /dev/null +++ b/lib/libvarnish/vefd.c @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 2025 Varnish Software AS + * All rights reserved. + * + * Author: Dridi Boukelmoune + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +int +VEFD_Open(struct vefd *vefd) +{ + int fd[2]; + + CHECK_OBJ_NOTNULL(vefd, VEFD_MAGIC); + assert(vefd->poll_fd == -1); + assert(vefd->priv_fd == -1); + + if (pipe(fd) < 0) + return (-1); + + AZ(fcntl(fd[0], F_SETFL, O_CLOEXEC|O_NONBLOCK)); + AZ(fcntl(fd[1], F_SETFL, O_CLOEXEC|O_NONBLOCK)); + vefd->poll_fd = fd[0]; + vefd->priv_fd = fd[1]; + return (0); +} + +int +VEFD_Signal(struct vefd *vefd) +{ + ssize_t r; + + CHECK_OBJ_NOTNULL(vefd, VEFD_MAGIC); + assert(vefd->poll_fd >= 0); + assert(vefd->priv_fd >= 0); + assert(vefd->poll_fd != vefd->priv_fd); + r = write(vefd->priv_fd, "", 1); + if (r < 0 && errno != EAGAIN && errno != EWOULDBLOCK) + return (-1); + return (0); +} + +int +VEFD_Clear(struct vefd *vefd) +{ + char buf[64]; + ssize_t r; + + CHECK_OBJ_NOTNULL(vefd, VEFD_MAGIC); + assert(vefd->poll_fd >= 0); + assert(vefd->priv_fd >= 0); + assert(vefd->poll_fd != vefd->priv_fd); + do { + r = read(vefd->poll_fd, buf, sizeof buf); + } while (r > 0); + if (errno != EAGAIN && errno != EWOULDBLOCK) + return (-1); + return (0); +} + +int +VEFD_Close(struct vefd *vefd) +{ + + CHECK_OBJ_NOTNULL(vefd, VEFD_MAGIC); + assert(vefd->poll_fd >= 0); + assert(vefd->priv_fd >= 0); + assert(vefd->poll_fd != vefd->priv_fd); + closefd(&vefd->poll_fd); + closefd(&vefd->priv_fd); + return (0); +} From c63dca28ba1542bc530d9a79498259203c347a15 Mon Sep 17 00:00:00 2001 From: Dridi Boukelmoune Date: Fri, 13 Jun 2025 12:05:17 +0200 Subject: [PATCH 2/3] build: Detect eventfd() at configure time --- configure.ac | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index 2483dfeac2b..4ff0d3eb652 100644 --- a/configure.ac +++ b/configure.ac @@ -483,6 +483,8 @@ else ac_cv_func_port_create=no fi +AC_CHECK_FUNCS([eventfd]) + # --with-persistent-storage AC_ARG_WITH(persistent-storage, AS_HELP_STRING([--with-persistent-storage], From 2488afdd93a386fb4a78404999720b000238d852 Mon Sep 17 00:00:00 2001 From: Dridi Boukelmoune Date: Fri, 13 Jun 2025 12:15:22 +0200 Subject: [PATCH 3/3] vefd: Use eventfd() when available --- lib/libvarnish/vefd.c | 56 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/lib/libvarnish/vefd.c b/lib/libvarnish/vefd.c index 05860e1004e..8be1c703115 100644 --- a/lib/libvarnish/vefd.c +++ b/lib/libvarnish/vefd.c @@ -32,8 +32,13 @@ #include "config.h" +#if HAVE_EVENTFD +# include +#else +# include +#endif + #include -#include #include #include #include @@ -43,6 +48,54 @@ #include #include +#if HAVE_EVENTFD +int +VEFD_Open(struct vefd *vefd) +{ + + CHECK_OBJ_NOTNULL(vefd, VEFD_MAGIC); + assert(vefd->poll_fd == -1); + assert(vefd->priv_fd == -1); + + vefd->poll_fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); + return (vefd->poll_fd); +} + +int +VEFD_Signal(struct vefd *vefd) +{ + int64_t buf = 1; + + CHECK_OBJ_NOTNULL(vefd, VEFD_MAGIC); + assert(vefd->poll_fd >= 0); + assert(vefd->priv_fd == -1); + assert(write(vefd->poll_fd, &buf, sizeof buf) == sizeof buf); + return (0); +} + +int +VEFD_Clear(struct vefd *vefd) +{ + int64_t buf; + + CHECK_OBJ_NOTNULL(vefd, VEFD_MAGIC); + assert(vefd->poll_fd >= 0); + assert(vefd->priv_fd == -1); + assert(read(vefd->poll_fd, &buf, sizeof buf) == sizeof buf); + return (0); +} + +int +VEFD_Close(struct vefd *vefd) +{ + + CHECK_OBJ_NOTNULL(vefd, VEFD_MAGIC); + assert(vefd->poll_fd >= 0); + assert(vefd->priv_fd == -1); + closefd(&vefd->poll_fd); + return (0); +} +#else /* !HAVE_EVENTFD */ int VEFD_Open(struct vefd *vefd) { @@ -107,3 +160,4 @@ VEFD_Close(struct vefd *vefd) closefd(&vefd->priv_fd); return (0); } +#endif /* HAVE_EVENTFD */