Solve legacy problem with clear operation (coredump with running threads)
[anna.git] / source / comm / internal / Poll.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #include <anna/comm/internal/Poll.hpp>
10
11 //-----------------------------------------------------------------------------------
12 //  RECORDAR QUE ESTA CLASE SOLO SE USA EN LA VERSION SINGLE-THREAD DEL
13 //  comm::Communicator
14 //-----------------------------------------------------------------------------------
15
16 using namespace anna;
17
18 void comm::Poll::setTimeout(const Millisecond &timeout)
19 throw() {
20   if((a_timeout.tv_sec = timeout / 1000) == 0)
21     a_timeout.tv_usec = timeout * 1000;
22   else
23     a_timeout.tv_usec = 0;
24
25   a_ptrTimeout = (a_timeout.tv_sec != 0 || a_timeout.tv_usec != 0) ? &a_timeout : NULL;
26 }
27
28 //--------------------------------------------------------------------------------------------
29 // Si a_ptrTimeout != NULL => se devuelve el tiempo que ha sobrado de la espera maxima
30 // establecida (en Solaris este puntero no se modifica para nada)
31 //
32 // Para las dos implementacion el NULL => espera hasta que llegue un mensaje.
33 //--------------------------------------------------------------------------------------------
34 void comm::Poll::waitMessage()
35 throw(RuntimeException) {
36   if(a_ptrTimeout == NULL)
37     a_pollr = select(a_maxfd, (fd_set*) anna_memcpy(&a_fdset, &a_fdmask, sizeof(fd_set)), NULL);
38   else {
39 #ifdef __linux__
40     timeval timeout(a_timeout);
41     a_pollr = select(a_maxfd, (fd_set*) anna_memcpy(&a_fdset, &a_fdmask, sizeof(fd_set)), &timeout);
42 #else
43     a_pollr = select(a_maxfd, (fd_set*) anna_memcpy(&a_fdset, &a_fdmask, sizeof(fd_set)), a_ptrTimeout);
44 #endif
45   }
46 }
47
48 //-----------------------------------------------------------------------------------------
49 // Se ha detectado una condicion de error. Se recibe trafico por fd = { 16, 19} y el
50 // tramiento de 16 => cierre de 19 mediante comm::Communicator::attach => el a_ifd no
51 // llegaba nunca a tratar al 19, porque el a_maxfd ha sido modificado con 16, pero el a_pollr
52 // sigue indicado que queda un fd por tratar. ver Poll::erase
53 //
54 // (1) Una vez que ha tratado detectado la activada desactiva el indicador
55 //-----------------------------------------------------------------------------------------
56 int comm::Poll::fetch()
57 throw() {
58   int result = -1;
59
60   while(a_pollr > 0) {
61     if(FD_ISSET(a_ifd, &a_fdset)) {
62       FD_CLR(a_ifd, &a_fdset);                                           // (1)
63       result = a_ifd ++;
64
65       if(a_ifd > a_maxfd)
66         a_ifd = a_minfd;
67
68       a_pollr --;
69       break;
70     }
71
72     if(++ a_ifd > a_maxfd)
73       a_ifd = a_minfd;
74   }
75
76   return result;
77 }
78
79 void comm::Poll::insert(const int fd)
80 throw() {
81   FD_SET(fd, &a_fdmask);
82
83   if(a_maxfd < fd) a_maxfd = fd;
84
85   if(fd < a_minfd)
86     a_ifd = a_minfd = fd;
87 }
88
89 //---------------------------------------------------------------------------------------
90 // Hay que comprobar que el 'fd' que vamos a eliminar de la lista no este en la lista
91 // de pendientes de tratar.
92 //---------------------------------------------------------------------------------------
93 void comm::Poll::erase(const int fd)
94 throw() {
95   FD_CLR(fd, &a_fdmask);
96
97   if(FD_ISSET(fd, &a_fdset) && a_pollr > 0) {                                // (1)
98     FD_CLR(fd, &a_fdset);
99     a_pollr --;
100   }
101
102   if(fd == a_maxfd || fd == a_minfd) {
103     const int max = a_maxfd;
104     a_maxfd = 0;
105     a_minfd = INT_MAX;
106
107     for(int ifd = 0; ifd <= max; ifd ++) {
108       if(FD_ISSET(ifd, &a_fdmask)) {
109         if(a_maxfd < ifd) a_maxfd = ifd;
110
111         if(ifd < a_minfd) a_minfd = ifd;
112       }
113     }
114
115     a_ifd = a_minfd;
116   }
117 }
118