socketengine_epoll.cpp

Go to the documentation of this file.
00001 /*
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  */
00011 
00012 #include "services.h"
00013 #include "anope.h"
00014 #include "sockets.h"
00015 #include "socketengine.h"
00016 #include "config.h"
00017 
00018 #include <sys/epoll.h>
00019 #include <ulimit.h>
00020 #include <errno.h>
00021 
00022 static int EngineHandle;
00023 static std::vector<epoll_event> events;
00024 
00025 void SocketEngine::Init()
00026 {
00027         EngineHandle = epoll_create(4);
00028 
00029         if (EngineHandle == -1)
00030                 throw SocketException("Could not initialize epoll socket engine: " + Anope::LastError());
00031         
00032         events.resize(DefaultSize);
00033 }
00034 
00035 void SocketEngine::Shutdown()
00036 {
00037         while (!Sockets.empty())
00038                 delete Sockets.begin()->second;
00039 }
00040 
00041 void SocketEngine::Change(Socket *s, bool set, SocketFlag flag)
00042 {
00043         if (set == s->flags[flag])
00044                 return;
00045 
00046         bool before_registered = s->flags[SF_READABLE] || s->flags[SF_WRITABLE];
00047 
00048         s->flags[flag] = set;
00049         
00050         bool now_registered = s->flags[SF_READABLE] || s->flags[SF_WRITABLE];
00051 
00052         epoll_event ev;
00053 
00054         memset(&ev, 0, sizeof(ev));
00055 
00056         ev.events = (s->flags[SF_READABLE] ? EPOLLIN : 0) | (s->flags[SF_WRITABLE] ? EPOLLOUT : 0);
00057         ev.data.fd = s->GetFD();
00058 
00059         int mod;
00060         if (!before_registered && now_registered)
00061                 mod = EPOLL_CTL_ADD;
00062         else if (before_registered && !now_registered)
00063                 mod = EPOLL_CTL_DEL;
00064         else if (before_registered && now_registered)
00065                 mod = EPOLL_CTL_MOD;
00066         else
00067                 return;
00068         
00069         if (epoll_ctl(EngineHandle, mod, ev.data.fd, &ev) == -1)
00070                  throw SocketException("Unable to epoll_ctl() fd " + stringify(ev.data.fd) + " to epoll: " + Anope::LastError());
00071 }
00072 
00073 void SocketEngine::Process()
00074 {
00075         if (Sockets.size() > events.size())
00076                 events.resize(events.size() * 2);
00077 
00078         int total = epoll_wait(EngineHandle, &events.front(), events.size(), Config->ReadTimeout * 1000);
00079         Anope::CurTime = time(NULL);
00080 
00081         /* EINTR can be given if the read timeout expires */
00082         if (total == -1)
00083         {
00084                 if (errno != EINTR)
00085                         Log() << "SockEngine::Process(): error: " << Anope::LastError();
00086                 return;
00087         }
00088 
00089         for (int i = 0; i < total; ++i)
00090         {
00091                 epoll_event &ev = events[i];
00092 
00093                 std::map<int, Socket *>::iterator it = Sockets.find(ev.data.fd);
00094                 if (it == Sockets.end())
00095                         continue;
00096                 Socket *s = it->second;
00097 
00098                 if (ev.events & (EPOLLHUP | EPOLLERR))
00099                 {
00100                         s->ProcessError();
00101                         delete s;
00102                         continue;
00103                 }
00104 
00105                 if (!s->Process())
00106                 {
00107                         if (s->flags[SF_DEAD])
00108                                 delete s;
00109                         continue;
00110                 }
00111 
00112                 if ((ev.events & EPOLLIN) && !s->ProcessRead())
00113                         s->flags[SF_DEAD] = true;
00114 
00115                 if ((ev.events & EPOLLOUT) && !s->ProcessWrite())
00116                         s->flags[SF_DEAD] = true;
00117 
00118                 if (s->flags[SF_DEAD])
00119                         delete s;
00120         }
00121 }
00122