lib/nfs/Connection: detect libnfs reconnect

When rpc_reconnect_requeue() gets called from inside nfs_service(),
the NfsInputStream can stall completely because the old socket has
been unregistered from epoll automatically, but the new one has never
been registered.  Therefore, nfs_service() will never be called again.

This kludge attempts to detect this condition by checking
nfs_which_events()==POLLOUT.

https://bugs.musicpd.org/view.php?id=4081
This commit is contained in:
Max Kellermann 2017-02-01 21:16:50 +01:00
parent 38d263ac19
commit 05eac20ffe
2 changed files with 14 additions and 1 deletions

2
NEWS
View File

@ -1,4 +1,6 @@
ver 0.20.4 (not yet released) ver 0.20.4 (not yet released)
* input
- nfs: fix freeze after reconnect
* output * output
- sndio: work around a libroar C++ incompatibility - sndio: work around a libroar C++ incompatibility
* workaround for GCC 4.9 "constexpr" bug * workaround for GCC 4.9 "constexpr" bug

View File

@ -396,6 +396,17 @@ NfsConnection::ScheduleSocket()
assert(GetEventLoop().IsInside()); assert(GetEventLoop().IsInside());
assert(context != nullptr); assert(context != nullptr);
const int which_events = nfs_which_events(context);
if (which_events == POLLOUT && SocketMonitor::IsDefined())
/* kludge: if libnfs asks only for POLLOUT, it means
that it is currently waiting for the connect() to
finish - rpc_reconnect_requeue() may have been
called from inside nfs_service(); we must now
unregister the old socket and register the new one
instead */
SocketMonitor::Steal();
if (!SocketMonitor::IsDefined()) { if (!SocketMonitor::IsDefined()) {
int _fd = nfs_get_fd(context); int _fd = nfs_get_fd(context);
if (_fd < 0) if (_fd < 0)
@ -405,7 +416,7 @@ NfsConnection::ScheduleSocket()
SocketMonitor::Open(_fd); SocketMonitor::Open(_fd);
} }
SocketMonitor::Schedule(libnfs_to_events(nfs_which_events(context))); SocketMonitor::Schedule(libnfs_to_events(which_events));
} }
inline int inline int