use DispatchTimeout() and/or select() with timeout instead of polling loop in wxSocket::DoWait()
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@57572 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -255,7 +255,14 @@ public:
|
|||||||
virtual int Read(void *buffer, int size) = 0;
|
virtual int Read(void *buffer, int size) = 0;
|
||||||
virtual int Write(const 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;
|
virtual wxSocketImpl *WaitConnection(wxSocketBase& wxsocket) = 0;
|
||||||
|
|
||||||
|
@@ -69,6 +69,21 @@ IMPLEMENT_CLASS(wxSocketClient, wxSocketBase)
|
|||||||
IMPLEMENT_CLASS(wxDatagramSocket, wxSocketBase)
|
IMPLEMENT_CLASS(wxDatagramSocket, wxSocketBase)
|
||||||
IMPLEMENT_DYNAMIC_CLASS(wxSocketEvent, wxEvent)
|
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
|
// private classes
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
@@ -390,8 +405,7 @@ void wxSocketImpl::Shutdown()
|
|||||||
*/
|
*/
|
||||||
void wxSocketImpl::SetTimeout(unsigned long millis)
|
void wxSocketImpl::SetTimeout(unsigned long millis)
|
||||||
{
|
{
|
||||||
m_timeout.tv_sec = (millis / 1000);
|
SetTimeValFromMS(m_timeout, millis);
|
||||||
m_timeout.tv_usec = (millis % 1000) * 1000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxSocketImpl::NotifyOnStateChange(wxSocketNotify event)
|
void wxSocketImpl::NotifyOnStateChange(wxSocketNotify event)
|
||||||
@@ -1106,29 +1120,23 @@ wxSocketBase& wxSocketBase::Discard()
|
|||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Polls the socket to determine its status. This function will
|
This function will check for the events specified in the flags parameter,
|
||||||
* check for the events specified in the 'flags' parameter, and
|
and it will return a mask indicating which operations can be performed.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
wxSocketEventFlags wxSocketImpl::Select(wxSocketEventFlags flags)
|
wxSocketEventFlags wxSocketImpl::Select(wxSocketEventFlags flags,
|
||||||
|
unsigned long timeout)
|
||||||
{
|
{
|
||||||
assert(this);
|
|
||||||
|
|
||||||
wxSocketEventFlags result = 0;
|
wxSocketEventFlags result = 0;
|
||||||
fd_set readfds;
|
|
||||||
fd_set writefds;
|
|
||||||
fd_set exceptfds;
|
|
||||||
struct timeval tv;
|
|
||||||
|
|
||||||
if (m_fd == INVALID_SOCKET)
|
if (m_fd == INVALID_SOCKET)
|
||||||
return (wxSOCKET_LOST_FLAG & flags);
|
return (wxSOCKET_LOST_FLAG & flags);
|
||||||
|
|
||||||
/* Do not use a static struct, Linux can garble it */
|
struct timeval tv;
|
||||||
tv.tv_sec = 0;
|
SetTimeValFromMS(tv, timeout);
|
||||||
tv.tv_usec = 0;
|
|
||||||
|
|
||||||
|
fd_set readfds;
|
||||||
|
fd_set writefds;
|
||||||
|
fd_set exceptfds;
|
||||||
wxFD_ZERO(&readfds);
|
wxFD_ZERO(&readfds);
|
||||||
wxFD_ZERO(&writefds);
|
wxFD_ZERO(&writefds);
|
||||||
wxFD_ZERO(&exceptfds);
|
wxFD_ZERO(&exceptfds);
|
||||||
@@ -1211,12 +1219,6 @@ wxSocketEventFlags wxSocketImpl::Select(wxSocketEventFlags flags)
|
|||||||
return (result | m_detected) & 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
|
bool
|
||||||
wxSocketBase::DoWait(long seconds, long milliseconds, wxSocketEventFlags flags)
|
wxSocketBase::DoWait(long seconds, long milliseconds, wxSocketEventFlags flags)
|
||||||
{
|
{
|
||||||
@@ -1247,33 +1249,55 @@ wxSocketBase::DoWait(long seconds, long milliseconds, wxSocketEventFlags flags)
|
|||||||
eventLoop = NULL;
|
eventLoop = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset them before starting to wait
|
// Wait until we receive the event we're waiting for or the timeout expires
|
||||||
m_eventsgot = 0;
|
// (but note that we always execute the loop at least once, even if timeout
|
||||||
|
// is 0 as this is used for polling)
|
||||||
// Wait in an active polling loop: notice that the loop is executed at
|
|
||||||
// least once, even if timeout is 0 (i.e. polling).
|
|
||||||
bool gotEvent = false;
|
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;
|
wxSocketEventFlags events;
|
||||||
if ( eventLoop )
|
if ( eventLoop )
|
||||||
{
|
{
|
||||||
// This function is only called if wxSOCKET_BLOCK flag was not used
|
// reset them before starting to wait
|
||||||
// and so we should dispatch the events if there is an event loop
|
m_eventsgot = 0;
|
||||||
// capable of doing it.
|
|
||||||
if ( eventLoop->Pending() )
|
eventLoop->DispatchTimeout(timeLeft);
|
||||||
eventLoop->Dispatch();
|
|
||||||
|
|
||||||
events = m_eventsgot;
|
events = m_eventsgot;
|
||||||
}
|
}
|
||||||
else
|
else // no event loop or waiting in another thread
|
||||||
{
|
{
|
||||||
// We always stop waiting when the connection is lost as it doesn't
|
// as explained below, we should always check for wxSOCKET_LOST_FLAG
|
||||||
// make sense to continue further, even if wxSOCKET_LOST_FLAG is
|
events = m_impl->Select(flags | wxSOCKET_LOST_FLAG, timeLeft);
|
||||||
// not specified in flags to wait for.
|
|
||||||
events = m_impl->Select(flags | wxSOCKET_LOST_FLAG);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 )
|
||||||
|
{
|
||||||
|
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)?
|
// Incoming connection (server) or connection established (client)?
|
||||||
if ( events & wxSOCKET_CONNECTION_FLAG )
|
if ( events & wxSOCKET_CONNECTION_FLAG )
|
||||||
{
|
{
|
||||||
@@ -1289,34 +1313,6 @@ wxSocketBase::DoWait(long seconds, long milliseconds, wxSocketEventFlags flags)
|
|||||||
gotEvent = true;
|
gotEvent = true;
|
||||||
break;
|
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;
|
return gotEvent;
|
||||||
@@ -1467,37 +1463,6 @@ void wxSocketBase::SetFlags(wxSocketFlags flags)
|
|||||||
|
|
||||||
void wxSocketBase::OnRequest(wxSocketNotify notification)
|
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;
|
wxSocketEventFlags flag = 0;
|
||||||
switch ( notification )
|
switch ( notification )
|
||||||
{
|
{
|
||||||
@@ -1528,6 +1493,19 @@ void wxSocketBase::OnRequest(wxSocketNotify notification)
|
|||||||
// send the wx event if enabled and we're interested in it
|
// send the wx event if enabled and we're interested in it
|
||||||
if ( m_notify && (m_eventmask & flag) && m_handler )
|
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);
|
wxSocketEvent event(m_id);
|
||||||
event.m_event = notification;
|
event.m_event = notification;
|
||||||
event.m_clientData = m_clientData;
|
event.m_clientData = m_clientData;
|
||||||
|
Reference in New Issue
Block a user