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