bool PhysicalSocketServer::Wait(int cmsWait, bool process_io)
 {
     // Calculate timing information
     
     struct timeval *ptvWait = NULL;
     struct timeval tvWait;
     struct timeval tvStop;
     if (cmsWait > 0)
     {
         // Calculate wait timeval
         tvWait.tv_sec = cmsWait / 1000;
         tvWait.tv_usec = (cmsWait % 1000) * 1000;
         ptvWait = &tvWait;
         
         // Calculate when to return in a timeval
         gettimeofday(&tvStop, NULL);
         tvStop.tv_sec += tvWait.tv_sec;
         tvStop.tv_usec += tvWait.tv_usec;
         if (tvStop.tv_usec >= 1000000) {
             tvStop.tv_usec -= 1000000;
             tvStop.tv_sec += 1;
         }
     }
     
     // Zero all fd_sets. Don't need to do this inside the loop since
     // select() zeros the descriptors not signaled
     
     fd_set fdsRead;
     FD_ZERO(&fdsRead);
     fd_set fdsWrite;
     FD_ZERO(&fdsWrite);
     
     fWait_ = true;
     while (fWait_)
     {
         int fdmax = -1;
         {
             CriticalSectionScoped cr(&crit_);
             for (size_t i = 0; i < dispatchers_.size(); ++i)
             {
                 // Query dispatchers for read and write wait state
                 Dispatcher *pdispatcher = dispatchers_[i];
                 if (!process_io && (pdispatcher != signal_wakeup_))
                     continue;
                 int fd = pdispatcher->GetDescriptor();
                 if (fd > fdmax)
                     fdmax = fd;
                 
                 uint32 ff = pdispatcher->GetRequestedEvents();
                 if (ff & (DE_READ | DE_ACCEPT))
                     FD_SET(fd, &fdsRead);
                 if (ff & (DE_WRITE | DE_CONNECT))
                     FD_SET(fd, &fdsWrite);
             }
         }
         
         // Wait then call handlers as appropriate
         // < 0 means error
         // 0 means timeout
         // > 0 means count of descriptors ready
         int n = select(fdmax + 1, &fdsRead, &fdsWrite, NULL, ptvWait);
         
         // If error, return error.
         if (n < 0)
         {
             if (errno != EINTR)
             {
                 printf("select error. %d.\n", errno);
                 return false;
             }
             // Else ignore the error and keep going. If this EINTR was for one of the
             // signals managed by this PhysicalSocketServer, the
             // PosixSignalDeliveryDispatcher will be in the signaled state in the next
             // iteration.
         }
         else if (n == 0)
         {
             // If timeout, return success
             return true;
         }
         else
         {
             // We have signaled descriptors
             CriticalSectionScoped cr(&crit_);
             for (size_t i = 0; i < dispatchers_.size(); ++i)
             {
                 Dispatcher *pdispatcher = dispatchers_[i];
                 int fd = pdispatcher->GetDescriptor();
                 uint32 ff = 0;
                 int errcode = 0;
                 
                 // Reap any error code, which can be signaled through reads or writes.
                 // TODO: Should we set errcode if getsockopt fails?
                 if (FD_ISSET(fd, &fdsRead) || FD_ISSET(fd, &fdsWrite)) {
                     socklen_t len = sizeof(errcode);
                     ::getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &len);
                 }
                 
                 // Check readable descriptors. If we're waiting on an accept, signal
                 // that. Otherwise we're waiting for data, check to see if we're
                 // readable or really closed.
                 // TODO: Only peek at TCP descriptors.
                 if (FD_ISSET(fd, &fdsRead))
                 {
                     FD_CLR(fd, &fdsRead);
                     
                     if (pdispatcher->GetRequestedEvents() & DE_ACCEPT)
                     {
                         ff |= DE_ACCEPT;
                     }
                     else if (errcode || pdispatcher->IsDescriptorClosed())
                     {
                         ff |= DE_CLOSE;
                     }
                     else
                     {
                         ff |= DE_READ;
                     }
                 }
                 
                 // Check writable descriptors. If we're waiting on a connect, detect
                 // success versus failure by the reaped error code.
                 if (FD_ISSET(fd, &fdsWrite))
                 {
                     FD_CLR(fd, &fdsWrite);
                     
                     if (pdispatcher->GetRequestedEvents() & DE_CONNECT)
                     {
                         if (!errcode)
                         {
                             ff |= DE_CONNECT;
                         }
                         else
                         {
                             ff |= DE_CLOSE;
                         }
                     }
                     else
                     {
                         ff |= DE_WRITE;
                     }
                 }
                 
                 // Tell the descriptor about the event.
                 if (ff != 0)
                 {
                     pdispatcher->OnPreEvent(ff);
                     pdispatcher->OnEvent(ff, errcode);
                 }
             }
         }
         
         // Recalc the time remaining to wait. Doing it here means it doesn't get
         // calced twice the first time through the loop
         if (ptvWait)
         {
             ptvWait->tv_sec = 0;
             ptvWait->tv_usec = 0;
             struct timeval tvT;
             gettimeofday(&tvT, NULL);
             if ((tvStop.tv_sec > tvT.tv_sec) || ((tvStop.tv_sec == tvT.tv_sec)&& (tvStop.tv_usec > tvT.tv_usec)))
             {
                 ptvWait->tv_sec = tvStop.tv_sec - tvT.tv_sec;
                 ptvWait->tv_usec = tvStop.tv_usec - tvT.tv_usec;
                 if (ptvWait->tv_usec < 0)
                 {
                     ptvWait->tv_usec += 1000000;
                     ptvWait->tv_sec -= 1;
                 }
             }
         }
     }
     
     return true;
 }