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