File indexing completed on 2024-05-19 13:30:29
0001 /* 0002 Copyright (C) 2015 Andreas Hartmetz <ahartmetz@gmail.com> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LGPL. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 Boston, MA 02110-1301, USA. 0018 0019 Alternatively, this file is available under the Mozilla Public License 0020 Version 1.1. You may obtain a copy of the License at 0021 http://www.mozilla.org/MPL/ 0022 */ 0023 0024 #include "selecteventpoller_unix.h" 0025 0026 #include "eventdispatcher_p.h" 0027 #include "iioeventlistener.h" 0028 0029 #include <fcntl.h> 0030 #include <unistd.h> 0031 0032 #include <cassert> 0033 #include <cstdio> 0034 0035 0036 SelectEventPoller::SelectEventPoller(EventDispatcher *dispatcher) 0037 : IEventPoller(dispatcher) 0038 { 0039 pipe2(m_interruptPipe, O_NONBLOCK); 0040 resetFdSets(); 0041 } 0042 0043 SelectEventPoller::~SelectEventPoller() 0044 { 0045 close(m_interruptPipe[0]); 0046 close(m_interruptPipe[1]); 0047 } 0048 0049 IEventPoller::InterruptAction SelectEventPoller::poll(int timeout) 0050 { 0051 IEventPoller::InterruptAction ret = IEventPoller::NoInterrupt; 0052 0053 resetFdSets(); 0054 0055 int nfds = m_interruptPipe[0]; 0056 0057 // set up the interruption listener 0058 FD_SET(m_interruptPipe[0], &m_readSet); 0059 0060 for (const auto &fdRw : m_fds) { 0061 if (fdRw.second & uint32(IO::RW::Read)) { 0062 nfds = std::max(nfds, fdRw.first); 0063 FD_SET(fdRw.first, &m_readSet); 0064 } 0065 if (fdRw.second & uint32(IO::RW::Write)) { 0066 nfds = std::max(nfds, fdRw.first); 0067 FD_SET(fdRw.first, &m_writeSet); 0068 } 0069 } 0070 0071 struct timeval tv; 0072 struct timeval *tvPointer = nullptr; 0073 if (timeout >= 0) { 0074 tv.tv_sec = timeout / 1000; 0075 tv.tv_usec = (timeout % 1000) * 1000; 0076 tvPointer = &tv; 0077 } 0078 0079 // select! 0080 nfds += 1; // see documentation of select()... 0081 int numEvents = select(nfds, &m_readSet, &m_writeSet, nullptr, tvPointer); 0082 0083 // check for interruption 0084 if (FD_ISSET(m_interruptPipe[0], &m_readSet)) { 0085 // interrupt; read bytes from pipe to clear buffers and get the interrupt type 0086 ret = IEventPoller::ProcessAuxEvents; 0087 char buf; 0088 while (read(m_interruptPipe[0], &buf, 1) > 0) { 0089 if (buf == 'S') { 0090 ret = IEventPoller::Stop; 0091 } 0092 } 0093 } 0094 0095 if (ret == IEventPoller::Stop) { 0096 // ### discarding the rest of the events, to avoid touching "dead" data while shutting down 0097 numEvents = 0; 0098 } 0099 0100 // dispatch reads and writes 0101 if (numEvents < 0) { 0102 // TODO error handling 0103 } else { 0104 EventDispatcherPrivate* const edpriv = EventDispatcherPrivate::get(m_dispatcher); 0105 for (int i = 0; i < nfds && numEvents > 0; i++) { 0106 if (FD_ISSET(i, &m_readSet)) { 0107 edpriv->notifyListenerForIo(i, IO::RW::Read); 0108 numEvents--; 0109 } 0110 if (FD_ISSET(i, &m_writeSet)) { 0111 edpriv->notifyListenerForIo(i, IO::RW::Write); 0112 numEvents--; 0113 } 0114 } 0115 } 0116 0117 return ret; 0118 } 0119 0120 void SelectEventPoller::resetFdSets() 0121 { 0122 FD_ZERO(&m_readSet); 0123 FD_ZERO(&m_writeSet); 0124 } 0125 0126 void SelectEventPoller::interrupt(IEventPoller::InterruptAction action) 0127 { 0128 assert(action == IEventPoller::ProcessAuxEvents || action == IEventPoller::Stop); 0129 // write a byte to the write end so the poll waiting on the read end returns 0130 char buf = (action == IEventPoller::Stop) ? 'S' : 'N'; 0131 write(m_interruptPipe[1], &buf, 1); 0132 } 0133 0134 void SelectEventPoller::addFileDescriptor(FileDescriptor fd, uint32 ioRw) 0135 { 0136 // The main select specific part of registration is in setReadWriteInterest(). 0137 // Here we just check fd limits. 0138 if (fd >= FD_SETSIZE) { 0139 // TODO error... 0140 return; 0141 } 0142 0143 m_fds.emplace(fd, ioRw); 0144 } 0145 0146 void SelectEventPoller::removeFileDescriptor(FileDescriptor fd) 0147 { 0148 m_fds.erase(fd); 0149 } 0150 0151 void SelectEventPoller::setReadWriteInterest(FileDescriptor fd, uint32 ioRw) 0152 { 0153 m_fds.at(fd) = ioRw; 0154 }