LCOV - code coverage report
Current view: top level - src/util - edge.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 0 90 0.0 %
Date: 2026-06-25 07:23:51 Functions: 0 12 0.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           0 : EdgeTriggeredEvents::EdgeTriggeredEvents(SocketEventsMode events_mode)
      19             :     : m_mode(events_mode)
      20           0 : {
      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           0 : }
      50             : 
      51           0 : EdgeTriggeredEvents::~EdgeTriggeredEvents()
      52           0 : {
      53           0 :     if (m_valid) {
      54             : #if defined(USE_KQUEUE) || defined(USE_EPOLL)
      55           0 :         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           0 :     }
      63           0 : }
      64             : 
      65           0 : bool EdgeTriggeredEvents::RegisterEntity(int entity, const std::string& entity_name) const
      66             : {
      67           0 :     assert(m_valid);
      68             : 
      69           0 :     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           0 :     } else if (m_mode == SocketEventsMode::KQueue) {
      83             : #ifdef USE_KQUEUE
      84             :         struct kevent event;
      85           0 :         EV_SET(&event, entity, EVFILT_READ, EV_ADD, 0, 0, nullptr);
      86           0 :         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           0 :     } else {
      95           0 :         assert(false);
      96             :     }
      97           0 :     return true;
      98           0 : }
      99             : 
     100           0 : bool EdgeTriggeredEvents::UnregisterEntity(int entity, const std::string& entity_name) const
     101             : {
     102           0 :     assert(m_valid);
     103             : 
     104           0 :     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           0 :     } else if (m_mode == SocketEventsMode::KQueue) {
     115             : #ifdef USE_KQUEUE
     116             :         struct kevent event;
     117           0 :         EV_SET(&event, entity, EVFILT_READ, EV_DELETE, 0, 0, nullptr);
     118           0 :         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           0 :     } else {
     127           0 :         assert(false);
     128             :     }
     129           0 :     return true;
     130           0 : }
     131             : 
     132           0 : bool EdgeTriggeredEvents::AddSocket(SOCKET socket) const
     133             : {
     134           0 :     return RegisterEntity(socket, "socket");
     135           0 : }
     136             : 
     137           0 : bool EdgeTriggeredEvents::RemoveSocket(SOCKET socket) const
     138             : {
     139           0 :     return UnregisterEntity(socket, "socket");
     140           0 : }
     141             : 
     142           0 : bool EdgeTriggeredEvents::RegisterPipe(int wakeup_pipe)
     143             : {
     144           0 :     if (m_pipe_registered) {
     145           0 :         LogPrintf("Pipe already registered, ignoring new registration request\n");
     146           0 :         return false;
     147             :     }
     148           0 :     bool ret = RegisterEntity(wakeup_pipe, "wakeup pipe");
     149           0 :     if (ret) m_pipe_registered = true;
     150           0 :     return ret;
     151           0 : }
     152             : 
     153           0 : bool EdgeTriggeredEvents::UnregisterPipe(int wakeup_pipe)
     154             : {
     155           0 :     if (!m_pipe_registered) {
     156           0 :         LogPrintf("No pipe currently registered to unregister, ignoring request\n");
     157           0 :         return false;
     158             :     }
     159           0 :     bool ret = UnregisterEntity(wakeup_pipe, "wakeup pipe");
     160           0 :     if (ret) m_pipe_registered = false;
     161           0 :     return ret;
     162           0 : }
     163             : 
     164           0 : bool EdgeTriggeredEvents::RegisterEvents(SOCKET socket) const
     165             : {
     166           0 :     assert(m_valid && socket != INVALID_SOCKET);
     167             : 
     168           0 :     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           0 :     } else if (m_mode == SocketEventsMode::KQueue) {
     184             : #ifdef USE_KQUEUE
     185             :         struct kevent events[2];
     186           0 :         EV_SET(&events[0], socket, EVFILT_READ, EV_ADD, 0, 0, nullptr);
     187           0 :         EV_SET(&events[1], socket, EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, nullptr);
     188             : 
     189           0 :         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           0 :     } else {
     198           0 :         assert(false);
     199             :     }
     200           0 :     return true;
     201           0 : }
     202             : 
     203           0 : bool EdgeTriggeredEvents::UnregisterEvents(SOCKET socket) const
     204             : {
     205           0 :     assert(m_valid);
     206             : 
     207           0 :     if (socket == INVALID_SOCKET) {
     208           0 :         LogPrintf("Cannot unregister events for invalid socket\n");
     209           0 :         return false;
     210             :     }
     211             : 
     212           0 :     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           0 :     } else if (m_mode == SocketEventsMode::KQueue) {
     223             : #ifdef USE_KQUEUE
     224             :         struct kevent events[2];
     225           0 :         EV_SET(&events[0], socket, EVFILT_READ, EV_DELETE, 0, 0, nullptr);
     226           0 :         EV_SET(&events[1], socket, EVFILT_WRITE, EV_DELETE, 0, 0, nullptr);
     227           0 :         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           0 :     } else {
     236           0 :         assert(false);
     237             :     }
     238           0 :     return true;
     239           0 : }

Generated by: LCOV version 1.16