TDME2  1.9.200
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
KernelEventMechanism.cpp
Go to the documentation of this file.
1 // kqueue
2 #if defined(__FreeBSD__) || defined(__OpenBSD__)
3  #include <sys/types.h>
4 #endif
5 
6 #if defined(__HAIKU__)
7  #define _DEFAULT_SOURCE
8 #endif
9 
10 #include <sys/event.h>
11 #include <sys/time.h>
12 
13 #include <errno.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 
19 #include <array>
20 #include <vector>
21 
22 #include <tdme/tdme.h>
28 
29 using std::array;
30 using std::vector;
31 
35 
36 KernelEventMechanism::KernelEventMechanism() : initialized(false),_psd(nullptr) {
37  // allocate platform specific data
38  _psd = static_cast<void*>(new KernelEventMechanismPSD());
39 }
40 
42  // delete platform specific data
43  delete static_cast<KernelEventMechanismPSD*>(_psd);
44 }
45 
46 void KernelEventMechanism::setSocketInterest(NetworkSocket* socket, const NIOInterest lastInterest, const NIOInterest interest, const void* cookie) {
47  // exit if not initialized
48  if (initialized == false) return;
49 
50  // platform specific data
51  auto psd = static_cast<KernelEventMechanismPSD*>(_psd);
52 
53  psd->kqMutex.lock();
54  // check for change list overrun
55  if (psd->kqChangeListCurrent + 2 >= psd->kqChangeListMax) {
56  psd->kqChangeList[0].resize(psd->kqChangeListMax << 1);
57  psd->kqChangeList[1].resize(psd->kqChangeListMax << 1);
58  }
59  // handle read interest
60  if ((interest & NIO_INTEREST_READ) == NIO_INTEREST_READ) {
61  auto& ke = psd->kqChangeList[psd->kqChangeListBuffer][psd->kqChangeListCurrent++];
62  ke.ident = socket->descriptor;
63  ke.filter = EVFILT_READ;
64  ke.flags = EV_ADD;
65  ke.fflags = 0;
66  ke.data = 0;
67  ke.udata = (void*)cookie;
68  } else {
69  auto& ke = psd->kqChangeList[psd->kqChangeListBuffer][psd->kqChangeListCurrent++];
70  ke.ident = socket->descriptor;
71  ke.filter = EVFILT_READ;
72  ke.flags = EV_DELETE;
73  ke.fflags = 0;
74  ke.data = 0;
75  ke.udata = (void*)cookie;
76  }
77  // handle write interest
78  if ((interest & NIO_INTEREST_WRITE) == NIO_INTEREST_WRITE) {
79  auto& ke = psd->kqChangeList[psd->kqChangeListBuffer][psd->kqChangeListCurrent++];
80  ke.ident = socket->descriptor;
81  ke.filter = EVFILT_WRITE;
82  ke.flags = EV_ADD;
83  ke.fflags = 0;
84  ke.data = 0;
85  ke.udata = (void*)cookie;
86  } else {
87  auto& ke = psd->kqChangeList[psd->kqChangeListBuffer][psd->kqChangeListCurrent++];
88  ke.ident = socket->descriptor;
89  ke.filter = EVFILT_WRITE;
90  ke.flags = EV_DELETE;
91  ke.fflags = 0;
92  ke.data = 0;
93  ke.udata = (void*)cookie;
94  }
95  //
96  psd->kqMutex.unlock();
97 }
98 
100  // exit if not initialized
101  if (initialized == false) return;
102 
103  // platform specific data
104  auto psd = static_cast<KernelEventMechanismPSD*>(_psd);
105 
106  psd->kqMutex.lock();
107  // check for change list overrun
108  if (psd->kqChangeListCurrent + 2 >= psd->kqChangeListMax) {
109  psd->kqChangeList[0].resize(psd->kqChangeListMax << 1);
110  psd->kqChangeList[1].resize(psd->kqChangeListMax << 1);
111  }
112  // remove read interest
113  {
114  auto& ke = psd->kqChangeList[psd->kqChangeListBuffer][psd->kqChangeListCurrent++];
115  ke.ident = socket->descriptor;
116  ke.filter = EVFILT_READ;
117  ke.flags = EV_DELETE;
118  ke.fflags = 0;
119  ke.data = 0;
120  ke.udata = nullptr;
121  }
122  // remove write interest
123  {
124  auto& ke = psd->kqChangeList[psd->kqChangeListBuffer][psd->kqChangeListCurrent++];
125  ke.ident = socket->descriptor;
126  ke.filter = EVFILT_WRITE;
127  ke.flags = EV_DELETE;
128  ke.fflags = 0;
129  ke.data = 0;
130  ke.udata = nullptr;
131  }
132  //
133  psd->kqMutex.unlock();
134 }
135 
136 void KernelEventMechanism::initKernelEventMechanism(const unsigned int maxSockets) {
137  // exit if initialized
138  if (initialized == true) return;
139 
140  // platform specific data
141  auto psd = static_cast<KernelEventMechanismPSD*>(_psd);
142 
143  // kqueue change list, max sockets * (read + write change)
144  // can still be too less as you could change the filter a lot in a single request
145  psd->kqChangeListMax = maxSockets * 2;
146  psd->kqChangeListCurrent = 0;
147  psd->kqChangeList[0].resize(psd->kqChangeListMax);
148  psd->kqChangeList[1].resize(psd->kqChangeListMax);
149 
150  // kqueue event list, max sockets * (read + write change)
151  psd->kqEventListMax = maxSockets * 2;
152  psd->kqEventList.resize(psd->kqEventListMax);
153 
154  // start kqueue and get the descriptor
155  psd->kq = kqueue();
156  if (psd->kq == -1) {
158  std::string msg = "Could not create kqueue: ";
159  msg+= strerror(errno);
160  throw NetworkKEMException(msg);
161  }
162 
163  //
164  initialized = true;
165 }
166 
168  // exit if not initialized
169  if (initialized == false) return;
170 
171  // platform specific data
172  auto psd = static_cast<KernelEventMechanismPSD*>(_psd);
173 
174  //
175  close(psd->kq);
176 }
177 
179  // exit if not initialized
180  if (initialized == false) return -1;
181 
182  // platform specific data
183  auto psd = (KernelEventMechanismPSD*)_psd;
184 
185  // have a timeout of 1ms
186  // as we only can delegate interest changes to the kernel by
187  // running kevent
188  const struct timespec timeout = {0, 1L * 1000L * 1000L};
189 
190  //
191  while (true == true) {
192  // do kqueue change list double buffer logic
193  psd->kqMutex.lock();
194 
195  // current kevent parameter from current change kqueue list
196  auto kqChangeListFilledBuffer = psd->kqChangeListBuffer;
197  auto kqChangeListFilledCurrent = psd->kqChangeListCurrent;
198 
199  // cycle change list buffer
200  psd->kqChangeListBuffer = (psd->kqChangeListBuffer + 1) % 2;
201 
202  // reset change list
203  psd->kqChangeListCurrent = 0;
204 
205  // done
206  psd->kqMutex.unlock();
207 
208  // kevent
209  int events = kevent(
210  psd->kq,
211  psd->kqChangeList[kqChangeListFilledBuffer].data(),
212  kqChangeListFilledCurrent,
213  psd->kqEventList.data(),
214  psd->kqEventListMax,
215  &timeout
216  );
217 
218  // check for error
219  if (events == -1) {
220  if (errno == EINTR) {
221  // kevent was interrupted by system call, so ignore this and restart
222  } else {
223  std::string msg = "kevent failed: ";
224  msg+= strerror(errno);
225  throw NetworkKEMException(msg);
226  }
227  } else {
228  //
229  return events;
230  }
231  }
232 }
233 
234 void KernelEventMechanism::decodeKernelEvent(const unsigned int index, NIOInterest &interest, void*& cookie) {
235  // exit if not initialized
236  if (initialized == false) return;
237 
238  // platform specific data
239  auto psd = static_cast<KernelEventMechanismPSD*>(_psd);
240 
241  const auto& ke = psd->kqEventList[index];
242  cookie = (void*)ke.udata;
243  switch (ke.filter) {
244  case(EVFILT_READ):
245  interest = NIO_INTEREST_READ;
246  break;
247  case(EVFILT_WRITE):
248  interest = NIO_INTEREST_WRITE;
249  break;
250  default:
251  interest = NIO_INTEREST_NONE;
252  }
253 }
Interface to kernel event mechanismns.
void shutdownKernelEventMechanism()
Shutdowns the kernel event mechanism.
void removeSocket(NetworkSocket *socket)
Removes a socket.
void setSocketInterest(NetworkSocket *socket, const NIOInterest lastInterest, const NIOInterest interest, const void *cookie)
Sets a non blocked socket io interest.
int doKernelEventMechanism()
Do the kernel event mechanism.
void initKernelEventMechanism(const unsigned int maxSockets)
Initializes the kernel event mechanism.
void decodeKernelEvent(const unsigned int index, NIOInterest &interest, void *&cookie)
Decodes a kernel event.
Kernel event mechanism exception class.
Base class of network sockets.
Definition: NetworkSocket.h:17
BSD kernel event mechanism platform specific data.
void lock()
Locks the mutex, additionally mutex locks will block until other locks have been unlocked.
Definition: Mutex.h:47
const NIOInterest NIO_INTEREST_NONE
Definition: NIOInterest.h:11
const NIOInterest NIO_INTEREST_READ
Definition: NIOInterest.h:12
uint8_t NIOInterest
type definition for network IO interest
Definition: NIOInterest.h:10
const NIOInterest NIO_INTEREST_WRITE
Definition: NIOInterest.h:13