]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
msg/async/Event: use eventfd on Linux
authorMax Kellermann <max.kellermann@ionos.com>
Mon, 30 Sep 2024 10:39:03 +0000 (12:39 +0200)
committerMax Kellermann <max.kellermann@ionos.com>
Wed, 21 May 2025 06:00:43 +0000 (08:00 +0200)
eventfd is Linux's first-choice tool for waking up I/O event loops.
It is faster and more robust than pipes - it does not need a list of
pipe buffers, cannot become full, and writing/reading to it is a
simple memory access.

eventfd has been available since Linux 2.6.22, therefore this patch
does not do any configure-time checks and no runtime fallback.  If
we're __linux__, it must be available.

To avoid an ABI breakage, both fields `notify_receive_fd` and
`notify_send_fd` remain, both set to the same eventfd value.

Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
src/msg/async/Event.cc

index 16abb1368b0249ea27edcf29fcec884fafe71ea9..9e53821b200c3312afcf3cc25b8968e7d9ec2481 100644 (file)
 #endif
 #endif
 
+#ifdef __linux__
+#include <sys/eventfd.h>
+#endif
+
 #define dout_subsys ceph_subsys_ms
 
 #undef dout_prefix
@@ -48,6 +52,10 @@ class C_handle_notify : public EventCallback {
  public:
   C_handle_notify(EventCenter *c, CephContext *cc): center(c), cct(cc) {}
   void do_request(uint64_t fd_or_id) override {
+#ifdef __linux__
+    eventfd_t value;
+    read(fd_or_id, &value, sizeof(value));
+#else
     char c[256];
     int r = 0;
     do {
@@ -61,6 +69,7 @@ class C_handle_notify : public EventCallback {
           ldout(cct, 1) << __func__ << " read notify pipe failed: " << cpp_strerror(ceph_sock_errno()) << dendl;
       }
     } while (r > 0);
+#endif
   }
 };
 
@@ -154,6 +163,16 @@ int EventCenter::init(int nevent, unsigned center_id, const std::string &type)
   if (!driver->need_wakeup())
     return 0;
 
+#ifdef __linux__
+  int efd = eventfd(0, EFD_NONBLOCK|EFD_CLOEXEC);
+  if (efd < 0) {
+    const int e = errno;
+    lderr(cct) << __func__ << " can't create eventfd: " << cpp_strerror(e) << dendl;
+    return -e;
+  }
+
+  notify_receive_fd = notify_send_fd = efd;
+#else
   int fds[2];
 
   #ifdef _WIN32
@@ -177,6 +196,7 @@ int EventCenter::init(int nevent, unsigned center_id, const std::string &type)
   if (r < 0) {
     return r;
   }
+#endif
 
   return r;
 }
@@ -197,8 +217,12 @@ EventCenter::~EventCenter()
 
   if (notify_receive_fd >= 0)
     compat_closesocket(notify_receive_fd);
+#ifndef __linux__
+  /* on Linux, notify_receive_fd and notify_send_fd are the same
+     eventfd, therefore we close only one of them */
   if (notify_send_fd >= 0)
     compat_closesocket(notify_send_fd);
+#endif
 
   delete driver;
   if (notify_handler)
@@ -347,7 +371,11 @@ void EventCenter::wakeup()
     return ;
 
   ldout(cct, 20) << __func__ << dendl;
+#ifdef __linux__
+  static constexpr eventfd_t buf = 1;
+#else
   static constexpr char buf = 'c';
+#endif
   // wake up "event_wait"
   #ifdef _WIN32
   int n = send(notify_send_fd, &buf, sizeof(buf), 0);