Anope IRC Services  Version 2.0
socketengine_kqueue.cpp
Go to the documentation of this file.
1 /*
2  *
3  * (C) 2003-2014 Anope Team
4  * Contact us at team@anope.org
5  *
6  * Please read COPYING and README for further details.
7  *
8  * Based on the original code of Epona by Lara.
9  * Based on the original code of Services by Andy Church.
10  */
11 
12 #include "services.h"
13 #include "anope.h"
14 #include "sockets.h"
15 #include "socketengine.h"
16 #include "logger.h"
17 #include "config.h"
18 
19 #include <sys/types.h>
20 #include <sys/event.h>
21 #include <sys/time.h>
22 #include <errno.h>
23 
24 static int kq_fd;
25 static std::vector<struct kevent> change_events, event_events;
26 static unsigned change_count;
27 
28 static inline struct kevent *GetChangeEvent()
29 {
30  if (change_count == change_events.size())
31  change_events.resize(change_count * 2);
32 
33  return &change_events[change_count++];
34 }
35 
36 void SocketEngine::Init()
37 {
38  kq_fd = kqueue();
39 
40  if (kq_fd < 0)
41  throw SocketException("Unable to create kqueue engine: " + Anope::LastError());
42 
43  change_events.resize(DefaultSize);
44  event_events.resize(DefaultSize);
45 }
46 
48 {
49  while (!Sockets.empty())
50  delete Sockets.begin()->second;
51 }
52 
53 void SocketEngine::Change(Socket *s, bool set, SocketFlag flag)
54 {
55  if (set == s->flags[flag])
56  return;
57 
58  s->flags[flag] = set;
59 
60  int mod;
61  if (flag == SF_READABLE)
62  mod = EVFILT_READ;
63  else if (flag == SF_WRITABLE)
64  mod = EVFILT_WRITE;
65  else
66  return;
67 
68  struct kevent *event = GetChangeEvent();
69  EV_SET(event, s->GetFD(), mod, set ? EV_ADD : EV_DELETE, 0, 0, NULL);
70 }
71 
73 {
74  if (Sockets.size() > event_events.size())
75  event_events.resize(event_events.size() * 2);
76 
77  static timespec kq_timespec = { Config->ReadTimeout, 0 };
78  int total = kevent(kq_fd, &change_events.front(), change_count, &event_events.front(), event_events.size(), &kq_timespec);
79  change_count = 0;
80  Anope::CurTime = time(NULL);
81 
82  /* EINTR can be given if the read timeout expires */
83  if (total == -1)
84  {
85  if (errno != EINTR)
86  Log() << "SockEngine::Process(): error: " << Anope::LastError();
87  return;
88  }
89 
90  for (int i = 0; i < total; ++i)
91  {
92  struct kevent &event = event_events[i];
93  if (event.flags & EV_ERROR)
94  continue;
95 
96  std::map<int, Socket *>::iterator it = Sockets.find(event.ident);
97  if (it == Sockets.end())
98  continue;
99  Socket *s = it->second;
100 
101  if (event.flags & EV_EOF)
102  {
103  s->ProcessError();
104  delete s;
105  continue;
106  }
107 
108  if (!s->Process())
109  {
110  if (s->flags[SF_DEAD])
111  delete s;
112  continue;
113  }
114 
115  if (event.filter == EVFILT_READ && !s->ProcessRead())
116  s->flags[SF_DEAD] = true;
117  else if (event.filter == EVFILT_WRITE && !s->ProcessWrite())
118  s->flags[SF_DEAD] = true;
119 
120  if (s->flags[SF_DEAD])
121  delete s;
122  }
123 }
124 
static struct kevent * GetChangeEvent()
std::bitset< SF_SIZE > flags
Definition: sockets.h:203
static int kq_fd
SocketFlag
Definition: sockets.h:124
static void Init()
CoreExport const string LastError()
Definition: misc.cpp:606
virtual bool Process()
Definition: sockets.cpp:498
virtual bool ProcessRead()
Definition: sockets.cpp:503
virtual bool ProcessWrite()
Definition: sockets.cpp:508
static void Process()
static std::map< int, Socket * > Sockets
Definition: socketengine.h:24
static void Change(Socket *s, bool set, SocketFlag flag)
CoreExport time_t CurTime
Definition: main.cpp:41
int GetFD() const
Definition: sockets.cpp:474
Definition: Config.cs:26
static std::vector< struct kevent > event_events
static const int DefaultSize
Definition: socketengine.h:21
static std::vector< struct kevent > change_events
static void Shutdown()
static unsigned change_count
Definition: logger.h:53
virtual void ProcessError()
Definition: sockets.cpp:513