ARPDAS_QNX6 1.0
|
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 }