Commit | Line | Data |
---|---|---|
d44e3c4f | 1 | /****************************************************************************** |
2 | * Copyright (c) 2000-2016 Ericsson Telecom AB | |
3 | * All rights reserved. This program and the accompanying materials | |
4 | * are made available under the terms of the Eclipse Public License v1.0 | |
5 | * which accompanies this distribution, and is available at | |
6 | * http://www.eclipse.org/legal/epl-v10.html | |
7 | * | |
8 | * Contributors: | |
9 | * Balasko, Jeno | |
10 | * Feher, Csaba | |
11 | * Raduly, Csaba | |
12 | * Szabados, Kristof | |
13 | * | |
14 | ******************************************************************************/ | |
970ed795 EL |
15 | #ifndef FD_AND_TIMEOUT_USER_HH |
16 | #define FD_AND_TIMEOUT_USER_HH | |
17 | ||
18 | // These header files contain the definitions of classes: | |
19 | // FdMap, Handler_List and Fd_And_Timeout_User; and structure FdSets. | |
20 | // These are used for socket and timeout event handling and | |
21 | // provide services for classes TTCN_Communication, TTCN_Snapshot and PORT. | |
22 | // Emulation of the backward compatible event handler interface is done | |
23 | // in class Fd_And_Timeout_User. | |
24 | // This file is not part of the binary distribution. | |
25 | // The member functions are implemented in Snapshot.cc. | |
26 | ||
27 | ||
28 | #include <sys/types.h> | |
29 | #include "poll.h" | |
30 | #ifdef USE_EPOLL | |
31 | ||
32 | #if defined(__GNUC__) && (__GNUC__ < 3) | |
33 | // __op is the name of one of the parameters of epoll_ctl() | |
34 | // But for GCC 2, __op is a synonym of "operator" | |
35 | #define __op p__op | |
36 | #endif | |
37 | ||
38 | #include "sys/epoll.h" | |
39 | ||
40 | #ifdef p__op | |
41 | #undef p__op | |
42 | #endif | |
43 | ||
44 | #endif | |
45 | ||
46 | #include "Types.h" | |
47 | #include "Error.hh" | |
48 | #include "Event_Handler.hh" | |
49 | ||
50 | ||
51 | class FdMap { | |
52 | public: | |
53 | /** The return value contains the event value before the add operation */ | |
54 | static fd_event_type_enum add(int fd, Fd_Event_Handler * handler, | |
55 | fd_event_type_enum event); | |
56 | /** The return value contains the event value before the remove operation */ | |
57 | static fd_event_type_enum remove(int fd, const Fd_Event_Handler * handler, | |
58 | fd_event_type_enum event); | |
59 | static fd_event_type_enum find(int fd, Fd_Event_Handler * * handler); | |
60 | static inline int getSize() { return nItems; } | |
61 | static inline int getFdLimit() { return capacity; } | |
62 | #ifdef USE_EPOLL | |
63 | static void initialize(int fdLimit) { | |
64 | nItems = 0; capacity = fdLimit; items2 = 0; epollFd = -1; | |
65 | for (int i = 0; i < ITEM1_CAPACITY; ++i) items1[i].init(); // debugging | |
66 | } | |
67 | static void terminate() { if (items2 != 0) { delete[] items2; items2=0; } } | |
68 | #else | |
69 | static void initialize(int fdLimit) { | |
70 | nItems = 0; capacity = fdLimit; items2 = 0; pollFds2 = 0; | |
71 | needUpdate = false; nPollFdsFrozen = 0; | |
72 | for (int i = 0; i < ITEM1_CAPACITY; ++i) { | |
73 | items1[i].init(); // for debugging | |
74 | init(pollFds1[i++]); // for debugging | |
75 | } | |
76 | } | |
77 | static void terminate() { | |
78 | if (items2 != 0) { delete[] items2; items2 = 0; } | |
79 | if (pollFds2 != 0) { delete[] pollFds2; pollFds2 = 0; } | |
80 | } | |
81 | static inline pollfd * getPollFds() { | |
82 | return (pollFds2 == 0) ? pollFds1 : pollFds2; | |
83 | } | |
84 | #endif | |
85 | // implementation dependent public interface | |
86 | // only for better performance | |
87 | static inline bool isItems1Used() { return items2 == 0; } | |
88 | #ifdef USE_EPOLL | |
89 | static inline fd_event_type_enum item1atIndex(int i, int * fd, | |
90 | Fd_Event_Handler * * handler) { | |
91 | *fd = items1[i].fd; | |
92 | *handler = items1[i].d.hnd; | |
93 | return epollEventToEvent(items1[i].d.evt); | |
94 | } | |
95 | static inline fd_event_type_enum item2atFd(int fd, | |
96 | Fd_Event_Handler * * handler) { | |
97 | *handler = items2[fd].hnd; | |
98 | return epollEventToEvent(items2[fd].evt); | |
99 | } | |
100 | #else | |
101 | static inline fd_event_type_enum item1atIndex(int i, int * fd, | |
102 | Fd_Event_Handler * * handler) { | |
103 | *fd = items1[i].fd; | |
104 | *handler = items1[i].d.hnd; | |
105 | return pollEventToEvent(getPollFds()[items1[i].d.ixPoll].events); | |
106 | } | |
107 | static inline fd_event_type_enum item2atFd(int fd, | |
108 | Fd_Event_Handler * * handler) { | |
109 | *handler = items2[fd].hnd; | |
110 | return pollEventToEvent(getPollFds()[items2[fd].ixPoll].events); | |
111 | } | |
112 | #endif | |
113 | private: | |
114 | struct Data { | |
115 | #ifdef USE_EPOLL | |
116 | short evt; // fd_event_type_enum with size of short | |
117 | short ixE; // only for invalidating epoll_event entries | |
118 | Fd_Event_Handler * hnd; | |
119 | inline Data() : evt(0), ixE(-1), hnd(0) {} | |
120 | inline void init() { evt = 0; ixE = -1; hnd = 0; } | |
121 | #else | |
122 | int ixPoll; // index to poll array | |
123 | Fd_Event_Handler * hnd; | |
124 | inline Data() : ixPoll(-1), hnd(0) {} | |
125 | inline void init() { ixPoll = -1; hnd = 0; } | |
126 | #endif | |
127 | }; | |
128 | struct Item { | |
129 | int fd; | |
130 | Data d; | |
131 | inline Item() : fd(-1), d() {} | |
132 | inline void init() { fd = -1; d.init(); } | |
133 | }; | |
134 | static int nItems; | |
135 | static int capacity; | |
136 | static inline int findInItems1(int fd) { | |
137 | if (nItems < 2) return (nItems == 1 && fd == items1[0].fd) ? 0 : -1; | |
138 | int i = 0, j = nItems, k; | |
139 | do { | |
140 | k = (i + j) >> 1; | |
141 | if (fd < items1[k].fd) j = k; else i = k; | |
142 | } while (j - i > 1); | |
143 | return (fd == items1[i].fd) ? i : -1; | |
144 | } | |
145 | static inline int findInsPointInItems1(int fd) { | |
146 | if (nItems < 2) return (nItems == 1 && fd > items1[0].fd) ? 1 : 0; | |
147 | int i = 0, j = nItems, k; | |
148 | do { | |
149 | k = (i + j) >> 1; | |
150 | if (fd < items1[k].fd) j = k; else i = k; | |
151 | } while (j - i > 1); | |
152 | return (fd <= items1[i].fd) ? i : j; | |
153 | } | |
154 | static inline bool findInItems2(int fd) { | |
155 | #ifdef USE_EPOLL | |
156 | return items2[fd].hnd != 0; | |
157 | #else | |
158 | return items2[fd].ixPoll >= 0; | |
159 | //Note: Frozen deleted items has 0 hnd | |
160 | #endif | |
161 | } | |
162 | // not implemented methods | |
163 | FdMap(); | |
164 | FdMap(const FdMap &); | |
165 | const FdMap & operator=(const FdMap &); | |
166 | // implementation dependent member variables | |
167 | static const int ITEM1_CAPACITY = 16; | |
168 | static const int ITEM1_CAPACITY_LOW = 8; | |
169 | static Item items1[ITEM1_CAPACITY]; | |
170 | static Data * items2; | |
171 | #ifndef USE_EPOLL | |
172 | static pollfd pollFds1[ITEM1_CAPACITY]; | |
173 | static pollfd * pollFds2; | |
174 | // pollFd2, items2 might be rewritten | |
175 | static inline void init(pollfd & p) { p.fd = -1; p.events = p.revents = 0; } | |
176 | static bool needUpdate; | |
177 | static int nPollFdsFrozen; | |
178 | static void copyItems2ToItems1(); | |
179 | #endif | |
180 | public: | |
181 | #ifdef USE_EPOLL | |
182 | static const int MAX_EPOLL_EVENTS = 64; | |
183 | static int epollFd; | |
184 | static epoll_event epollEvents[MAX_EPOLL_EVENTS]; | |
185 | static bool epollMarkFds(int nEvents); | |
186 | static void epollUnmarkFds(int nEvents); | |
187 | static inline __uint32_t eventToEpollEvent(fd_event_type_enum event) { | |
188 | __uint32_t epollEvent = 0; | |
189 | if ((event & FD_EVENT_RD) != 0) epollEvent |= EPOLLIN; | |
190 | if ((event & FD_EVENT_WR) != 0) epollEvent |= EPOLLOUT; | |
191 | if ((event & FD_EVENT_ERR) != 0) epollEvent |= EPOLLERR; | |
192 | return epollEvent; | |
193 | } | |
194 | static inline fd_event_type_enum epollEventToEvent(__uint32_t epollEvent) { | |
195 | int event = 0; | |
196 | if ((epollEvent & (EPOLLIN | EPOLLHUP)) != 0) event |= FD_EVENT_RD; | |
197 | if ((epollEvent & EPOLLOUT) != 0) event |= FD_EVENT_WR; | |
198 | if ((epollEvent & EPOLLERR) != 0) event |= FD_EVENT_ERR; | |
199 | return static_cast<fd_event_type_enum>(event); | |
200 | } | |
201 | static inline __uint32_t eventToEpollEvent(int event) { | |
202 | return eventToEpollEvent(static_cast<fd_event_type_enum>(event)); | |
203 | } | |
204 | #else | |
205 | static void pollFreeze(); | |
206 | static void pollUnfreeze(); | |
207 | static fd_event_type_enum getPollREvent(int fd); | |
208 | static inline short eventToPollEvent(fd_event_type_enum event) { | |
209 | short pollEvent = 0; | |
210 | if ((event & FD_EVENT_RD) != 0) pollEvent |= POLLIN; | |
211 | if ((event & FD_EVENT_WR) != 0) pollEvent |= POLLOUT; | |
212 | if ((event & FD_EVENT_ERR) != 0) pollEvent |= POLLERR; | |
213 | return pollEvent; | |
214 | } | |
215 | static inline fd_event_type_enum pollEventToEvent(short pollEvent) { | |
216 | int event = 0; | |
217 | if ((pollEvent & (POLLIN | POLLHUP)) != 0) event |= FD_EVENT_RD; | |
218 | if ((pollEvent & POLLOUT) != 0) event |= FD_EVENT_WR; | |
219 | if ((pollEvent & POLLERR) != 0) event |= FD_EVENT_ERR; | |
220 | return static_cast<fd_event_type_enum>(event); | |
221 | } | |
222 | static inline short eventToPollEvent(int event) { | |
223 | return eventToPollEvent(static_cast<fd_event_type_enum>(event)); | |
224 | } | |
225 | static const short pollEventMask = POLLIN | POLLOUT | POLLERR | POLLHUP; | |
226 | #endif | |
227 | }; | |
228 | ||
229 | ||
230 | ||
231 | ||
232 | ||
233 | class FdSets { | |
234 | /** FdSets is needed only for the old event handler API */ | |
235 | fd_set read_fds, write_fds, error_fds; | |
236 | public: | |
237 | inline FdSets() { clear(); } | |
238 | inline void clear() { | |
239 | FD_ZERO(&read_fds); FD_ZERO(&write_fds); FD_ZERO(&error_fds); | |
240 | } | |
241 | inline const fd_set * getReadFds() const { return &read_fds; } | |
242 | inline const fd_set * getWriteFds() const { return &write_fds; } | |
243 | inline const fd_set * getErrorFds() const { return &error_fds; } | |
244 | inline void add(int fd, fd_event_type_enum event) { | |
245 | if (fd >= (int)FD_SETSIZE) | |
246 | TTCN_error("FdSets::add: fd (%i) >= FD_SETSIZE (%i)",fd,FD_SETSIZE); | |
247 | if ((event & FD_EVENT_RD) != 0) { FD_SET(fd, &read_fds); } | |
248 | if ((event & FD_EVENT_WR) != 0) { FD_SET(fd, &write_fds); } | |
249 | if ((event & FD_EVENT_ERR) != 0) { FD_SET(fd, &error_fds); } | |
250 | } | |
251 | inline void remove(int fd, fd_event_type_enum event) { | |
252 | if (fd >= (int)FD_SETSIZE) | |
253 | TTCN_error("FdSets::remove: fd (%i) >= FD_SETSIZE (%i)", | |
254 | fd, FD_SETSIZE); | |
255 | if ((event & FD_EVENT_RD) != 0) { FD_CLR(fd, &read_fds); } | |
256 | if ((event & FD_EVENT_WR) != 0) { FD_CLR(fd, &write_fds); } | |
257 | if ((event & FD_EVENT_ERR) != 0) { FD_CLR(fd, &error_fds); } | |
258 | } | |
259 | inline fd_event_type_enum getEvent(int fd) const { | |
260 | return static_cast<fd_event_type_enum>( | |
261 | (FD_ISSET(fd, &read_fds) ? FD_EVENT_RD : 0) | | |
262 | (FD_ISSET(fd, &write_fds) ? FD_EVENT_WR : 0) | | |
263 | (FD_ISSET(fd, &error_fds) ? FD_EVENT_ERR : 0) ); | |
264 | } | |
265 | static inline fd_event_type_enum getEvent(const fd_set * rs, | |
266 | const fd_set * ws, const fd_set * es, int fd) { | |
267 | return static_cast<fd_event_type_enum>( | |
268 | ((rs != 0 && FD_ISSET(fd, rs)) ? FD_EVENT_RD : 0) | | |
269 | ((ws != 0 && FD_ISSET(fd, ws)) ? FD_EVENT_WR : 0) | | |
270 | ((es != 0 && FD_ISSET(fd, es)) ? FD_EVENT_ERR : 0) ); | |
271 | } | |
272 | private: | |
273 | // Note: Platform dependent implementation | |
274 | // Operations done an all fds of the sets are done faster | |
275 | static const int NOBPI = sizeof(long int) * 8; // N.Of Bits Per Item | |
276 | static const int NOI = FD_SETSIZE / NOBPI; // N.Of Items | |
277 | //static const int NOI_MAX = (FD_SETSIZE + NOBPI - 1) / NOBPI; | |
278 | static const int NORB = FD_SETSIZE % NOBPI; // Remaining Bits | |
279 | static const int RBM = (1 << NORB) - 1; // Mask for Remaining Bits | |
280 | static inline bool fdSetOr (fd_set & fdSet, const fd_set & fdSet2) { | |
281 | long orV = 0; | |
282 | for (int i = 0; i < NOI; ++i) | |
283 | orV |= ( ((long*)&fdSet)[i] |= ((const long*)&fdSet2)[i] ); | |
284 | if (NORB > 0) | |
285 | orV |= RBM & ( ((long*)&fdSet)[NOI] |= ((const long*)&fdSet2)[NOI]); | |
286 | return orV != 0; | |
287 | } | |
288 | static inline bool fdSetSubs (fd_set & fdSet, const fd_set & fdSet2) { | |
289 | long orV = 0; | |
290 | for (int i = 0; i < NOI; ++i) | |
291 | orV |= ( ((long*)&fdSet)[i] &= ~((const long*)&fdSet2)[i] ); | |
292 | if (NORB > 0) | |
293 | orV |= RBM & (((long*)&fdSet)[NOI] &= ~((const long*)&fdSet2)[NOI]); | |
294 | return orV != 0; | |
295 | } | |
296 | static inline bool fdSetAnd (fd_set & fdSet, const fd_set & fdSet2) { | |
297 | long orV = 0; | |
298 | for (int i = 0; i < NOI; ++i) | |
299 | orV |= ( ((long*)&fdSet)[i] &= ((const long*)&fdSet2)[i] ); | |
300 | if (NORB > 0) | |
301 | orV |= RBM & (((long*)&fdSet)[NOI] &= ((const long*)&fdSet2)[NOI]); | |
302 | return orV != 0; | |
303 | } | |
304 | static inline bool fdSetAnd (fd_set & fdSet, | |
305 | const fd_set & fdSet1, const fd_set & fdSet2) { | |
306 | long orV = 0; | |
307 | for (int i = 0; i < NOI; ++i) | |
308 | orV |= ( ((long*)&fdSet)[i] = | |
309 | (((const long*)&fdSet1)[i] & ((const long*)&fdSet2)[i]) ); | |
310 | if (NORB > 0) | |
311 | orV |= RBM & ( ((long*)&fdSet)[NOI] = | |
312 | (((const long*)&fdSet1)[NOI] & ((const long*)&fdSet2)[NOI]) ); | |
313 | return orV != 0; | |
314 | } | |
315 | inline long anyDiff(const FdSets & fdSet, int i) const { | |
316 | return (((const long*)&read_fds)[i] ^ | |
317 | ((const long*)&fdSet.read_fds)[i]) | | |
318 | (((const long*)&write_fds)[i] ^ | |
319 | ((const long*)&fdSet.write_fds)[i]) | | |
320 | (((const long*)&error_fds)[i] ^ | |
321 | ((const long*)&fdSet.error_fds)[i]); | |
322 | } | |
323 | inline long anyDiff(const fd_set * rs, const fd_set * ws, const fd_set * es, | |
324 | int i) const { | |
325 | return (((const long*)&read_fds)[i] ^ ((rs!=0)?((const long*)rs)[i]:0))| | |
326 | (((const long*)&write_fds)[i] ^((ws!=0)?((const long*)ws)[i]:0))| | |
327 | (((const long*)&error_fds)[i] ^((es!=0)?((const long*)es)[i]:0)); | |
328 | } | |
329 | inline long anySet(int i) const { | |
330 | return ((const long*)&read_fds)[i] | ((const long*)&write_fds)[i] | | |
331 | ((const long*)&error_fds)[i]; | |
332 | } | |
333 | inline long bothAnySet(const fd_set * rs, const fd_set * ws, const fd_set * es, | |
334 | int i) const { // both fd_set triplet has something set | |
335 | return (((const long*)&read_fds)[i] | | |
336 | ((const long*)&write_fds)[i] | | |
337 | ((const long*)&error_fds)[i]) & | |
338 | (((rs!=0)?((const long*)rs)[i]:0) | | |
339 | ((ws!=0)?((const long*)ws)[i]:0) | | |
340 | ((es!=0)?((const long*)es)[i]:0)); | |
341 | } | |
342 | inline long anyAnd(const FdSets & fdSet, int i) const { | |
343 | return (((const long*)&read_fds)[i] & | |
344 | ((const long*)&fdSet.read_fds)[i]) | | |
345 | (((const long*)&write_fds)[i] & | |
346 | ((const long*)&fdSet.write_fds)[i]) | | |
347 | (((const long*)&error_fds)[i] & | |
348 | ((const long*)&fdSet.error_fds)[i]); | |
349 | } | |
350 | static inline int lowestBit(long m) { | |
351 | int i = 0; | |
352 | while ((m & 0xFF) == 0) { m >>= 8l; i += 8; } | |
353 | while ((m & 1) == 0) { m >>= 1l; ++i; } | |
354 | return i; | |
355 | } | |
356 | public: | |
357 | inline bool setOr(const FdSets & fdSet) { | |
358 | return fdSetOr(read_fds, fdSet.read_fds) | | |
359 | fdSetOr(write_fds, fdSet.write_fds) | | |
360 | fdSetOr(error_fds, fdSet.error_fds); | |
361 | } | |
362 | inline bool setSubstract(const FdSets & fdSet) { | |
363 | return fdSetSubs(read_fds, fdSet.read_fds) | | |
364 | fdSetSubs(write_fds, fdSet.write_fds) | | |
365 | fdSetSubs(error_fds, fdSet.error_fds); | |
366 | } | |
367 | inline bool setAnd(const FdSets & fdSet) { | |
368 | return fdSetAnd(read_fds, fdSet.read_fds) | | |
369 | fdSetAnd(write_fds, fdSet.write_fds) | | |
370 | fdSetAnd(error_fds, fdSet.error_fds); | |
371 | } | |
372 | inline bool setAnd(const FdSets & fdSet1, const FdSets & fdSet2) { | |
373 | return fdSetAnd(read_fds, fdSet1.read_fds, fdSet2.read_fds) | | |
374 | fdSetAnd(write_fds, fdSet1.write_fds, fdSet2.write_fds) | | |
375 | fdSetAnd(error_fds, fdSet1.error_fds, fdSet2.error_fds); | |
376 | } | |
377 | /** Gives back the first fd where any of the three sets differ | |
378 | * in interval fd, ... fdLimit - 1 | |
379 | */ | |
380 | inline int getIxDiff(const fd_set * rs, const fd_set * ws, | |
381 | const fd_set * es, int fd, int fdLimit) const { | |
382 | int iL = fdLimit / NOBPI; | |
383 | int i = fd / NOBPI; | |
384 | long m; | |
385 | if (i < iL) { | |
386 | m = (unsigned long) anyDiff(rs, ws, es, i) >> | |
387 | (unsigned long) (fd % NOBPI); | |
388 | if (m != 0) return fd + lowestBit(m); | |
389 | for (++i; i < iL; ++i) | |
390 | if ((m = anyDiff(rs, ws, es, i)) != 0) | |
391 | return i * NOBPI + lowestBit(m); | |
392 | long rbm = ((1ul << (unsigned long) (fdLimit % NOBPI)) - 1); | |
393 | if (rbm != 0 && (m = anyDiff(rs, ws, es, i) & rbm) != 0 ) | |
394 | return i * NOBPI + lowestBit(m); | |
395 | } else { | |
396 | if (fd >= fdLimit) return fdLimit; | |
397 | // i == iL, unlikely case: fdLimit % NOBPI != 0 | |
398 | m = (unsigned long) anyDiff(rs, ws, es, i) & | |
399 | ((1ul << (unsigned long) (fdLimit % NOBPI)) - 1); | |
400 | m >>= (unsigned long) (fd % NOBPI); | |
401 | if (m != 0) return fd + lowestBit(m); | |
402 | } | |
403 | return fdLimit; | |
404 | } | |
405 | inline int getIxSet(int fd, int fdLimit) const { | |
406 | int iL = fdLimit / NOBPI; | |
407 | int i = fd / NOBPI; | |
408 | long m; | |
409 | if (i < iL) { | |
410 | m = (unsigned long) anySet(i) >> (unsigned long) (fd % NOBPI); | |
411 | if (m != 0) return fd + lowestBit(m); | |
412 | for (++i; i < iL; ++i) | |
413 | if ((m = anySet(i)) != 0) | |
414 | return i * NOBPI + lowestBit(m); | |
415 | long rbm = ((1ul << (unsigned long) (fdLimit % NOBPI)) - 1); | |
416 | if (rbm != 0 && (m = anySet(i) & rbm) != 0) | |
417 | return i * NOBPI + lowestBit(m); | |
418 | } else { | |
419 | if (fd >= fdLimit) return fdLimit; | |
420 | // i == iL | |
421 | m = (unsigned long) anySet(i) & | |
422 | ((1ul << (unsigned long) (fdLimit % NOBPI)) - 1); | |
423 | m >>= (unsigned long) (fd % NOBPI); | |
424 | if (m != 0) return fd + lowestBit(m); | |
425 | } | |
426 | return fdLimit; | |
427 | } | |
428 | /** Gives back the first fd where both set triplets has something set | |
429 | * in interval fd, ... fdLimit - 1 | |
430 | * (Used for special purpose: see Snapshot.cc: method set_fds_with_fd_sets) | |
431 | */ | |
432 | inline int getIxBothAnySet(const fd_set * rs, const fd_set * ws, | |
433 | const fd_set * es, int fd, int fdLimit) const { | |
434 | int iL = fdLimit / NOBPI; | |
435 | int i = fd / NOBPI; | |
436 | long m; | |
437 | if (i < iL) { | |
438 | m = (unsigned long) bothAnySet(rs, ws, es, i) >> | |
439 | (unsigned long) (fd % NOBPI); | |
440 | if (m != 0) return fd + lowestBit(m); | |
441 | for (++i; i < iL; ++i) | |
442 | if ((m = bothAnySet(rs, ws, es, i)) != 0) | |
443 | return i * NOBPI + lowestBit(m); | |
444 | long rbm = ((1ul << (unsigned long) (fdLimit % NOBPI)) - 1); | |
445 | if (rbm != 0 && (m = bothAnySet(rs, ws, es, i) & rbm) != 0 ) | |
446 | return i * NOBPI + lowestBit(m); | |
447 | } else { | |
448 | if (fd >= fdLimit) return fdLimit; | |
449 | // i == iL, unlikely case: fdLimit % NOBPI != 0 | |
450 | m = (unsigned long) bothAnySet(rs, ws, es, i) & | |
451 | ((1ul << (unsigned long) (fdLimit % NOBPI)) - 1); | |
452 | m >>= (unsigned long) (fd % NOBPI); | |
453 | if (m != 0) return fd + lowestBit(m); | |
454 | } | |
455 | return fdLimit; | |
456 | } | |
457 | }; | |
458 | ||
459 | ||
460 | ||
461 | ||
462 | ||
463 | class Handler_List { | |
464 | public: | |
465 | Handler_List() : head(), tail(), cur(0) { | |
466 | head.next = &tail; tail.prev = &head; | |
467 | } | |
468 | inline void first() { cur = head.next; } | |
469 | inline void next() { cur = cur->next; } | |
470 | inline bool finished() const { return cur == &tail; } | |
471 | inline Fd_And_Timeout_Event_Handler * current() const { return cur; } | |
472 | inline void add(Fd_And_Timeout_Event_Handler * handler) { | |
473 | if (handler->list != 0 || handler->prev != 0 || handler->next != 0) | |
474 | TTCN_error("Handler_List::add: Error in parameter"); //debug | |
475 | tail.prev->next = handler; handler->prev = tail.prev; | |
476 | tail.prev = handler; handler->next = &tail; | |
477 | handler->list = this; | |
478 | } | |
479 | inline void remove(Fd_And_Timeout_Event_Handler * handler) { | |
480 | if (handler->list != this) | |
481 | TTCN_error("Handler_List::remove: Error in parameter"); //debug | |
482 | handler->prev->next = handler->next; | |
483 | handler->next->prev = handler->prev; | |
484 | handler->prev = 0; handler->next = 0; handler->list = 0; | |
485 | } | |
486 | inline void clear() { | |
487 | Fd_And_Timeout_Event_Handler * hnd = head.next, * h; | |
488 | while (hnd != &tail) { | |
489 | h = hnd->next; hnd->prev = 0; hnd->next = 0; hnd->list = 0; hnd = h; | |
490 | } | |
491 | head.next = &tail; tail.prev = &head; cur = 0; | |
492 | } | |
493 | private: | |
494 | Fd_And_Timeout_Event_Handler head, tail, * cur; | |
495 | }; | |
496 | ||
497 | ||
498 | ||
499 | ||
500 | ||
501 | class Fd_And_Timeout_User { | |
502 | static inline void checkFd(int fd); | |
503 | public: | |
504 | static void initialize() { | |
505 | fdSetsReceived = 0; fdSetsToHnds = 0; | |
506 | nOldHandlers = 0; is_in_call_handlers = false; curRcvdEvtIx = -1; | |
507 | } | |
508 | static void terminate() { | |
509 | if (fdSetsReceived != 0) { delete fdSetsReceived; fdSetsReceived = 0; } | |
510 | if (fdSetsToHnds != 0) { delete fdSetsToHnds; fdSetsToHnds = 0; } | |
511 | } | |
512 | static void add_fd(int fd, Fd_Event_Handler * handler, | |
513 | fd_event_type_enum event); | |
514 | static void remove_fd(int fd, Fd_Event_Handler * handler, | |
515 | fd_event_type_enum event); | |
516 | static void set_timer(Fd_And_Timeout_Event_Handler * handler, | |
517 | double call_interval, boolean is_timeout = TRUE, | |
518 | boolean call_anyway = TRUE, boolean is_periodic = TRUE); | |
519 | ||
520 | static void set_fds_with_fd_sets(Fd_And_Timeout_Event_Handler * handler, | |
521 | const fd_set *read_fds, const fd_set *write_fds, | |
522 | const fd_set *error_fds); | |
523 | static void remove_all_fds(Fd_And_Timeout_Event_Handler * handler); | |
524 | ||
525 | static bool getTimeout(double * timeout); | |
526 | static void call_handlers(int nEvents); | |
527 | static int receiveEvents(int pollTimeout); | |
528 | static inline fd_event_type_enum getCurReceivedEvent() { | |
529 | // Checks are included because the test port might erroneously call | |
530 | // Handle_Fd_Event | |
531 | #ifdef USE_EPOLL | |
532 | if (curRcvdEvtIx < 0 || curRcvdEvtIx >= FdMap::MAX_EPOLL_EVENTS) | |
533 | return static_cast<fd_event_type_enum>(0); | |
534 | return | |
535 | FdMap::epollEventToEvent(FdMap::epollEvents[curRcvdEvtIx].events); | |
536 | #else | |
537 | if (curRcvdEvtIx < 0 || curRcvdEvtIx >= FdMap::getSize()) | |
538 | return static_cast<fd_event_type_enum>(0); | |
539 | return | |
540 | FdMap::pollEventToEvent(FdMap::getPollFds()[curRcvdEvtIx].revents); | |
541 | #endif | |
542 | } | |
543 | static inline bool get_is_in_call_handlers() { return is_in_call_handlers; } | |
544 | #ifdef USE_EPOLL | |
545 | static void reopenEpollFd(); | |
546 | #else | |
547 | static inline void reopenEpollFd() {} | |
548 | #endif | |
549 | ||
550 | private: | |
551 | static Handler_List timedList, oldApiCallList; | |
552 | static FdSets * fdSetsReceived; // active events for the old event handlers | |
553 | static FdSets * fdSetsToHnds; // temporary storage to pass it to the handler | |
554 | static int nOldHandlers; | |
555 | static bool is_in_call_handlers; | |
556 | static int curRcvdEvtIx; // Current Received Event Index - see call_handlers | |
557 | }; | |
558 | ||
559 | #endif |