Merge branch 'sock-event-fix'
Fix unwanted (and sometimes fatal) socket events for blocking sockets under Unix. See https://github.com/wxWidgets/wxWidgets/pull/1658
This commit is contained in:
@@ -57,10 +57,7 @@ public:
|
|||||||
// anything here
|
// anything here
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
virtual void UpdateBlockingState() wxOVERRIDE
|
||||||
virtual void DoClose() wxOVERRIDE;
|
|
||||||
|
|
||||||
virtual void UnblockAndRegisterWithEventLoop() wxOVERRIDE
|
|
||||||
{
|
{
|
||||||
if ( GetSocketFlags() & wxSOCKET_BLOCK )
|
if ( GetSocketFlags() & wxSOCKET_BLOCK )
|
||||||
{
|
{
|
||||||
@@ -74,6 +71,9 @@ private:
|
|||||||
// would result in data races and other unpleasantness.
|
// would result in data races and other unpleasantness.
|
||||||
wxIoctlSocketArg_t trueArg = 1;
|
wxIoctlSocketArg_t trueArg = 1;
|
||||||
ioctlsocket(m_fd, FIONBIO, &trueArg);
|
ioctlsocket(m_fd, FIONBIO, &trueArg);
|
||||||
|
|
||||||
|
// Uninstall it in case it was installed before.
|
||||||
|
wxSocketManager::Get()->Uninstall_Callback(this);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -83,6 +83,9 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void DoClose() wxOVERRIDE;
|
||||||
|
|
||||||
int m_msgnumber;
|
int m_msgnumber;
|
||||||
|
|
||||||
friend class wxSocketMSWManager;
|
friend class wxSocketMSWManager;
|
||||||
|
@@ -281,6 +281,12 @@ public:
|
|||||||
// notifications
|
// notifications
|
||||||
// -------------
|
// -------------
|
||||||
|
|
||||||
|
// Update the socket depending on the presence or absence of wxSOCKET_BLOCK
|
||||||
|
// in GetSocketFlags(): if it's present, make the socket blocking and
|
||||||
|
// ensure that we don't get any asynchronous event for it, otherwise put
|
||||||
|
// it into non-blocking mode and enable monitoring it in the event loop.
|
||||||
|
virtual void UpdateBlockingState() = 0;
|
||||||
|
|
||||||
// notify m_wxsocket about the given socket event by calling its (inaptly
|
// notify m_wxsocket about the given socket event by calling its (inaptly
|
||||||
// named) OnRequest() method
|
// named) OnRequest() method
|
||||||
void NotifyOnStateChange(wxSocketNotify event);
|
void NotifyOnStateChange(wxSocketNotify event);
|
||||||
@@ -323,10 +329,6 @@ private:
|
|||||||
// called by Close() if we have a valid m_fd
|
// called by Close() if we have a valid m_fd
|
||||||
virtual void DoClose() = 0;
|
virtual void DoClose() = 0;
|
||||||
|
|
||||||
// put this socket into non-blocking mode and enable monitoring this socket
|
|
||||||
// as part of the event loop
|
|
||||||
virtual void UnblockAndRegisterWithEventLoop() = 0;
|
|
||||||
|
|
||||||
// check that the socket wasn't created yet and that the given address
|
// check that the socket wasn't created yet and that the given address
|
||||||
// (either m_local or m_peer depending on the socket kind) is valid and
|
// (either m_local or m_peer depending on the socket kind) is valid and
|
||||||
// set m_error and return false if this is not the case
|
// set m_error and return false if this is not the case
|
||||||
@@ -350,7 +352,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// apply the options to the (just created) socket and register it with the
|
// apply the options to the (just created) socket and register it with the
|
||||||
// event loop by calling UnblockAndRegisterWithEventLoop()
|
// event loop by calling UpdateBlockingState()
|
||||||
void PostCreation();
|
void PostCreation();
|
||||||
|
|
||||||
// update local address after binding/connecting
|
// update local address after binding/connecting
|
||||||
|
@@ -40,6 +40,10 @@ public:
|
|||||||
|
|
||||||
virtual void ReenableEvents(wxSocketEventFlags flags) wxOVERRIDE
|
virtual void ReenableEvents(wxSocketEventFlags flags) wxOVERRIDE
|
||||||
{
|
{
|
||||||
|
// Events are only ever used for non-blocking sockets.
|
||||||
|
if ( GetSocketFlags() & wxSOCKET_BLOCK )
|
||||||
|
return;
|
||||||
|
|
||||||
// enable the notifications about input/output being available again in
|
// enable the notifications about input/output being available again in
|
||||||
// case they were disabled by OnRead/WriteWaiting()
|
// case they were disabled by OnRead/WriteWaiting()
|
||||||
//
|
//
|
||||||
@@ -55,6 +59,15 @@ public:
|
|||||||
EnableEvents(flags);
|
EnableEvents(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void UpdateBlockingState() wxOVERRIDE
|
||||||
|
{
|
||||||
|
// Make this int and not bool to allow passing it to ioctl().
|
||||||
|
const int isBlocking = (GetSocketFlags() & wxSOCKET_BLOCK) != 0;
|
||||||
|
ioctl(m_fd, FIONBIO, &isBlocking);
|
||||||
|
|
||||||
|
DoEnableEvents(wxSOCKET_INPUT_FLAG | wxSOCKET_OUTPUT_FLAG, !isBlocking);
|
||||||
|
}
|
||||||
|
|
||||||
// wxFDIOHandler methods
|
// wxFDIOHandler methods
|
||||||
virtual void OnReadWaiting() wxOVERRIDE;
|
virtual void OnReadWaiting() wxOVERRIDE;
|
||||||
virtual void OnWriteWaiting() wxOVERRIDE;
|
virtual void OnWriteWaiting() wxOVERRIDE;
|
||||||
@@ -69,14 +82,6 @@ private:
|
|||||||
wxCloseSocket(m_fd);
|
wxCloseSocket(m_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void UnblockAndRegisterWithEventLoop() wxOVERRIDE
|
|
||||||
{
|
|
||||||
int trueArg = 1;
|
|
||||||
ioctl(m_fd, FIONBIO, &trueArg);
|
|
||||||
|
|
||||||
EnableEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
// enable or disable notifications for socket input/output events
|
// enable or disable notifications for socket input/output events
|
||||||
void EnableEvents(int flags = wxSOCKET_INPUT_FLAG | wxSOCKET_OUTPUT_FLAG)
|
void EnableEvents(int flags = wxSOCKET_INPUT_FLAG | wxSOCKET_OUTPUT_FLAG)
|
||||||
{ DoEnableEvents(flags, true); }
|
{ DoEnableEvents(flags, true); }
|
||||||
|
@@ -366,9 +366,9 @@ void wxSocketImpl::PostCreation()
|
|||||||
if ( m_initialSendBufferSize >= 0 )
|
if ( m_initialSendBufferSize >= 0 )
|
||||||
SetSocketOption(SO_SNDBUF, m_initialSendBufferSize);
|
SetSocketOption(SO_SNDBUF, m_initialSendBufferSize);
|
||||||
|
|
||||||
// we always put our sockets in unblocked mode and handle blocking
|
// Call this to put our socket in unblocked mode: we'll handle blocking
|
||||||
// ourselves in DoRead/Write() if wxSOCKET_WAITALL is specified
|
// ourselves in DoRead/Write() if wxSOCKET_WAITALL is specified
|
||||||
UnblockAndRegisterWithEventLoop();
|
UpdateBlockingState();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxSocketError wxSocketImpl::UpdateLocalAddress()
|
wxSocketError wxSocketImpl::UpdateLocalAddress()
|
||||||
@@ -551,7 +551,7 @@ wxSocketImpl *wxSocketImpl::Accept(wxSocketBase& wxsocket)
|
|||||||
sock->m_fd = fd;
|
sock->m_fd = fd;
|
||||||
sock->m_peer = wxSockAddressImpl(from.addr, fromlen);
|
sock->m_peer = wxSockAddressImpl(from.addr, fromlen);
|
||||||
|
|
||||||
sock->UnblockAndRegisterWithEventLoop();
|
sock->UpdateBlockingState();
|
||||||
|
|
||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
@@ -1672,7 +1672,20 @@ void wxSocketBase::SetFlags(wxSocketFlags flags)
|
|||||||
"Using wxSOCKET_WAITALL or wxSOCKET_BLOCK with "
|
"Using wxSOCKET_WAITALL or wxSOCKET_BLOCK with "
|
||||||
"wxSOCKET_NOWAIT doesn't make sense" );
|
"wxSOCKET_NOWAIT doesn't make sense" );
|
||||||
|
|
||||||
|
// Blocking sockets are very different from non-blocking ones and we need
|
||||||
|
// to [un]register the socket with the event loop if wxSOCKET_BLOCK is
|
||||||
|
// being [un]set.
|
||||||
|
const bool
|
||||||
|
blockChanged = (m_flags & wxSOCKET_BLOCK) != (flags & wxSOCKET_BLOCK);
|
||||||
|
|
||||||
m_flags = flags;
|
m_flags = flags;
|
||||||
|
|
||||||
|
if ( blockChanged )
|
||||||
|
{
|
||||||
|
// Of course, we only do this if we already have the actual socket.
|
||||||
|
if ( m_impl )
|
||||||
|
m_impl->UpdateBlockingState();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -90,17 +90,18 @@ wxSocketError wxSocketImplUnix::GetLastError() const
|
|||||||
|
|
||||||
void wxSocketImplUnix::DoEnableEvents(int flags, bool enable)
|
void wxSocketImplUnix::DoEnableEvents(int flags, bool enable)
|
||||||
{
|
{
|
||||||
// No events for blocking sockets, they should be usable from the other
|
|
||||||
// threads and the events only work for the sockets used by the main one.
|
|
||||||
if ( GetSocketFlags() & wxSOCKET_BLOCK )
|
|
||||||
return;
|
|
||||||
|
|
||||||
wxSocketManager * const manager = wxSocketManager::Get();
|
wxSocketManager * const manager = wxSocketManager::Get();
|
||||||
if (!manager)
|
if (!manager)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ( enable )
|
if ( enable )
|
||||||
{
|
{
|
||||||
|
// We should never try to enable events for the blocking sockets, they
|
||||||
|
// should be usable from the other threads and the events only work for
|
||||||
|
// the sockets used by the main one.
|
||||||
|
wxASSERT_MSG( !(GetSocketFlags() & wxSOCKET_BLOCK),
|
||||||
|
"enabling events for a blocking socket?" );
|
||||||
|
|
||||||
if ( flags & wxSOCKET_INPUT_FLAG )
|
if ( flags & wxSOCKET_INPUT_FLAG )
|
||||||
manager->Install_Callback(this, wxSOCKET_INPUT);
|
manager->Install_Callback(this, wxSOCKET_INPUT);
|
||||||
if ( flags & wxSOCKET_OUTPUT_FLAG )
|
if ( flags & wxSOCKET_OUTPUT_FLAG )
|
||||||
|
Reference in New Issue
Block a user