Updated license
[anna.git] / source / comm / internal / Poll.cpp
1 // ANNA - Anna is Not Nothingness Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //     * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //     * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 //     * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #include <anna/comm/internal/Poll.hpp>
38
39 //-----------------------------------------------------------------------------------
40 //  RECORDAR QUE ESTA CLASE SOLO SE USA EN LA VERSION SINGLE-THREAD DEL
41 //  comm::Communicator
42 //-----------------------------------------------------------------------------------
43
44 using namespace anna;
45
46 void comm::Poll::setTimeout(const Millisecond &timeout)
47 throw() {
48   if((a_timeout.tv_sec = timeout / 1000) == 0)
49     a_timeout.tv_usec = timeout * 1000;
50   else
51     a_timeout.tv_usec = 0;
52
53   a_ptrTimeout = (a_timeout.tv_sec != 0 || a_timeout.tv_usec != 0) ? &a_timeout : NULL;
54 }
55
56 //--------------------------------------------------------------------------------------------
57 // Si a_ptrTimeout != NULL => se devuelve el tiempo que ha sobrado de la espera maxima
58 // establecida (en Solaris este puntero no se modifica para nada)
59 //
60 // Para las dos implementacion el NULL => espera hasta que llegue un mensaje.
61 //--------------------------------------------------------------------------------------------
62 void comm::Poll::waitMessage()
63 throw(RuntimeException) {
64   if(a_ptrTimeout == NULL)
65     a_pollr = select(a_maxfd, (fd_set*) anna_memcpy(&a_fdset, &a_fdmask, sizeof(fd_set)), NULL);
66   else {
67 #ifdef __linux__
68     timeval timeout(a_timeout);
69     a_pollr = select(a_maxfd, (fd_set*) anna_memcpy(&a_fdset, &a_fdmask, sizeof(fd_set)), &timeout);
70 #else
71     a_pollr = select(a_maxfd, (fd_set*) anna_memcpy(&a_fdset, &a_fdmask, sizeof(fd_set)), a_ptrTimeout);
72 #endif
73   }
74 }
75
76 //-----------------------------------------------------------------------------------------
77 // Se ha detectado una condicion de error. Se recibe trafico por fd = { 16, 19} y el
78 // tramiento de 16 => cierre de 19 mediante comm::Communicator::attach => el a_ifd no
79 // llegaba nunca a tratar al 19, porque el a_maxfd ha sido modificado con 16, pero el a_pollr
80 // sigue indicado que queda un fd por tratar. ver Poll::erase
81 //
82 // (1) Una vez que ha tratado detectado la activada desactiva el indicador
83 //-----------------------------------------------------------------------------------------
84 int comm::Poll::fetch()
85 throw() {
86   int result = -1;
87
88   while(a_pollr > 0) {
89     if(FD_ISSET(a_ifd, &a_fdset)) {
90       FD_CLR(a_ifd, &a_fdset);                                           // (1)
91       result = a_ifd ++;
92
93       if(a_ifd > a_maxfd)
94         a_ifd = a_minfd;
95
96       a_pollr --;
97       break;
98     }
99
100     if(++ a_ifd > a_maxfd)
101       a_ifd = a_minfd;
102   }
103
104   return result;
105 }
106
107 void comm::Poll::insert(const int fd)
108 throw() {
109   FD_SET(fd, &a_fdmask);
110
111   if(a_maxfd < fd) a_maxfd = fd;
112
113   if(fd < a_minfd)
114     a_ifd = a_minfd = fd;
115 }
116
117 //---------------------------------------------------------------------------------------
118 // Hay que comprobar que el 'fd' que vamos a eliminar de la lista no este en la lista
119 // de pendientes de tratar.
120 //---------------------------------------------------------------------------------------
121 void comm::Poll::erase(const int fd)
122 throw() {
123   FD_CLR(fd, &a_fdmask);
124
125   if(FD_ISSET(fd, &a_fdset) && a_pollr > 0) {                                // (1)
126     FD_CLR(fd, &a_fdset);
127     a_pollr --;
128   }
129
130   if(fd == a_maxfd || fd == a_minfd) {
131     const int max = a_maxfd;
132     a_maxfd = 0;
133     a_minfd = INT_MAX;
134
135     for(int ifd = 0; ifd <= max; ifd ++) {
136       if(FD_ISSET(ifd, &a_fdmask)) {
137         if(a_maxfd < ifd) a_maxfd = ifd;
138
139         if(ifd < a_minfd) a_minfd = ifd;
140       }
141     }
142
143     a_ifd = a_minfd;
144   }
145 }
146