ARPDAS_QNX6 1.0
Selector.cc
Go to the documentation of this file.
00001 #include <errno.h>
00002 #include <sys/select.h>
00003 #include "Selector.h"
00004 #include "nortlib.h"
00005 #include "nl_assert.h"
00006 
00007 Selector::Selector() {
00008   children_changed = false;
00009   gflags = 0;
00010 }
00011 
00012 /**
00013  * Actually does nothing.
00014  */
00015 Selector::~Selector() {
00016 }
00017 
00018 /**
00019  * Adds the Selectee as a child of the Selector. This adds the Selectee's fd
00020  * to the list of fds in the Selector's select() call, depending on the
00021  * Selectee's flags.
00022  */
00023 void Selector::add_child(Selectee *P) {
00024   if (S.find(P->fd) == S.end() ) {
00025     S[P->fd] = P;
00026     P->Stor = this;
00027     children_changed = true;
00028   } else {
00029     nl_error( 4, "fd %d already inserted in Selector::add_child", P->fd );
00030   }
00031 }
00032 
00033 /**
00034  * Removes Selectee from the Selector and deletes the Selectee. Note that this
00035  * is for use in a special case where the fd is being closed and the child
00036  * needs to be deleted, but the caller does not know the mapping from the fd
00037  * to the Selectee. In the usual case, the Selectee is deleted by its owner
00038  * after the event_loop has exited, and it is unnecessary to explicitly
00039  * remove the Selectees as children of the Selector.
00040  */
00041 void Selector::delete_child(int fd_in) {
00042   SelecteeMap::iterator pos;
00043   Selectee *P;
00044   pos = S.find(fd_in);
00045   if ( pos == S.end() )
00046     nl_error( 4, "Selectee not found for fd %d in Selector::delete_child()", fd_in );
00047   P = pos->second;
00048   nl_assert( fd_in == P->fd );
00049   if ( S.erase(fd_in) == 0 ) {
00050     nl_error( 4, "fd %d not found in Selector::delete_child()", P->fd);
00051   }
00052   children_changed = true;
00053   delete P;
00054 }
00055 
00056 /**
00057  * Useful when we know the fd but not the Selectee.
00058  * \returns 0 on success, 1 if fd_in is not found.
00059  */
00060 int Selector::update_flags(int fd_in, int flag) {
00061   SelecteeMap::const_iterator pos;
00062   pos = S.find(fd_in);
00063   if ( pos != S.end() ) {
00064     Selectee *P = pos->second;
00065     P->flags = flag;
00066     children_changed = true;
00067     return 0;
00068   } else {
00069     return 1;
00070   }
00071 }
00072 
00073 /**
00074  * Sets a bit in the global flags word. Selectees can set
00075  * a corresponding bit in their flags word to request
00076  * notification when the bit gets set. The function
00077  * Selector::gflag(gflag_index) returns the bit that
00078  * corresponds to set_gflag(gflag_index). gflag_index
00079  * can take on values from 0 to 8*sizeof(int)-4.
00080  */
00081 void Selector::set_gflag( unsigned gflag_index ) {
00082   nl_assert(gflag_index+4 < sizeof(int)*8 );
00083   gflags |= gflag(gflag_index);
00084 }
00085 
00086 /**
00087  * Loops waiting on select(), using the fds and flags of
00088  * each Selectee registered via add_child(). When select()
00089  * indicates that an fd is ready, the corresponding Selectee's
00090  * ProcessData() method is invoked with the flag value indicating
00091  * what action is ready.
00092  */
00093 void Selector::event_loop() {
00094   int keep_going = 1;
00095   int width = 0;
00096   int rc;
00097   fd_set readfds, writefds, exceptfds;
00098   
00099   while (keep_going) {
00100     TimeoutAccumulator to;
00101     SelecteeMap::const_iterator Sp;
00102 
00103     FD_ZERO(&readfds);
00104     FD_ZERO(&writefds);
00105     FD_ZERO(&exceptfds);
00106     to.Set_Min(GetTimeout());
00107     children_changed = false;
00108     for ( Sp = S.begin(); Sp != S.end(); ++Sp ) {
00109       Selectee *P = Sp->second;
00110       if (P->flags & gflags) {
00111         P->ProcessData(P->flags & gflags);
00112         gflags &= ~(P->flags & gflags);
00113       }
00114     }
00115     for ( Sp = S.begin(); Sp != S.end(); ++Sp ) {
00116       Selectee *P = Sp->second;
00117       if (P->flags & Sel_Read) FD_SET(P->fd, &readfds);
00118       if (P->flags & Sel_Write) FD_SET(P->fd, &writefds);
00119       if (P->flags & Sel_Except) FD_SET(P->fd, &exceptfds);
00120       if (P->flags & Sel_Timeout) to.Set_Min( P->GetTimeout() );
00121       if (width <= P->fd) width = P->fd+1;
00122     }
00123     rc = select(width, &readfds, &writefds, &exceptfds, to.timeout_val());
00124     if ( rc == 0 ) {
00125       if ( ProcessTimeout() )
00126         keep_going = 0;
00127       for ( Sp = S.begin(); Sp != S.end(); ++Sp ) {
00128         Selectee *P = Sp->second;
00129         if ((P->flags & Sel_Timeout) && P->ProcessData(Sel_Timeout))
00130           keep_going = 0;
00131       }
00132     } else if ( rc < 0 ) {
00133       if ( errno == EINTR ) keep_going = 0;
00134       else nl_error(3, "Unexpected error: %d", errno);
00135     } else {
00136       for ( Sp = S.begin(); Sp != S.end(); ++Sp ) {
00137         Selectee *P = Sp->second;
00138         int flags = 0;
00139         if ( (P->flags & Sel_Read) && FD_ISSET(P->fd, &readfds) )
00140           flags |= Sel_Read;
00141         if ( (P->flags & Sel_Write) && FD_ISSET(P->fd, &writefds) )
00142           flags |= Sel_Write;
00143         if ( (P->flags & Sel_Except) && FD_ISSET(P->fd, &exceptfds) )
00144           flags |= Sel_Except;
00145         if ( flags ) {
00146           if ( P->ProcessData(flags) )
00147             keep_going = 0;
00148           if (children_changed) break; // Changes can occur during ProcessData
00149         }
00150       }
00151     }
00152   }
00153 }
00154 
00155 /**
00156  * Virtual method called whenever select() returns 0. The default does nothing,
00157  * but it can be overridden.
00158  * @return non-zero if the event loop should terminate.
00159  */
00160 int Selector::ProcessTimeout() { return 0; }
00161 
00162 /**
00163  * Virtual method to allow Selector to bid on the select() timeout
00164  * along with the Selectee children. The minimum timeout value is used.
00165  * @return a Timeout * indicating the requested timeout value or NULL.
00166  */
00167 Timeout *Selector::GetTimeout() { return NULL; }
00168 
00169 extern "C" {
00170   char libtmpp_is_present(void) { return '\0'; }
00171 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines