1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
3 #include "base/socketevents.hpp"
4 #include "base/exception.hpp"
5 #include "base/logger.hpp"
6 #include "base/utility.hpp"
7 #include <boost/thread/once.hpp>
10 using namespace icinga;
12 void SocketEventEnginePoll::InitializeThread(int tid)
14 SocketEventDescriptor sed;
17 m_Sockets[tid][m_EventFDs[tid][0]] = sed;
18 m_FDChanged[tid] = true;
21 void SocketEventEnginePoll::ThreadProc(int tid)
23 Utility::SetThreadName("SocketIO");
25 std::vector<pollfd> pfds;
26 std::vector<SocketEventDescriptor> descriptors;
30 boost::mutex::scoped_lock lock(m_EventMutex[tid]);
32 if (m_FDChanged[tid]) {
33 pfds.resize(m_Sockets[tid].size());
34 descriptors.resize(m_Sockets[tid].size());
38 typedef std::map<SOCKET, SocketEventDescriptor>::value_type kv_pair;
40 for (const kv_pair& desc : m_Sockets[tid]) {
41 if (desc.second.Events == 0)
44 int events = desc.second.Events;
46 if (desc.second.EventInterface) {
47 desc.second.EventInterface->m_EnginePrivate = &pfds[i];
49 if (!desc.second.EventInterface->m_Events)
53 pfds[i].fd = desc.first;
54 pfds[i].events = events;
55 descriptors[i] = desc.second;
62 m_FDChanged[tid] = false;
63 m_CV[tid].notify_all();
67 ASSERT(!pfds.empty());
70 (void) WSAPoll(&pfds[0], pfds.size(), -1);
72 (void) poll(&pfds[0], pfds.size(), -1);
75 std::vector<EventDescription> events;
78 boost::mutex::scoped_lock lock(m_EventMutex[tid]);
83 for (std::vector<pollfd>::size_type i = 0; i < pfds.size(); i++) {
84 if ((pfds[i].revents & (POLLIN | POLLOUT | POLLHUP | POLLERR)) == 0)
87 if (pfds[i].fd == m_EventFDs[tid][0]) {
89 if (recv(m_EventFDs[tid][0], buffer, sizeof(buffer), 0) < 0)
90 Log(LogCritical, "SocketEvents", "Read from event FD failed.");
95 EventDescription event;
96 event.REvents = pfds[i].revents;
97 event.Descriptor = descriptors[i];
99 events.emplace_back(std::move(event));
103 for (const EventDescription& event : events) {
105 event.Descriptor.EventInterface->OnEvent(event.REvents);
106 } catch (const std::exception& ex) {
107 Log(LogCritical, "SocketEvents")
108 << "Exception thrown in socket I/O handler:\n"
109 << DiagnosticInformation(ex);
111 Log(LogCritical, "SocketEvents", "Exception of unknown type thrown in socket I/O handler.");
117 void SocketEventEnginePoll::Register(SocketEvents *se)
119 int tid = se->m_ID % SOCKET_IOTHREADS;
122 boost::mutex::scoped_lock lock(m_EventMutex[tid]);
124 VERIFY(se->m_FD != INVALID_SOCKET);
126 SocketEventDescriptor desc;
128 desc.EventInterface = se;
130 VERIFY(m_Sockets[tid].find(se->m_FD) == m_Sockets[tid].end());
132 m_Sockets[tid][se->m_FD] = desc;
134 m_FDChanged[tid] = true;
139 WakeUpThread(tid, true);
142 void SocketEventEnginePoll::Unregister(SocketEvents *se)
144 int tid = se->m_ID % SOCKET_IOTHREADS;
147 boost::mutex::scoped_lock lock(m_EventMutex[tid]);
149 if (se->m_FD == INVALID_SOCKET)
152 m_Sockets[tid].erase(se->m_FD);
153 m_FDChanged[tid] = true;
155 se->m_FD = INVALID_SOCKET;
156 se->m_Events = false;
159 WakeUpThread(tid, true);
162 void SocketEventEnginePoll::ChangeEvents(SocketEvents *se, int events)
164 if (se->m_FD == INVALID_SOCKET)
165 BOOST_THROW_EXCEPTION(std::runtime_error("Tried to read/write from a closed socket."));
167 int tid = se->m_ID % SOCKET_IOTHREADS;
170 boost::mutex::scoped_lock lock(m_EventMutex[tid]);
172 auto it = m_Sockets[tid].find(se->m_FD);
174 if (it == m_Sockets[tid].end())
177 if (it->second.Events == events)
180 it->second.Events = events;
182 if (se->m_EnginePrivate && std::this_thread::get_id() == m_Threads[tid].get_id())
183 ((pollfd *)se->m_EnginePrivate)->events = events;
185 m_FDChanged[tid] = true;
188 WakeUpThread(tid, false);