Merge pull request #78 from balaskoa/master
[deliverable/titan.core.git] / core / Snapshot.cc
CommitLineData
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 * Baji, Laszlo
10 * Balasko, Jeno
11 * Czimbalmos, Eduard
12 * Feher, Csaba
13 * Kovacs, Ferenc
14 * Pilisi, Gergely
15 * Raduly, Csaba
16 * Szabados, Kristof
17 * Szabo, Janos Zoltan – initial implementation
18 * Szalai, Gabor
19 * Pandi, Krisztian
20 *
21 ******************************************************************************/
970ed795
EL
22#include <string.h>
23#include <time.h>
24#include <sys/time.h>
25#include <math.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include <fcntl.h>
29#include <errno.h>
30
a38c6d4c 31#include <sys/select.h>
970ed795
EL
32#include <sys/types.h>
33#include <poll.h>
34#ifdef USE_EPOLL
35#include <sys/epoll.h>
36#endif
37
38#include "Types.h"
39
40#include "Snapshot.hh"
41#include "Fd_And_Timeout_User.hh"
42#include "Timer.hh"
43#include "Logger.hh"
44#include "Error.hh"
45#include "Event_Handler.hh"
46
47
48static const int MAX_INT_VAL = (int) ((unsigned int) -2 >> 1u);
49
50/******************************************************************************
51 * class FdMap *
52 ******************************************************************************/
53
54int FdMap::nItems;
55int FdMap::capacity;
56FdMap::Item FdMap::items1[ITEM1_CAPACITY];
57FdMap::Data * FdMap::items2;
58#ifndef USE_EPOLL
59pollfd FdMap::pollFds1[ITEM1_CAPACITY];
60pollfd * FdMap::pollFds2;
61bool FdMap::needUpdate;
62int FdMap::nPollFdsFrozen;
63#endif
64#ifdef USE_EPOLL
65int FdMap::epollFd;
66epoll_event FdMap::epollEvents[MAX_EPOLL_EVENTS];
67#endif
68
69fd_event_type_enum FdMap::add(int fd, Fd_Event_Handler * handler,
70 fd_event_type_enum event)
71{
72 if (handler == 0)
73 TTCN_error("FdMap::add: Internal error"); // debug
74 if (fd < 0 || fd >= capacity) {
75 TTCN_error_begin("Trying to add events of an invalid file descriptor "
76 "(%d) to the set of events handled by \"", fd);
77 handler->log();
78 TTCN_Logger::log_event("\".");
79 TTCN_error_end();
80 }
81 if ((event & ~(FD_EVENT_RD | FD_EVENT_WR | FD_EVENT_ERR)) != 0) {
82 TTCN_error_begin("Trying to add invalid events (%d) of file descriptor "
83 "(%d) to the set of events handled by \"", event, fd);
84 handler->log();
85 TTCN_Logger::log_event("\".");
86 TTCN_error_end();
87 }
88#ifndef USE_EPOLL
89 short pollEvent = eventToPollEvent(event);
90#endif
91 if (items2 == 0) {
92 int i = findInsPointInItems1(fd);
93 if (i < nItems && fd == items1[i].fd) {
94 // Already exists...
95 if (items1[i].d.hnd != 0 && items1[i].d.hnd != handler) {
96 TTCN_error_begin("Trying to add file descriptor (%d) "
97 "events (%d) to the set of events handled by \"",fd,event);
98 handler->log();
99 TTCN_Logger::log_event("\", but the events of the "
100 "file descriptor already have a different handler: \"");
101 if (items1[i].d.hnd != 0) items1[i].d.hnd->log();
102 TTCN_Logger::log_event("\".");
103 TTCN_error_end();
104 }
105 fd_event_type_enum oldEvent;
106#ifdef USE_EPOLL
107 oldEvent = static_cast<fd_event_type_enum>(items1[i].d.evt);
108 items1[i].d.evt |= static_cast<short>(event);
109#else
110 items1[i].d.hnd = handler; // in case it is a frozen deleted item
111 oldEvent = pollEventToEvent(pollFds1[items1[i].d.ixPoll].events);
112 pollFds1[items1[i].d.ixPoll].events |= pollEvent;
113#endif
114 return oldEvent;
115 }
116 if (nItems < ITEM1_CAPACITY) {
117 // Size of the static array is enough
118 for (int j = nItems - 1; j >= i; --j) items1[j + 1] = items1[j];
119 items1[i].fd = fd;
120#ifdef USE_EPOLL
121 items1[i].d.evt = static_cast<short>(event);
122 items1[i].d.ixE = -1;
123#else
124 pollFds1[nItems].fd = fd;
125 pollFds1[nItems].events = pollEvent;
126 pollFds1[nItems].revents = 0;
127 items1[i].d.ixPoll = nItems;
128#endif
129 items1[i].d.hnd = handler;
130 ++nItems;
131 return static_cast<fd_event_type_enum>(0);
132 }
133 // Copying items to the bigger dynamically allocated array
134 items2 = new Data[capacity]; // items2 is initialized in the constructor
135 for (i = 0; i < nItems; ++i) {
136 items2[items1[i].fd] = items1[i].d;
137 items1[i].init(); // not necessary - for debugging
138 }
139#ifndef USE_EPOLL
140 pollFds2 = new pollfd[capacity];
141 i = 0;
142 while (i < nItems) { pollFds2[i] = pollFds1[i]; init(pollFds1[i++]); }
143 while (i < ITEM1_CAPACITY) { init(pollFds2[i]); init(pollFds1[i++]); }
144 while (i < capacity) init(pollFds2[i++]);
145 //Note: From the above three loops: only the copying is needed
146 // The initializations are only for debugging
147#endif
148 // adding item...
149 } else {
150 if (findInItems2(fd)) {
151 // Already exists...
152 if (items2[fd].hnd != 0 && items2[fd].hnd != handler) {
153 TTCN_error_begin("Trying to add file descriptor (%d) "
154 "events (%d) to the set of events handled by \"",fd,event);
155 handler->log();
156 TTCN_Logger::log_event("\", but the events of the "
157 "file descriptor already have a different handler: \"");
158 if (items2[fd].hnd != 0) items2[fd].hnd->log();
159 TTCN_Logger::log_event("\".");
160 TTCN_error_end();
161 }
162 fd_event_type_enum oldEvent;
163#ifdef USE_EPOLL
164 oldEvent = static_cast<fd_event_type_enum>(items2[fd].evt);
165 items2[fd].evt |= static_cast<short>(event);
166#else
167 items2[fd].hnd = handler; // in case it is a frozen deleted item
168 oldEvent = pollEventToEvent(pollFds2[items2[fd].ixPoll].events);
169 pollFds2[items2[fd].ixPoll].events |= pollEvent;
170#endif
171 return oldEvent;
172 }
173 // adding item...
174 }
175 // ...adding item
176#ifdef USE_EPOLL
177 items2[fd].evt = static_cast<short>(event);
178 items2[fd].ixE = -1;
179#else
180 pollFds2[nItems].fd = fd;
181 pollFds2[nItems].events = pollEvent;
182 pollFds2[nItems].revents = 0;
183 items2[fd].ixPoll = nItems;
184#endif
185 items2[fd].hnd = handler;
186 ++nItems;
187 return static_cast<fd_event_type_enum>(0);
188}
189
190fd_event_type_enum FdMap::remove(int fd, const Fd_Event_Handler * handler,
191 fd_event_type_enum event)
192{
193 // Errors in Test Ports may be detected at this point
194 // handler is used only for checking;
195 // handler is 0 to remove a frozen deleted item
196 if (fd < 0 || fd >= capacity) {
197 TTCN_error_begin("Trying to remove events of an invalid file "
198 "descriptor (%d) from the set of events handled by \"", fd);
199 if (handler != 0) handler->log();
200 TTCN_Logger::log_event("\".");
201 TTCN_error_end();
202 }
203 if ((event & ~(FD_EVENT_RD | FD_EVENT_WR | FD_EVENT_ERR)) != 0) {
204 TTCN_error_begin("Trying to remove invalid events (%d) of file "
205 "descriptor (%d) from the set of events handled by \"", event, fd);
206 if (handler != 0) handler->log();
207 TTCN_Logger::log_event("\".");
208 TTCN_error_end();
209 }
210 fd_event_type_enum oldEvent;
211#ifndef USE_EPOLL
212 short pollEvent = eventToPollEvent(event);
213#endif
214 if (items2 == 0) {
215 int i = findInItems1(fd);
216 if (i < 0) {
217 TTCN_warning_begin("Trying to remove file descriptor (%d) "
218 "events (%d) from the set of events handled by \"",
219 fd, event);
220 if (handler != 0) handler->log();
221 TTCN_Logger::log_event("\", but events of the file descriptor "
222 "do not have a handler.");
223 TTCN_warning_end();
224 // Ignore errors for HP53582.
225 return FD_EVENT_ERR;
226 }
227 if (handler != items1[i].d.hnd) {
228 TTCN_error_begin("Trying to remove file descriptor (%d) "
229 "events (%d) from the set of events handled by \"", fd, event);
230 if (handler != 0) handler->log();
231 TTCN_Logger::log_event("\", but the events of the "
232 "file descriptor have different handler: \"");
233 if (items1[i].d.hnd != 0) items1[i].d.hnd->log();
234 TTCN_Logger::log_event("\".");
235 TTCN_error_end();
236 }
237#ifdef USE_EPOLL
238 short ixE = items1[i].d.ixE;
239 if (ixE >= 0) epollEvents[ixE].events &= ~eventToEpollEvent(event);
240 oldEvent = static_cast<fd_event_type_enum>(items1[i].d.evt);
241 if ((items1[i].d.evt &= ~static_cast<short>(event)) == 0) {
242 --nItems;
243 while (i < nItems) { items1[i] = items1[i + 1]; ++i; }
244 items1[nItems].init(); // not necessary - for debugging
245 }
246#else
247 int j = items1[i].d.ixPoll;
248 oldEvent = pollEventToEvent(pollFds1[j].events);
249 pollFds1[j].revents &= ~pollEvent;
250 if ((pollFds1[j].events &= ~pollEvent) == 0) {
251 if (j >= nPollFdsFrozen) {
252 if (j < nItems - 1) {
253 pollFds1[j] = pollFds1[nItems - 1];
254 int k = findInItems1(pollFds1[j].fd); // reads nItems
255 items1[k].d.ixPoll = j;
256 }
257 --nItems;
258 while (i < nItems) { items1[i] = items1[i + 1]; ++i; }
259 init(pollFds1[nItems]); // not necessary - for debugging
260 items1[nItems].init(); // not necessary - for debugging
261 } else { // The item is frozen; removal is postponed.
262 items1[i].d.hnd = 0;
263 needUpdate = true;
264 }
265 }
266#endif
267 } else {
268 if (!findInItems2(fd)) {
269 TTCN_error_begin("Trying to remove file descriptor (%d) "
270 "events (%d) from the set of events handled by \"",
271 fd, event);
272 if (handler != 0) handler->log();
273 TTCN_Logger::log_event("\", but events of the file descriptor "
274 "do not have a handler.");
275 TTCN_error_end();
276 }
277 if (items2[fd].hnd != handler) {
278 TTCN_error_begin("Trying to remove file descriptor (%d) "
279 "events (%d) from the set of events handled by \"", fd, event);
280 if (handler != 0) handler->log();
281 TTCN_Logger::log_event("\", but the events of the "
282 "file descriptor have different handler: \"");
283 items2[fd].hnd->log(); TTCN_Logger::log_event("\".");
284 TTCN_error_end();
285 }
286#ifdef USE_EPOLL
287 short ixE = items2[fd].ixE;
288 if (ixE >= 0) epollEvents[ixE].events &= ~eventToEpollEvent(event);
289 oldEvent = static_cast<fd_event_type_enum>(items2[fd].evt);
290 if ((items2[fd].evt &= ~static_cast<short>(event)) == 0) {
291 --nItems;
292 items2[fd].init(); // necessary to indicate an unused item
293 if (nItems <= ITEM1_CAPACITY_LOW) {
294 // could be improved with additional bookkeeping
295 // items1 has to be kept ordered with fd as key
296 for (int i = 0, n = 0; n < nItems && i < capacity; ++i) {
297 if (findInItems2(i)) {
298 items1[n].fd = i;
299 items1[n++].d = items2[i];
300 }
301 }
302 delete[] items2; items2 = 0;
303 //if (n < nItems) => error
304 }
305 }
306#else
307 int i = items2[fd].ixPoll;
308 oldEvent = pollEventToEvent(pollFds2[i].events);
309 pollFds2[i].revents &= ~pollEvent;
310 if ((pollFds2[i].events &= ~pollEvent) == 0) {
311 if (i >= nPollFdsFrozen) {
312 --nItems;
313 if (i < nItems) {
314 pollFds2[i] = pollFds2[nItems];
315 items2[pollFds2[i].fd].ixPoll = i;
316 }
317 init(pollFds2[nItems]); // not necessary - for debugging
318 items2[fd].init(); // necessary to indicate an unused item
319 if (nItems <= ITEM1_CAPACITY_LOW) {
320 // items1 has to be kept ordered with fd as key
321 copyItems2ToItems1();
322 delete[] items2; items2 = 0;
323 delete[] pollFds2; pollFds2 = 0;
324 }
325 } else { // The item is frozen; removal is postponed.
326 items2[fd].hnd = 0;
327 needUpdate = true;
328 }
329 }
330#endif
331 }
332 return oldEvent;
333}
334
335fd_event_type_enum FdMap::find(int fd, Fd_Event_Handler * * handler)
336{
337 Data * data;
338 if (items2 == 0) {
339 int i = findInItems1(fd);
340 if (i < 0) { *handler = 0; return static_cast<fd_event_type_enum>(0); }
341 data = &items1[i].d;
342 } else {
343 if (!findInItems2(fd)) {
344 *handler = 0; return static_cast<fd_event_type_enum>(0);
345 }
346 data = &items2[fd];
347 }
348 *handler = data->hnd;
349#ifdef USE_EPOLL
350 return static_cast<fd_event_type_enum>(data->evt);
351#else
352 return pollEventToEvent(getPollFds()[data->ixPoll].events);
353#endif
354}
355
356#ifndef USE_EPOLL
357void FdMap::copyItems2ToItems1()
358{
359 if (nItems != ITEM1_CAPACITY_LOW)
360 TTCN_error("FdMap::copyItems2ToItems1: Internal error");
361 if (ITEM1_CAPACITY_LOW == 0) return;
362 int n = nItems;
363 int i = 0;
364 for (int m = n - 1; m != 0; ++i) m >>= 1;
365 Item * d, itemsTmp[ITEM1_CAPACITY_LOW];
366 bool f = (i & 1) != 0;
367 d = (i == 0 || f) ? items1 : itemsTmp;
368 for (int j = 0, k = nItems - 1; j < k; j += 2) {
369 pollFds1[j] = pollFds2[j]; pollFds1[j + 1] = pollFds2[j + 1];
370 int fd1 = pollFds1[j].fd, fd2 = pollFds1[j + 1].fd;
371 if (fd1 <= fd2) {
372 d[j].fd = fd1; d[j].d = items2[fd1];
373 d[j + 1].fd = fd2; d[j + 1].d = items2[fd2];
374 } else {
375 d[j].fd = fd2; d[j].d = items2[fd2];
376 d[j + 1].fd = fd1; d[j + 1].d = items2[fd1];
377 }
378 }
379 if ((nItems & 1) != 0) {
380 pollFds1[n - 1] = pollFds2[n - 1];
381 int fd1 = pollFds1[n - 1].fd;
382 d[nItems - 1].fd = fd1;
383 d[nItems - 1].d = items2[fd1];
384 }
385 for (int j = 1; j < i; ++j) {
386 Item * s = f ? items1 : itemsTmp;
387 f = !f;
388 d = f ? items1 : itemsTmp;
389 int step = 1 << j;
390 int step2 = step * 2;
391 int w = 0;
392 for (int k = 0; k < n; k += step2) {
393 int u = k;
394 int v = k + step;
395 int uN = (n >= v) ? step : (n - u);
396 int vN = (n >= v + step) ? step : (n - v);
397 while (uN != 0 && vN > 0) {
398 if (s[u].fd <= s[v].fd) {
399 d[w++] = s[u++]; --uN;
400 } else {
401 d[w++] = s[v++]; --vN;
402 }
403 }
404 while (uN != 0) { d[w++] = s[u++]; --uN; }
405 while (vN > 0) { d[w++] = s[v++]; --vN; }
406 }
407 }
408}
409#endif
410
411#ifdef USE_EPOLL
412bool FdMap::epollMarkFds(int nEvents)
413{
414 bool all_valid = true;
415 for (int i = 0; i < nEvents; ++i) {
416 int fd = epollEvents[i].data.fd;
417 if (items2 == 0) {
418 int j = findInItems1(fd);
419 if (j >= 0) items1[j].d.ixE = i;
420 else all_valid = false;
421 } else {
422 if (findInItems2(fd)) items2[fd].ixE = i;
423 else all_valid = false;
424 }
425 }
426 return all_valid;
427}
428
429void FdMap::epollUnmarkFds(int nEvents)
430{
431 for (int i = 0; i < nEvents; ++i) {
432 int fd = epollEvents[i].data.fd;
433 if (items2 == 0) {
434 int j = findInItems1(fd);
435 if (j >= 0) items1[j].d.ixE = -1;
436 } else {
437 if (findInItems2(fd)) items2[fd].ixE = -1;
438 }
439 }
440}
441#else
442void FdMap::pollFreeze()
443{
444 nPollFdsFrozen = nItems;
445}
446
447void FdMap::pollUnfreeze()
448{
449 if (!needUpdate) { nPollFdsFrozen = 0; return; }
450 int i = 0, j = nPollFdsFrozen;
451 nPollFdsFrozen = 0;
452 while (i < j) {
453 pollfd & pollFd = getPollFds()[i];
454 if (pollFd.events == 0) {
455 remove(pollFd.fd, 0, static_cast<fd_event_type_enum>(
456 FD_EVENT_RD | FD_EVENT_WR | FD_EVENT_ERR));
457 if (nItems < j) j = nItems;
458 // item at index i is changed and has to be checked if exists
459 } else ++i;
460 }
461 needUpdate = false;
462}
463
464fd_event_type_enum FdMap::getPollREvent(int fd)
465{
466 if (items2 == 0) {
467 int i = findInItems1(fd);
468 if (i >= 0)
469 return pollEventToEvent(pollFds1[items1[i].d.ixPoll].revents);
470 } else {
471 if (findInItems2(fd))
472 return pollEventToEvent(pollFds2[items2[fd].ixPoll].revents);
473 }
474 return static_cast<fd_event_type_enum>(0);
475}
476#endif
477
478
479
480
481
482/******************************************************************************
483 * class Fd_Event_Handler *
484 ******************************************************************************/
485
486void Fd_Event_Handler::log() const
487{
488 TTCN_Logger::log_event("handler <invalid>");
489}
490
491
492
493
494
495
496/******************************************************************************
497 * class Fd_And_Timeout_Event_Handler *
498 ******************************************************************************/
499
500void Fd_And_Timeout_Event_Handler::Handle_Fd_Event(int,
501 boolean, boolean, boolean)
502{
503 TTCN_error("Fd_And_Timeout_Event_Handler::Handle_Fd_Event: "
504 "Erroneous usage of class Fd_And_Timeout_Event_Handler");
505 // This method cannot be pure virtual because of necessary instantiation
506 // inside TITAN
507}
508
509void Fd_And_Timeout_Event_Handler::Handle_Timeout(double)
510{
511 TTCN_error("Fd_And_Timeout_Event_Handler::Handle_Timeout: "
512 "Erroneous usage of class Fd_And_Timeout_Event_Handler");
513 // This method cannot be pure virtual because of necessary instantiation
514 // inside TITAN
515}
516
517void Fd_And_Timeout_Event_Handler::Event_Handler(const fd_set *,
518 const fd_set *, const fd_set *, double)
519{
520 TTCN_error("Fd_And_Timeout_Event_Handler::Event_Handler: "
521 "Erroneous usage of class Fd_And_Timeout_Event_Handler");
522 // This method cannot be pure virtual because of necessary instantiation
523 // inside TITAN
524}
525
526Fd_And_Timeout_Event_Handler::~Fd_And_Timeout_Event_Handler()
527{
528 // In case the event handler forgot to stop its timer,
529 // stop it at this point.
530 Fd_And_Timeout_User::set_timer(this, 0.0);
531 // In case the event handler forgot to remove all of its file descriptor
532 // events, remove those at this point.
533 Fd_And_Timeout_User::remove_all_fds(this);
534}
535
536void Fd_And_Timeout_Event_Handler::log() const
537{
538 TTCN_Logger::log_event("handler <unknown>");
539}
540
541
542
543
544
545/* The maximal blocking time to be used in poll, epoll and select (in seconds).
546 * On some systems (e.g. Solaris) the select call is a libc wrapper for
547 * poll(2). In the wrapper the overflows are not always handled thus select
548 * may return EINVAL in some cases.
549 * This value is derived from the maximal possible value for the last argument
550 * of poll, which is measured in milliseconds. */
551#define MAX_BLOCK_TIME (~(0x80 << ((sizeof(int) - 1) * 8)) / 1000)
552
553
554
555
556
557/******************************************************************************
558 * class Fd_And_Timeout_User *
559 ******************************************************************************/
560
561Handler_List Fd_And_Timeout_User::timedList,
562 Fd_And_Timeout_User::oldApiCallList;
563FdSets * Fd_And_Timeout_User::fdSetsReceived;
564FdSets * Fd_And_Timeout_User::fdSetsToHnds;
565int Fd_And_Timeout_User::nOldHandlers;
566bool Fd_And_Timeout_User::is_in_call_handlers;
567int Fd_And_Timeout_User::curRcvdEvtIx;
568
569inline void Fd_And_Timeout_User::checkFd(int fd)
570{
571 if (
572#ifdef USE_EPOLL
573 fd == FdMap::epollFd ||
574#endif
575 fcntl(fd, F_GETFD, FD_CLOEXEC) < 0)
576 TTCN_error("Trying to add events of an invalid file descriptor (%d)", fd);
577}
578
579void Fd_And_Timeout_User::add_fd(int fd, Fd_Event_Handler * handler,
580 fd_event_type_enum event)
581{
582 fd_event_type_enum oldEvent = FdMap::add(fd, handler, event);
583 Fd_And_Timeout_Event_Handler * tmHnd =
584 dynamic_cast<Fd_And_Timeout_Event_Handler *>(handler);
585 if (tmHnd != 0) {
586 if (tmHnd->fdSets != 0) {
587 if (fd >= (int)FD_SETSIZE)
588 TTCN_error("The file descriptor (%d) to be added is too big "
589 "to be handled by Event_Handler. FD_SETSIZE is %d",
590 fd, FD_SETSIZE);
591 tmHnd->fdSets->add(fd, event);
592 }
593 if (oldEvent == 0) ++tmHnd->fdCount;
594 }
595#ifdef USE_EPOLL
596 epoll_event epollEvent;
597 memset(&epollEvent, 0, sizeof(epollEvent));
598 epollEvent.events = FdMap::eventToEpollEvent(oldEvent | event);
599 epollEvent.data.fd = fd;
600 if ( ( (oldEvent == 0) ?
601 epoll_ctl(FdMap::epollFd, EPOLL_CTL_ADD, fd, &epollEvent) :
602 epoll_ctl(FdMap::epollFd, EPOLL_CTL_MOD, fd, &epollEvent) ) < 0 ) {
603 checkFd(fd);
604 TTCN_error("Fd_And_Timeout_User::add_fd: System call epoll_ctl failed "
605 "when adding fd: %d, errno: %d", fd, errno);
606 }
607#else
608 checkFd(fd);
609#endif
610}
611
612void Fd_And_Timeout_User::remove_fd(int fd, Fd_Event_Handler * handler,
613 fd_event_type_enum event)
614{
615 if (handler == 0)
616 TTCN_error("Fd_And_Timeout_User::remove_fd: Internal error"); // debug
617 fd_event_type_enum oldEvent = FdMap::remove(fd, handler, event);
618 // Ignore errors for HP53582.
619 if (oldEvent == FD_EVENT_ERR) return;
620 fd_event_type_enum newEvent =
621 static_cast<fd_event_type_enum>(oldEvent & ~event);
622 Fd_And_Timeout_Event_Handler * tmHnd =
623 dynamic_cast<Fd_And_Timeout_Event_Handler *>(handler);
624 if (tmHnd != 0) {
625 if (newEvent == 0) --tmHnd->fdCount;
626 if (tmHnd->getIsOldApi()) {
627 fdSetsReceived->remove(fd, event);
628 tmHnd->fdSets->remove(fd, event);
629 }
630 }
631#ifdef USE_EPOLL
632 epoll_event epollEvent;
633 memset(&epollEvent, 0, sizeof(epollEvent));
634 epollEvent.data.fd = fd;
635 if (newEvent == 0) {
636 if (epoll_ctl(FdMap::epollFd, EPOLL_CTL_DEL, fd, &epollEvent) < 0) {
637 // Check if fd exists. If not, assume, that it was closed earlier.
638 int errno_tmp = errno;
639 if (fcntl(fd, F_GETFD, FD_CLOEXEC) >= 0) {
640 errno = errno_tmp;
641 TTCN_error("System call epoll_ctl failed when deleting fd: %d, "
642 "errno: %d", fd, errno);
643 }
644 // fd was closed before removing it from the database of TITAN.
645 // This removes fd from the epoll set causing epoll_ctl to fail.
646 errno = 0; // It is not an error if epoll_ctl fails here
647 }
648 } else {
649 // There is still event type to wait for. - This is the unusual case.
650 epollEvent.events = FdMap::eventToEpollEvent(newEvent);
651 if (epoll_ctl(FdMap::epollFd, EPOLL_CTL_MOD, fd, &epollEvent) < 0) {
652 TTCN_error("System call epoll_ctl failed when removing fd: %d, "
653 "errno: %d", fd, errno);
654 }
655 }
656#endif
657}
658
659void Fd_And_Timeout_User::set_timer(Fd_And_Timeout_Event_Handler * handler,
660 double call_interval,
661 boolean is_timeout, boolean call_anyway, boolean is_periodic)
662{
663 if (call_interval != 0.0) {
664 if (handler->list == 0) timedList.add(handler);
665 handler->callInterval = call_interval;
666 handler->last_called = TTCN_Snapshot::time_now();
667 handler->isTimeout = is_timeout;
668 handler->callAnyway = call_anyway;
669 handler->isPeriodic = is_periodic;
670 } else {
671 if (handler->list == &timedList) timedList.remove(handler);
672 // Note: Normally the port may be only in timedList or in no list.
673 // - The port is put in oldApiCallList only temporarily while calling
674 // event handlers.
675 // The set_timer method may be called from outside snapshot evaluation
676 // or in the event handler. In both cases the port is removed from
677 // oldApiCallList beforehand.
678 // - However when MC requests a port to be unmapped: the request is
679 // processed in the event handler of MC_Connection. In this event
680 // handler a port may be unmapped which has been put in oldApiCallList
681 // temporarily.
682 handler->callInterval = 0.0;
683 }
684}
685
686void Fd_And_Timeout_User::set_fds_with_fd_sets(
687 Fd_And_Timeout_Event_Handler * handler,
688 const fd_set *read_fds, const fd_set *write_fds, const fd_set *error_fds)
689{
690 // Probaly in class PORT: Install_Handler should not be possible to be
691 // called from new event handlers
692 int fdLimit = FdMap::getFdLimit();
693 if ((int)FD_SETSIZE < fdLimit) fdLimit = FD_SETSIZE;
694 if (handler->fdSets == 0) {
695 if (handler->fdCount != 0) {
696 // Usage of the new and old API is mixed. - It should not happen.
697 // It is handled, but not most efficiently.
698 remove_all_fds(handler);
699 }
700 handler->fdSets = new FdSets;
701 ++nOldHandlers;
702 if (fdSetsReceived == 0) fdSetsReceived = new FdSets;
703 if (fdSetsToHnds == 0) fdSetsToHnds = new FdSets;
704 }
705 FdSets * fdSets = handler->fdSets;
706 fd_event_type_enum eventOld, eventNew;
707#ifdef USE_EPOLL
708 // Removing fds which refer to different descriptors than
709 // in the previous call. (closed and other fd created with same id)
710 epoll_event epollEvent;
711 for (int fd = 0; ; ++fd) {
712 fd = fdSets->getIxBothAnySet(read_fds, write_fds, error_fds,fd,fdLimit);
713 if (fd >= fdLimit) break;
714 memset(&epollEvent, 0, sizeof(epollEvent));
715 epollEvent.data.fd = fd;
716 // Check (inverse) if fd is still in the epoll set
717 if (epoll_ctl(FdMap::epollFd, EPOLL_CTL_ADD, fd, &epollEvent) >= 0 ) {
718 // fd was not in the epoll set as fd was closed and a new
719 // descriptor was created with the same id.
720 eventOld = fdSets->getEvent(fd);
721 Fd_And_Timeout_User::remove_fd(fd, handler, eventOld);
722 } else {
723 errno = 0; // fd is already in the epoll set - it is not an error
724 }
725 }
726#endif
727 fd_event_type_enum event;
728 for (int fd = 0; ; ++fd) {
729 fd = fdSets->getIxDiff(read_fds, write_fds, error_fds, fd, fdLimit);
730 if (fd >= fdLimit) break;
731 eventOld = fdSets->getEvent(fd);
732 eventNew = FdSets::getEvent(read_fds, write_fds, error_fds, fd);
733 event = static_cast<fd_event_type_enum>(eventNew & ~eventOld);
734 if (event != 0) Fd_And_Timeout_User::add_fd(fd, handler, event);
735 event = static_cast<fd_event_type_enum>(eventOld & ~eventNew);
736 if (event != 0) Fd_And_Timeout_User::remove_fd(fd, handler, event);
737 }
738}
739
740void Fd_And_Timeout_User::remove_all_fds(Fd_And_Timeout_Event_Handler * handler)
741{
742 if (handler->fdSets != 0 &&
743#ifdef USE_EPOLL
744 !FdMap::isItems1Used()
745#else
746 (unsigned) FdMap::getSize() > FD_SETSIZE / sizeof(long)
747#endif
748 ) {
749 // FdSets is used to enumerate and remove all file descriptor of
750 // the specified handler
751 FdSets * fdSets = handler->fdSets;
752 for (int fd = 0; handler->fdCount != 0; ++fd) {
753 fd = fdSets->getIxSet(fd, FD_SETSIZE);
754 if (fd >= (int)FD_SETSIZE)
755 TTCN_error("Fd_And_Timeout_User::remove_all_fds Internal "
756 "error 1: fdCount: %i", handler->fdCount);//debug
757 Fd_And_Timeout_User::remove_fd(fd, handler, fdSets->getEvent(fd));
758 }
759 } else {
760 // FdMap is used to enumerate and remove all file descriptor of
761 // the specified handler
762 Fd_Event_Handler * hnd = 0;
763 fd_event_type_enum event = static_cast<fd_event_type_enum>(0);
764 int i;
765 int fd = -1;
766#ifdef USE_EPOLL
767 int fdLimit = FdMap::getFdLimit();
768 while (handler->fdCount != 0 && !FdMap::isItems1Used()) {
769 do {
770 if (++fd >= fdLimit)
771 TTCN_error("Fd_And_Timeout_User::remove_all_fds Internal "
772 "error 2: fdCount: %i", handler->fdCount);//debug
773 event = FdMap::item2atFd(fd, &hnd);
774 } while (event == 0 || hnd != handler);
775 Fd_And_Timeout_User::remove_fd(fd, handler, event);
776 }
777#else
778 i = -1;
779 while (handler->fdCount != 0 && !FdMap::isItems1Used()) {
780 pollfd * pollFds = FdMap::getPollFds();
781 do {
782 ++i;
783 if (i >= FdMap::getSize())
784 TTCN_error("Fd_And_Timeout_User::remove_all_fds Internal "
785 "error 3: fdCount: %i", handler->fdCount);//debug
786 fd = pollFds[i].fd;
787 event = FdMap::item2atFd(fd, &hnd);
788 } while (event == 0 || hnd != handler);
789 Fd_And_Timeout_User::remove_fd(fd, handler, event);
790 --i; // recheck pollfd item at index i
791 }
792#endif
793 i = -1;
794 while (handler->fdCount != 0) {
795 do {
796 if (++i >= FdMap::getSize())
797 TTCN_error("Fd_And_Timeout_User::remove_all_fds Internal "
798 "error 4: fdCount: %i", handler->fdCount);//debug
799 event = FdMap::item1atIndex(i, &fd, &hnd);
800 } while (event == 0 || hnd != handler);
801 Fd_And_Timeout_User::remove_fd(fd, handler, event);
802 --i; // recheck item at index i
803 }
804 }
805 if (handler->fdSets != 0) {
806 delete handler->fdSets; handler->fdSets = 0;
807 --nOldHandlers;
808 if (nOldHandlers == 0) {
809 delete fdSetsReceived; fdSetsReceived = 0;
810 delete fdSetsToHnds; fdSetsToHnds = 0;
811 }
812 }
813}
814
815bool Fd_And_Timeout_User::getTimeout(double * timeout)
816{
817 timedList.first();
818 if (timedList.finished()) return false;
819
820 Fd_And_Timeout_Event_Handler * handler = timedList.current();
821 double earliestTimeout = handler->last_called + handler->callInterval;
822 timedList.next();
823
824 while (!timedList.finished()) {
825 handler = timedList.current();
826 timedList.next();
827 double nextCall = handler->last_called + handler->callInterval;
828 if (nextCall < earliestTimeout) earliestTimeout = nextCall;
829 }
830 *timeout = earliestTimeout;
831 return true;
832}
833
834void Fd_And_Timeout_User::call_handlers(int nEvents)
835{
836 try { // To keep consistency in case of exceptions
837 is_in_call_handlers = true;
838 if (nOldHandlers != 0) { fdSetsReceived->clear(); }
839 if (nEvents > 0) {
840 // Note: FdMap may be modified during event handler calls
841#ifdef USE_EPOLL
842 FdMap::epollMarkFds(nEvents);
843 int ixLimit = nEvents;
844#else
845 FdMap::pollFreeze();
846 int ixLimit = FdMap::getSize();
847 // Below this index pollfd array items are not removed
848 // If an item should have been removed, then the events field is 0
849#endif
850 try { // To keep consistency in case of exceptions
851 for (int ix = 0; ix != ixLimit; ++ix) {
852#ifdef USE_EPOLL
853 int fd = FdMap::epollEvents[ix].data.fd;
854 fd_event_type_enum event =
855 FdMap::epollEventToEvent(FdMap::epollEvents[ix].events);
856#else
857 pollfd * pollFd = &(FdMap::getPollFds()[ix]);
858 if ((pollFd->revents & FdMap::pollEventMask) == 0) continue;
859 int fd = pollFd->fd;
860 fd_event_type_enum event = FdMap::pollEventToEvent(pollFd->revents);
861 // The event handler may need pollFd.revents or epoll .events
862#endif
863 Fd_Event_Handler * handler = 0;
864 fd_event_type_enum wEvent = FdMap::find(fd, &handler);
865 if (wEvent != 0) {
866 event = static_cast<fd_event_type_enum>(
867 event & (wEvent | FD_EVENT_ERR));
868 if (event != 0) {
869 curRcvdEvtIx = ix; // see getCurReceivedEvent()
870 Fd_And_Timeout_Event_Handler * tmHnd =
871 dynamic_cast<Fd_And_Timeout_Event_Handler*>(handler);
872 if (tmHnd != 0 && tmHnd->getIsOldApi()) {
873 fdSetsReceived->add(fd, event);
874 if (tmHnd->list == 0) oldApiCallList.add(tmHnd);
875 } else
876 handler->Handle_Fd_Event(fd, (event & FD_EVENT_RD) != 0,
877 (event & FD_EVENT_WR) != 0,
878 (event & FD_EVENT_ERR) != 0);
879 if (tmHnd != 0 && tmHnd->list == &timedList)
880 tmHnd->hasEvent = TRUE;
881 }
882 }
883#ifndef USE_EPOLL
884 pollFd->revents = 0;
885#endif
886 }
887 } catch(...) {
888#ifdef USE_EPOLL
889 FdMap::epollUnmarkFds(nEvents);
890#else
891 FdMap::pollUnfreeze();
892#endif
893 throw;
894 }
895#ifdef USE_EPOLL
896 FdMap::epollUnmarkFds(nEvents);
897#else
898 FdMap::pollUnfreeze();
899#endif
900 // Call handlers with old API without timer
901 for (oldApiCallList.first(); !oldApiCallList.finished(); ) {
902 Fd_And_Timeout_Event_Handler * handler = oldApiCallList.current();
903 oldApiCallList.next();
904 oldApiCallList.remove(handler);
905 // Check if the event handler was uninstalled in the meanwhile
906 // (Currently the check is superfluous as an other event handler
907 // may not uninstall this event handler.)
908 if (handler->fdSets == 0) continue;
909 // Get the common set of received and waited events
910 // Check if the set contains any element
911 if ( fdSetsToHnds->setAnd(*fdSetsReceived, *handler->fdSets) ) {
912 double current_time = TTCN_Snapshot::time_now();
913 double time_since_last_call = current_time -
914 handler->last_called;
915 handler->last_called = current_time;
916 handler->Event_Handler(fdSetsToHnds->getReadFds(),
917 fdSetsToHnds->getWriteFds(), fdSetsToHnds->getErrorFds(),
918 time_since_last_call);
919 }
920 }
921 }
922 // Call timeout handlers (also handlers with old API with timer)
923 double current_time = TTCN_Snapshot::time_now();
924 for (timedList.first(); !timedList.finished(); ) {
925 Fd_And_Timeout_Event_Handler * handler = timedList.current();
926 timedList.next(); // The handler may be removed from the list
927 if (handler->getIsOldApi())
928 handler->hasEvent =
929 fdSetsToHnds->setAnd(*fdSetsReceived, *handler->fdSets);
930 bool callHandler = (handler->hasEvent && handler->isTimeout) ?
931 handler->callAnyway :
932 current_time > (handler->last_called + handler->callInterval);
933 if ( !handler->isPeriodic &&
934 (callHandler || (handler->hasEvent && handler->isTimeout)) ) {
935 handler->callInterval = 0.0;
936 timedList.remove(handler);
937 }
938 handler->hasEvent = FALSE;
939 if (callHandler) {
940 double time_since_last_call = current_time - handler->last_called;
941 handler->last_called = current_time;
942 if (!handler->getIsOldApi())
943 handler->Handle_Timeout(time_since_last_call);
944 else if (handler->fdSets != 0)
945 handler->Event_Handler(fdSetsToHnds->getReadFds(),
946 fdSetsToHnds->getWriteFds(), fdSetsToHnds->getErrorFds(),
947 time_since_last_call);
948 current_time = TTCN_Snapshot::time_now();
949 }
950 }
951 is_in_call_handlers = false;
952 } catch (...) { oldApiCallList.clear(); is_in_call_handlers = false; throw; }
953}
954
955int Fd_And_Timeout_User::receiveEvents(int pollTimeout)
956{
957 int ret_val;
958#ifdef USE_EPOLL
959 ret_val = epoll_wait(FdMap::epollFd,
960 FdMap::epollEvents, FdMap::MAX_EPOLL_EVENTS, pollTimeout);
961 if (ret_val < 0 && errno != EINTR)
962 TTCN_error("System call epoll_wait() failed when taking a new snapshot.");
963#else
964 ret_val = poll(FdMap::getPollFds(), FdMap::getSize(), pollTimeout);
965 if (ret_val < 0 && errno != EINTR)
966 TTCN_error("System call poll() failed when taking a new snapshot.");
967#endif
968 return ret_val;
969}
970
971#ifdef USE_EPOLL
972void Fd_And_Timeout_User::reopenEpollFd()
973{
974 if (FdMap::epollFd != -1) { close (FdMap::epollFd); FdMap::epollFd = -1; }
975 FdMap::epollFd = epoll_create(16 /* epoll size hint */);
976 // FIXME: method to determine the optimal epoll size hint
977 // epoll size hint is ignored in newer kernels
978 // for older kernels: it should be big enough not to be too slow
979 // and it should not be very big to limit memory usage
980 if (FdMap::epollFd < 0)
981 TTCN_error("System call epoll_create() failed in child process.");
982
983 if (FdMap::getSize() != 1)
984 TTCN_error("Fd_And_Timeout_User::reopenEpollFd: Internal error");
985}
986#endif
987
988
989
990
991
992/******************************************************************************
993 * class TTCN_Snapshot *
994 ******************************************************************************/
995
996boolean TTCN_Snapshot::else_branch_found;
997double TTCN_Snapshot::alt_begin;
998
999void TTCN_Snapshot::initialize()
1000{
1001 long openMax = sysconf(_SC_OPEN_MAX);
1002 int fdLimit = (openMax <= (long) MAX_INT_VAL) ? (int) openMax : MAX_INT_VAL;
1003
1004 FdMap::initialize(fdLimit);
1005 Fd_And_Timeout_User::initialize();
1006#ifdef USE_EPOLL
1007 FdMap::epollFd = epoll_create(16 /* epoll size hint */);
1008 // FIXME: method to determine the optimal epoll size hint
1009 // epoll size hint is ignored in newer kernels
1010 // for older kernels: it should be big enough not to be too slow
1011 // and it should not be very big to limit memory usage
1012 if (FdMap::epollFd < 0)
1013 TTCN_error("TTCN_Snapshot::initialize: "
1014 "System call epoll_create() failed.");
1015#endif
1016 else_branch_found = FALSE;
1017 alt_begin = time_now();
1018}
1019
1020void TTCN_Snapshot::check_fd_setsize()
1021{
1022 if ((long) FdMap::getFdLimit() > (long) FD_SETSIZE)
1023 TTCN_Logger::log_fd_limits(FdMap::getFdLimit(), (long) FD_SETSIZE);
1024}
1025
1026void TTCN_Snapshot::terminate()
1027{
1028#ifdef USE_EPOLL
1029 if (FdMap::epollFd != -1) { close (FdMap::epollFd); FdMap::epollFd = -1; }
1030#endif
1031 Fd_And_Timeout_User::terminate();
1032 FdMap::terminate();
1033}
1034
1035void TTCN_Snapshot::else_branch_reached()
1036{
1037 if (!else_branch_found) {
1038 else_branch_found = TRUE;
1039 TTCN_warning("An [else] branch of an alt construct has been reached. "
1040 "Re-configuring the snapshot manager to call the event handlers "
1041 "even when taking the first snapshot.");
1042 }
1043}
1044
1045double TTCN_Snapshot::time_now()
1046{
1047 static time_t start_time;
1048 static boolean first_call = TRUE;
1049 struct timeval tv;
1050 if (gettimeofday(&tv, NULL) == -1)
1051 TTCN_error("gettimeofday() system call failed.");
1052 if (first_call) {
1053 start_time = tv.tv_sec;
1054 first_call = FALSE;
1055 }
1056 return (double)(tv.tv_sec - start_time) + 1e-6 * (double)tv.tv_usec;
1057}
1058
1059
1060void TTCN_Snapshot::take_new(boolean block_execution)
1061{
1062 if (block_execution || else_branch_found) {
1063
1064 // jump here if epoll()/poll()/select() was interrupted by a signal
1065 again:
1066 // determine the timeout value for epoll()/poll()/select()
1067 double timeout = 0.0;
1068 int pollTimeout = 0; // timeout for poll/epoll
1069 bool handleTimer = false;
1070 if (block_execution) {
1071 // find the earliest timeout
1072 double timer_timeout, handler_timeout = 0.0;
1073 boolean is_timer_timeout = TIMER::get_min_expiration(timer_timeout);
1074 bool is_handler_timeout =
1075 Fd_And_Timeout_User::getTimeout(&handler_timeout);
1076 if (is_timer_timeout) {
1077 if (is_handler_timeout && handler_timeout < timer_timeout)
1078 timeout = handler_timeout;
1079 else timeout = timer_timeout;
1080 } else if (is_handler_timeout) timeout = handler_timeout;
1081 if (is_timer_timeout || is_handler_timeout) {
1082 // there are active TTCN-3 or test port timers
1083 double current_time = time_now();
1084 double block_time = timeout - current_time;
1085 if (block_time > 0.0) {
1086 // the first timeout is in the future: blocking is needed
1087 // filling up tv with appropriate values
1088 if (block_time < (double)MAX_BLOCK_TIME) {
1089 pollTimeout = static_cast<int>(floor(block_time*1000));
1090 handleTimer = true;
1091 } else {
1092 // issue a warning: the user probably does not want such
1093 // long waiting
1094 TTCN_warning("The time needed for the first timer "
1095 "expiry is %g seconds. The operating system does "
1096 "not support such long waiting at once. The "
1097 "maximum time of blocking was set to %d seconds "
1098 "(ca. %d days).", block_time, MAX_BLOCK_TIME,
1099 MAX_BLOCK_TIME / 86400);
1100 // also modify the the timeout value to get out
1101 // immediately from the while() loop below
1102 timeout = current_time + (double)MAX_BLOCK_TIME;
1103 pollTimeout = MAX_BLOCK_TIME * 1000;
1104 handleTimer = true;
1105 }
1106 } else {
1107 // first timer is already expired: do not block
1108 // pollTimeout is 0
1109 handleTimer = true;
1110 }
1111 } else {
1112 // no active timers: infinite timeout
1113 pollTimeout = -1;
1114 }
1115 } else {
1116 // blocking was not requested (we are in a first snapshot after an
1117 // [else] branch): do not block - pollTimeout is 0
1118 }
1119
1120 if (FdMap::getSize() == 0 && pollTimeout < 0)
1121 TTCN_error("There are no active timers and no installed event "
1122 "handlers. Execution would block forever.");
1123
1124 int ret_val = 0;
1125 if (FdMap::getSize() != 0) {
1126 ret_val = Fd_And_Timeout_User::receiveEvents(pollTimeout);
1127 // call epoll_wait() / poll()
1128 if (ret_val < 0) { /* EINTR - signal */ errno = 0; goto again; }
1129 } else {
1130 // There isn't any file descriptor to check
1131 if (pollTimeout > 0) {
1132 // waiting only for a timeout in the future
1133 timeval tv;
1134 tv.tv_sec = pollTimeout / 1000;
1135 tv.tv_usec = (pollTimeout % 1000) * 1000;
1136 ret_val = select(0, NULL, NULL, NULL, &tv);
1137 if (ret_val < 0 && errno == EINTR) {
1138 /* signal */ errno = 0; goto again;
1139 }
1140 if ((ret_val < 0 && errno != EINTR) || ret_val > 0)
1141 TTCN_error("System call select() failed when taking a new "
1142 "snapshot.");
1143 } else if (pollTimeout < 0)
1144 TTCN_error("There are no active timers or installed event "
1145 "handlers. Execution would block forever.");
1146 }
1147
1148 if (ret_val > 0) {
1149 Fd_And_Timeout_User::call_handlers(ret_val);
1150 } else if (ret_val == 0 && handleTimer) {
1151 // if select() returned because of the timeout, but too early
1152 // do an other round if it has to wait much,
1153 // or do a busy wait if only a few cycles are needed
1154 if (pollTimeout > 0){
1155 double difference = time_now() - timeout;
1156 if(difference < 0.0){
1157 if(difference < -0.001){
1158 errno = 0;
1159 goto again;
1160 } else {
1161 while (time_now() < timeout) ;
1162 }
1163 }
1164 }
1165 Fd_And_Timeout_User::call_handlers(0); // Call timeout handlers
1166 }
1167 }
1168 // just update the time and check the testcase guard timer if blocking was
1169 // not requested and there is no [else] branch in the test suite
1170
1171 alt_begin = time_now();
1172
1173 if (testcase_timer.timeout() == ALT_YES)
1174 TTCN_error("Guard timer has expired. Execution of current test case "
1175 "will be interrupted.");
1176}
1177
1178void TTCN_Snapshot::block_for_sending(int send_fd, Fd_Event_Handler * handler)
1179{
1180 // To be backward compatible: handler is optional
1181 if (Fd_And_Timeout_User::get_is_in_call_handlers())
1182 TTCN_error("TTCN_Snapshot::block_for_sending: The function may not be "
1183 "called from event handler");
1184 Fd_Event_Handler * hnd = 0;
1185 if ((FdMap::find(send_fd, &hnd) & FD_EVENT_WR) != 0)
1186 TTCN_error("TTCN_Snapshot::block_for_sending: An event handler already "
1187 "waits for file descriptor %d to be writable", send_fd);
1188 if (handler != 0 && hnd != 0 && handler != hnd)
1189 TTCN_error("TTCN_Snapshot::block_for_sending: File descriptor %d "
1190 "already has a handler, which is different from the currently "
1191 "specified.", send_fd);
1192 static Fd_And_Timeout_Event_Handler dummyHandler;
1193 if (hnd == 0) { hnd = (handler != 0) ? handler : &dummyHandler; }
1194 Fd_And_Timeout_User::add_fd(send_fd, hnd, FD_EVENT_WR);
1195 for ( ; ; ) {
1196 int ret_val = Fd_And_Timeout_User::receiveEvents(-1); // epoll / poll
1197 if (ret_val >= 0) {
1198 bool writable = false;
1199 bool readable = false;
1200#ifdef USE_EPOLL
1201
1202 for (int i = 0; i < ret_val; ++i) {
1203 if (FdMap::epollEvents[i].data.fd == send_fd) {
1204 readable = true;
1205 if ((FdMap::epollEvents[i].events & EPOLLOUT) != 0){
1206 writable = true;
1207 }
1208 break;
1209 }
1210 }
1211#else
1212 if (FdMap::getPollREvent(send_fd) != 0) {readable = true;}
1213 if ((FdMap::getPollREvent(send_fd) & FD_EVENT_WR) != 0) {writable = true;}
1214#endif
1215 if (writable) break;
1216 Fd_And_Timeout_User::call_handlers(ret_val);
1217 if (readable) break;
1218 }
1219 // interrupted - EINTR
1220 }
1221 Fd_And_Timeout_User::remove_fd(send_fd, hnd, FD_EVENT_WR);
1222#ifndef USE_EPOLL
1223 // As Fd_And_Timeout_User::call_handlers is not called:
1224 // received events should be cleared at this point
1225 // (Most probably the behavior would be correct without clearing it.)
1226 int nPollFds = FdMap::getSize();
1227 pollfd * pollFds = FdMap::getPollFds();
1228 for (int i = 0; i < nPollFds; ++i) pollFds[i].revents = 0;
1229#endif
1230}
This page took 0.066439 seconds and 5 git commands to generate.