]> git.saurik.com Git - wxWidgets.git/commitdiff
use DispatchTimeout() and/or select() with timeout instead of polling loop in wxSocke...
authorVadim Zeitlin <vadim@wxwidgets.org>
Fri, 26 Dec 2008 22:50:50 +0000 (22:50 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Fri, 26 Dec 2008 22:50:50 +0000 (22:50 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@57572 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/private/socket.h
src/common/socket.cpp

index d953f082ec14e94dd3a837cabfb89020a80a5a70..078593477ff94481c98e98f11cc8f8b1845292ae 100644 (file)
@@ -255,7 +255,14 @@ public:
     virtual int Read(void *buffer, int size) = 0;
     virtual int Write(const void *buffer, int size) = 0;
 
-    wxSocketEventFlags Select(wxSocketEventFlags flags);
+    // basically a wrapper for select(): returns the condition of the socket,
+    // blocking for not longer than timeout ms for something to become
+    // available
+    //
+    // flags defines what kind of conditions we're interested in, the return
+    // value is composed of a (possibly empty) subset of the bits set in flags
+    wxSocketEventFlags Select(wxSocketEventFlags flags,
+                              unsigned long timeout = 0);
 
     virtual wxSocketImpl *WaitConnection(wxSocketBase& wxsocket) = 0;
 
index 221af68ee49af82acad2a54f033f33b7a9ab4b2c..071b0d53964bb724857d12a0f40d3902c90ef055 100644 (file)
@@ -69,6 +69,21 @@ IMPLEMENT_CLASS(wxSocketClient, wxSocketBase)
 IMPLEMENT_CLASS(wxDatagramSocket, wxSocketBase)
 IMPLEMENT_DYNAMIC_CLASS(wxSocketEvent, wxEvent)
 
+// ----------------------------------------------------------------------------
+// private functions
+// ----------------------------------------------------------------------------
+
+namespace
+{
+
+void SetTimeValFromMS(timeval& tv, unsigned long ms)
+{
+    tv.tv_sec  = (ms / 1000);
+    tv.tv_usec = (ms % 1000) * 1000;
+}
+
+} // anonymous namespace
+
 // --------------------------------------------------------------------------
 // private classes
 // --------------------------------------------------------------------------
@@ -390,8 +405,7 @@ void wxSocketImpl::Shutdown()
  */
 void wxSocketImpl::SetTimeout(unsigned long millis)
 {
-    m_timeout.tv_sec  = (millis / 1000);
-    m_timeout.tv_usec = (millis % 1000) * 1000;
+    SetTimeValFromMS(m_timeout, millis);
 }
 
 void wxSocketImpl::NotifyOnStateChange(wxSocketNotify event)
@@ -1106,29 +1120,23 @@ wxSocketBase& wxSocketBase::Discard()
 // --------------------------------------------------------------------------
 
 /*
- *  Polls the socket to determine its status. This function will
- *  check for the events specified in the 'flags' parameter, and
- *  it will return a mask indicating which operations can be
- *  performed. This function won't block, regardless of the
- *  mode (blocking | nonblocking) of the socket.
+    This function will check for the events specified in the flags parameter,
+    and it will return a mask indicating which operations can be performed.
  */
-wxSocketEventFlags wxSocketImpl::Select(wxSocketEventFlags flags)
+wxSocketEventFlags wxSocketImpl::Select(wxSocketEventFlags flags,
+                                        unsigned long timeout)
 {
-  assert(this);
-
   wxSocketEventFlags result = 0;
-  fd_set readfds;
-  fd_set writefds;
-  fd_set exceptfds;
-  struct timeval tv;
 
   if (m_fd == INVALID_SOCKET)
     return (wxSOCKET_LOST_FLAG & flags);
 
-  /* Do not use a static struct, Linux can garble it */
-  tv.tv_sec = 0;
-  tv.tv_usec = 0;
+  struct timeval tv;
+  SetTimeValFromMS(tv, timeout);
 
+  fd_set readfds;
+  fd_set writefds;
+  fd_set exceptfds;
   wxFD_ZERO(&readfds);
   wxFD_ZERO(&writefds);
   wxFD_ZERO(&exceptfds);
@@ -1211,12 +1219,6 @@ wxSocketEventFlags wxSocketImpl::Select(wxSocketEventFlags flags)
   return (result | m_detected) & flags;
 }
 
-// All Wait functions poll the socket using Select() to
-// check for the specified combination of conditions, until one
-// of these conditions become true, an error occurs, or the
-// timeout elapses. The polling loop runs the event loop so that
-// this won't block the GUI.
-
 bool
 wxSocketBase::DoWait(long seconds, long milliseconds, wxSocketEventFlags flags)
 {
@@ -1247,33 +1249,55 @@ wxSocketBase::DoWait(long seconds, long milliseconds, wxSocketEventFlags flags)
         eventLoop = NULL;
     }
 
-    // reset them before starting to wait
-    m_eventsgot = 0;
-
-    // Wait in an active polling loop: notice that the loop is executed at
-    // least once, even if timeout is 0 (i.e. polling).
+    // Wait until we receive the event we're waiting for or the timeout expires
+    // (but note that we always execute the loop at least once, even if timeout
+    // is 0 as this is used for polling)
     bool gotEvent = false;
-    for ( ;; )
+    for ( bool firstTime = true; !m_interrupt ; firstTime = false )
     {
+        long timeLeft = wxMilliClockToLong(timeEnd - wxGetLocalTimeMillis());
+        if ( timeLeft < 0 )
+        {
+            if ( !firstTime )
+                break;   // timed out
+
+            timeLeft = 0;
+        }
+
+        // This function is only called if wxSOCKET_BLOCK flag was not used and
+        // so we should dispatch the events if there is an event loop capable
+        // of doing it.
         wxSocketEventFlags events;
         if ( eventLoop )
         {
-            // This function is only called if wxSOCKET_BLOCK flag was not used
-            // and so we should dispatch the events if there is an event loop
-            // capable of doing it.
-            if ( eventLoop->Pending() )
-                eventLoop->Dispatch();
+            // reset them before starting to wait
+            m_eventsgot = 0;
+
+            eventLoop->DispatchTimeout(timeLeft);
 
             events = m_eventsgot;
         }
-        else
+        else // no event loop or waiting in another thread
+        {
+            // as explained below, we should always check for wxSOCKET_LOST_FLAG
+            events = m_impl->Select(flags | wxSOCKET_LOST_FLAG, timeLeft);
+        }
+
+        // always check for wxSOCKET_LOST_FLAG, even if flags doesn't include
+        // it, as continuing to wait for anything else after getting it is
+        // pointless
+        if ( events & wxSOCKET_LOST_FLAG )
         {
-            // We always stop waiting when the connection is lost as it doesn't
-            // make sense to continue further, even if wxSOCKET_LOST_FLAG is
-            // not specified in flags to wait for.
-            events = m_impl->Select(flags | wxSOCKET_LOST_FLAG);
+            m_connected = false;
+            m_establishing = false;
+            if ( flags & wxSOCKET_LOST_FLAG )
+                gotEvent = true;
+            break;
         }
 
+        // otherwise mask out the bits we're not interested in
+        events &= flags;
+
         // Incoming connection (server) or connection established (client)?
         if ( events & wxSOCKET_CONNECTION_FLAG )
         {
@@ -1289,34 +1313,6 @@ wxSocketBase::DoWait(long seconds, long milliseconds, wxSocketEventFlags flags)
             gotEvent = true;
             break;
         }
-
-        // Connection lost
-        if ( events & wxSOCKET_LOST_FLAG )
-        {
-            m_connected = false;
-            m_establishing = false;
-            if ( flags & wxSOCKET_LOST_FLAG )
-                gotEvent = true;
-            break;
-        }
-
-        if ( m_interrupt )
-            break;
-
-        // Wait more?
-        const wxMilliClock_t timeNow = wxGetLocalTimeMillis();
-        if ( timeNow >= timeEnd )
-            break;
-
-#if wxUSE_THREADS
-        // no event loop or waiting in another thread
-        if ( !eventLoop )
-        {
-            // We're busy waiting but at least give up the rest of our current
-            // time slice.
-            wxThread::Yield();
-        }
-#endif // wxUSE_THREADS
     }
 
     return gotEvent;
@@ -1467,37 +1463,6 @@ void wxSocketBase::SetFlags(wxSocketFlags flags)
 
 void wxSocketBase::OnRequest(wxSocketNotify notification)
 {
-    switch ( notification )
-    {
-        case wxSOCKET_CONNECTION:
-            m_establishing = false;
-            m_connected = true;
-            break;
-
-            // If we are in the middle of a R/W operation, do not
-            // propagate events to users. Also, filter 'late' events
-            // which are no longer valid.
-
-        case wxSOCKET_INPUT:
-            if (m_reading || !m_impl->Select(wxSOCKET_INPUT_FLAG))
-                return;
-            break;
-
-        case wxSOCKET_OUTPUT:
-            if (m_writing || !m_impl->Select(wxSOCKET_OUTPUT_FLAG))
-                return;
-            break;
-
-        case wxSOCKET_LOST:
-            m_connected = false;
-            m_establishing = false;
-            break;
-
-        case wxSOCKET_MAX_EVENT:
-            wxFAIL_MSG( "unexpected notification" );
-            return;
-    }
-
     wxSocketEventFlags flag = 0;
     switch ( notification )
     {
@@ -1528,6 +1493,19 @@ void wxSocketBase::OnRequest(wxSocketNotify notification)
     // send the wx event if enabled and we're interested in it
     if ( m_notify && (m_eventmask & flag) && m_handler )
     {
+        // If we are in the middle of a R/W operation, do not propagate events
+        // to users. Also, filter 'late' events which are no longer valid.
+        if ( notification == wxSOCKET_INPUT )
+        {
+            if ( m_reading || !m_impl->Select(wxSOCKET_INPUT_FLAG) )
+                return;
+        }
+        else if ( notification == wxSOCKET_OUTPUT )
+        {
+            if ( m_writing || !m_impl->Select(wxSOCKET_OUTPUT_FLAG) )
+                return;
+        }
+
         wxSocketEvent event(m_id);
         event.m_event      = notification;
         event.m_clientData = m_clientData;