LCOV - code coverage report
Current view: top level - src/util - edge.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 64 90 71.1 %
Date: 2026-06-25 07:23:43 Functions: 12 12 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2020-2024 The Dash Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <util/edge.h>
       6             : 
       7             : #include <logging.h>
       8             : #include <util/sock.h>
       9             : 
      10             : #ifdef USE_EPOLL
      11             : #include <sys/epoll.h>
      12             : #endif
      13             : 
      14             : #ifdef USE_KQUEUE
      15             : #include <sys/event.h>
      16             : #endif
      17             : 
      18        5642 : EdgeTriggeredEvents::EdgeTriggeredEvents(SocketEventsMode events_mode)
      19             :     : m_mode(events_mode)
      20        2821 : {
      21             :     if (m_mode == SocketEventsMode::EPoll) {
      22             : #ifdef USE_EPOLL
      23             :         m_fd = epoll_create1(0);
      24             :         if (m_fd == -1) {
      25             :             LogPrintf("Unable to initialize EdgeTriggeredEvents, epoll_create1 returned -1 with error %s\n",
      26             :                       NetworkErrorString(WSAGetLastError()));
      27             :             return;
      28             :         }
      29             : #else
      30             :         LogPrintf("Attempting to initialize EdgeTriggeredEvents for epoll without support compiled in!\n");
      31             :         return;
      32             : #endif /* USE_EPOLL */
      33             :     } else if (m_mode == SocketEventsMode::KQueue) {
      34             : #ifdef USE_KQUEUE
      35             :         m_fd = kqueue();
      36             :         if (m_fd == -1) {
      37             :             LogPrintf("Unable to initialize EdgeTriggeredEvents, kqueue returned -1 with error %s\n",
      38             :                       NetworkErrorString(WSAGetLastError()));
      39             :             return;
      40             :         }
      41             : #else
      42             :         LogPrintf("Attempting to initialize EdgeTriggeredEvents for kqueue without support compiled in!\n");
      43             :         return;
      44             : #endif /* USE_KQUEUE */
      45             :     } else {
      46             :         assert(false);
      47             :     }
      48             :     m_valid = true;
      49        2821 : }
      50             : 
      51        5642 : EdgeTriggeredEvents::~EdgeTriggeredEvents()
      52        2821 : {
      53        2821 :     if (m_valid) {
      54             : #if defined(USE_KQUEUE) || defined(USE_EPOLL)
      55        2821 :         if (close(m_fd) != 0) {
      56           0 :             LogPrintf("Destroying EdgeTriggeredEvents instance, close() failed for m_fd = %d with error %s\n", m_fd,
      57             :                       NetworkErrorString(WSAGetLastError()));
      58           0 :         }
      59             : #else
      60             :         assert(false);
      61             : #endif /* defined(USE_KQUEUE) || defined(USE_EPOLL) */
      62        2821 :     }
      63        5642 : }
      64             : 
      65        5857 : bool EdgeTriggeredEvents::RegisterEntity(int entity, const std::string& entity_name) const
      66             : {
      67        5857 :     assert(m_valid);
      68             : 
      69        5857 :     if (m_mode == SocketEventsMode::EPoll) {
      70             : #ifdef USE_EPOLL
      71             :         epoll_event event;
      72             :         event.data.fd = entity;
      73             :         event.events = EPOLLIN;
      74             :         if (epoll_ctl(m_fd, EPOLL_CTL_ADD, entity, &event) != 0) {
      75             :             LogPrintf("Failed to add %s to epoll fd (epoll_ctl returned error %s)\n", entity_name,
      76             :                       NetworkErrorString(WSAGetLastError()));
      77             :             return false;
      78             :         }
      79             : #else
      80           0 :         assert(false);
      81             : #endif /* USE_EPOLL */
      82        5857 :     } else if (m_mode == SocketEventsMode::KQueue) {
      83             : #ifdef USE_KQUEUE
      84             :         struct kevent event;
      85        5857 :         EV_SET(&event, entity, EVFILT_READ, EV_ADD, 0, 0, nullptr);
      86        5857 :         if (kevent(m_fd, &event, 1, nullptr, 0, nullptr) != 0) {
      87           0 :             LogPrintf("Failed to add %s to kqueue fd (kevent returned error %s)\n", entity_name,
      88             :                       NetworkErrorString(WSAGetLastError()));
      89           0 :             return false;
      90             :         }
      91             : #else
      92             :         assert(false);
      93             : #endif /* USE_KQUEUE */
      94        5857 :     } else {
      95           0 :         assert(false);
      96             :     }
      97        5857 :     return true;
      98        5857 : }
      99             : 
     100        5857 : bool EdgeTriggeredEvents::UnregisterEntity(int entity, const std::string& entity_name) const
     101             : {
     102        5857 :     assert(m_valid);
     103             : 
     104        5857 :     if (m_mode == SocketEventsMode::EPoll) {
     105             : #ifdef USE_EPOLL
     106             :         if (epoll_ctl(m_fd, EPOLL_CTL_DEL, entity, nullptr) != 0) {
     107             :             LogPrintf("Failed to remove %s from epoll fd (epoll_ctl returned error %s)\n", entity_name,
     108             :                       NetworkErrorString(WSAGetLastError()));
     109             :             return false;
     110             :         }
     111             : #else
     112           0 :         assert(false);
     113             : #endif /* USE_EPOLL */
     114        5857 :     } else if (m_mode == SocketEventsMode::KQueue) {
     115             : #ifdef USE_KQUEUE
     116             :         struct kevent event;
     117        5857 :         EV_SET(&event, entity, EVFILT_READ, EV_DELETE, 0, 0, nullptr);
     118        5857 :         if (kevent(m_fd, &event, 1, nullptr, 0, nullptr) != 0) {
     119           0 :             LogPrintf("Failed to remove %s from kqueue fd (kevent returned error %s)\n", entity_name,
     120             :                       NetworkErrorString(WSAGetLastError()));
     121           0 :             return false;
     122             :         }
     123             : #else
     124             :         assert(false);
     125             : #endif /* USE_KQUEUE */
     126        5857 :     } else {
     127           0 :         assert(false);
     128             :     }
     129        5857 :     return true;
     130        5857 : }
     131             : 
     132        3036 : bool EdgeTriggeredEvents::AddSocket(SOCKET socket) const
     133             : {
     134        3036 :     return RegisterEntity(socket, "socket");
     135           0 : }
     136             : 
     137        3036 : bool EdgeTriggeredEvents::RemoveSocket(SOCKET socket) const
     138             : {
     139        3036 :     return UnregisterEntity(socket, "socket");
     140           0 : }
     141             : 
     142        2821 : bool EdgeTriggeredEvents::RegisterPipe(int wakeup_pipe)
     143             : {
     144        2821 :     if (m_pipe_registered) {
     145           0 :         LogPrintf("Pipe already registered, ignoring new registration request\n");
     146           0 :         return false;
     147             :     }
     148        2821 :     bool ret = RegisterEntity(wakeup_pipe, "wakeup pipe");
     149        2821 :     if (ret) m_pipe_registered = true;
     150        2821 :     return ret;
     151        2821 : }
     152             : 
     153        2821 : bool EdgeTriggeredEvents::UnregisterPipe(int wakeup_pipe)
     154             : {
     155        2821 :     if (!m_pipe_registered) {
     156           0 :         LogPrintf("No pipe currently registered to unregister, ignoring request\n");
     157           0 :         return false;
     158             :     }
     159        2821 :     bool ret = UnregisterEntity(wakeup_pipe, "wakeup pipe");
     160        2821 :     if (ret) m_pipe_registered = false;
     161        2821 :     return ret;
     162        2821 : }
     163             : 
     164        9947 : bool EdgeTriggeredEvents::RegisterEvents(SOCKET socket) const
     165             : {
     166        9947 :     assert(m_valid && socket != INVALID_SOCKET);
     167             : 
     168        9947 :     if (m_mode == SocketEventsMode::EPoll) {
     169             : #ifdef USE_EPOLL
     170             :         epoll_event e;
     171             :         // We're using edge-triggered mode, so it's important that we drain sockets even if no signals come in
     172             :         e.events = EPOLLIN | EPOLLOUT | EPOLLET | EPOLLERR | EPOLLHUP;
     173             :         e.data.fd = socket;
     174             : 
     175             :         if (epoll_ctl(m_fd, EPOLL_CTL_ADD, socket, &e) != 0) {
     176             :             LogPrintf("Failed to register events for socket -- epoll_ctl(%d, %d, %d, ...) returned error: %s\n",
     177             :                       m_fd, EPOLL_CTL_ADD, socket, NetworkErrorString(WSAGetLastError()));
     178             :             return false;
     179             :         }
     180             : #else
     181           0 :         assert(false);
     182             : #endif /* USE_EPOLL */
     183        9947 :     } else if (m_mode == SocketEventsMode::KQueue) {
     184             : #ifdef USE_KQUEUE
     185             :         struct kevent events[2];
     186        9947 :         EV_SET(&events[0], socket, EVFILT_READ, EV_ADD, 0, 0, nullptr);
     187        9947 :         EV_SET(&events[1], socket, EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, nullptr);
     188             : 
     189        9947 :         if (kevent(m_fd, events, 2, nullptr, 0, nullptr) != 0) {
     190           0 :             LogPrintf("Failed to register events for socket -- kevent(%d, %d, %d, ...) returned error: %s\n",
     191             :                       m_fd, EV_ADD, socket, NetworkErrorString(WSAGetLastError()));
     192           0 :             return false;
     193             :         }
     194             : #else
     195             :         assert(false);
     196             : #endif /* USE_KQUEUE */
     197        9947 :     } else {
     198           0 :         assert(false);
     199             :     }
     200        9947 :     return true;
     201        9947 : }
     202             : 
     203        9947 : bool EdgeTriggeredEvents::UnregisterEvents(SOCKET socket) const
     204             : {
     205        9947 :     assert(m_valid);
     206             : 
     207        9947 :     if (socket == INVALID_SOCKET) {
     208           0 :         LogPrintf("Cannot unregister events for invalid socket\n");
     209           0 :         return false;
     210             :     }
     211             : 
     212        9947 :     if (m_mode == SocketEventsMode::EPoll) {
     213             : #ifdef USE_EPOLL
     214             :         if (epoll_ctl(m_fd, EPOLL_CTL_DEL, socket, nullptr) != 0) {
     215             :             LogPrintf("Failed to unregister events for socket -- epoll_ctl(%d, %d, %d, ...) returned error: %s\n",
     216             :                       m_fd, EPOLL_CTL_DEL, socket, NetworkErrorString(WSAGetLastError()));
     217             :             return false;
     218             :         }
     219             : #else
     220           0 :         assert(false);
     221             : #endif /* USE_EPOLL */
     222        9947 :     } else if (m_mode == SocketEventsMode::KQueue) {
     223             : #ifdef USE_KQUEUE
     224             :         struct kevent events[2];
     225        9947 :         EV_SET(&events[0], socket, EVFILT_READ, EV_DELETE, 0, 0, nullptr);
     226        9947 :         EV_SET(&events[1], socket, EVFILT_WRITE, EV_DELETE, 0, 0, nullptr);
     227        9947 :         if (kevent(m_fd, events, 2, nullptr, 0, nullptr) != 0) {
     228           0 :             LogPrintf("Failed to unregister events for socket -- kevent(%d, %d, %d, ...) returned error: %s\n",
     229             :                       m_fd, EV_DELETE, socket, NetworkErrorString(WSAGetLastError()));
     230           0 :             return false;
     231             :         }
     232             : #else
     233             :         assert(false);
     234             : #endif /* USE_KQUEUE */
     235        9947 :     } else {
     236           0 :         assert(false);
     237             :     }
     238        9947 :     return true;
     239        9947 : }

Generated by: LCOV version 1.16