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/application.hpp"
7 #include "base/scriptglobal.hpp"
8 #include "base/utility.hpp"
9 #include <boost/thread/once.hpp>
12 # include <sys/epoll.h>
13 #endif /* __linux__ */
15 using namespace icinga;
17 static boost::once_flag l_SocketIOOnceFlag = BOOST_ONCE_INIT;
18 static SocketEventEngine *l_SocketIOEngine;
20 int SocketEvents::m_NextID = 0;
22 void SocketEventEngine::Start()
24 for (int tid = 0; tid < SOCKET_IOTHREADS; tid++) {
25 Socket::SocketPair(m_EventFDs[tid]);
27 Utility::SetNonBlockingSocket(m_EventFDs[tid][0]);
28 Utility::SetNonBlockingSocket(m_EventFDs[tid][1]);
31 Utility::SetCloExec(m_EventFDs[tid][0]);
32 Utility::SetCloExec(m_EventFDs[tid][1]);
35 InitializeThread(tid);
37 m_Threads[tid] = std::thread(std::bind(&SocketEventEngine::ThreadProc, this, tid));
41 void SocketEventEngine::WakeUpThread(int sid, bool wait)
43 int tid = sid % SOCKET_IOTHREADS;
45 if (std::this_thread::get_id() == m_Threads[tid].get_id())
49 boost::mutex::scoped_lock lock(m_EventMutex[tid]);
51 m_FDChanged[tid] = true;
53 while (m_FDChanged[tid]) {
54 (void) send(m_EventFDs[tid][1], "T", 1, 0);
56 boost::system_time const timeout = boost::get_system_time() + boost::posix_time::milliseconds(50);
57 m_CV[tid].timed_wait(lock, timeout);
60 (void) send(m_EventFDs[tid][1], "T", 1, 0);
64 void SocketEvents::InitializeEngine()
66 String eventEngine = Configuration::EventEngine;
68 if (eventEngine.IsEmpty())
70 eventEngine = "epoll";
73 #endif /* __linux__ */
75 if (eventEngine == "poll")
76 l_SocketIOEngine = new SocketEventEnginePoll();
78 else if (eventEngine == "epoll")
79 l_SocketIOEngine = new SocketEventEngineEpoll();
80 #endif /* __linux__ */
82 Log(LogWarning, "SocketEvents")
83 << "Invalid event engine selected: " << eventEngine << " - Falling back to 'poll'";
87 l_SocketIOEngine = new SocketEventEnginePoll();
90 l_SocketIOEngine->Start();
92 Configuration::EventEngine = eventEngine;
96 * Constructor for the SocketEvents class.
98 SocketEvents::SocketEvents(const Socket::Ptr& socket)
99 : m_ID(m_NextID++), m_FD(socket->GetFD()), m_EnginePrivate(nullptr)
101 boost::call_once(l_SocketIOOnceFlag, &SocketEvents::InitializeEngine);
106 SocketEvents::~SocketEvents()
108 VERIFY(m_FD == INVALID_SOCKET);
111 void SocketEvents::Register()
113 l_SocketIOEngine->Register(this);
116 void SocketEvents::Unregister()
118 l_SocketIOEngine->Unregister(this);
121 void SocketEvents::ChangeEvents(int events)
123 l_SocketIOEngine->ChangeEvents(this, events);
126 boost::mutex& SocketEventEngine::GetMutex(int tid)
128 return m_EventMutex[tid];
131 bool SocketEvents::IsHandlingEvents() const
133 int tid = m_ID % SOCKET_IOTHREADS;
134 boost::mutex::scoped_lock lock(l_SocketIOEngine->GetMutex(tid));
138 void SocketEvents::OnEvent(int revents)