From fa21fc3bd5c5824624dc5a8d1658b25c1109e84d Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Fri, 12 Aug 2011 10:22:38 +0200 Subject: [PATCH] UDP shutdown fixed --- pvAccessApp/remote/blockingUDP.h | 2 - pvAccessApp/remote/blockingUDPTransport.cpp | 62 +++++++++------------ testApp/client/testStartStop.cpp | 14 +++++ 3 files changed, 40 insertions(+), 38 deletions(-) create mode 100644 testApp/client/testStartStop.cpp diff --git a/pvAccessApp/remote/blockingUDP.h b/pvAccessApp/remote/blockingUDP.h index ddcf571..1aa68a0 100644 --- a/pvAccessApp/remote/blockingUDP.h +++ b/pvAccessApp/remote/blockingUDP.h @@ -211,8 +211,6 @@ namespace epics { virtual void processRead(); - void wakeupMessage(); - private: static void threadRunner(void* param); diff --git a/pvAccessApp/remote/blockingUDPTransport.cpp b/pvAccessApp/remote/blockingUDPTransport.cpp index c5f2df9..385cc82 100644 --- a/pvAccessApp/remote/blockingUDPTransport.cpp +++ b/pvAccessApp/remote/blockingUDPTransport.cpp @@ -52,23 +52,19 @@ namespace epics { _threadId(0) { PVDATA_REFCOUNT_MONITOR_CONSTRUCT(blockingUDPTransport); - - /* - osiSockAddr tmpAddr; - osiSocklen_t saddr_length = sizeof (tmpAddr); - int status = ::getsockname(_channel, &tmpAddr.sa, &saddr_length); - if (status < 0) + + // set receive timeout so that we do not have problems at shutdown (recvfrom would block) + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + if (setsockopt (_channel, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) { - char strBuffer[64]; - epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); - errlogSevPrintf(errlogMinor, "getsockname error: %s", strBuffer); + errlogSevPrintf(errlogMajor, + "Failed to set SO_RCVTIMEO for UDP socket %s: %s.", + inetAddressToString(_bindAddress).c_str(), strerror(errno)); } - else - { - int localPort = ntohs(tmpAddr.ia.sin_port); - } - */ - //errlogSevPrintf(errlogInfo, "UDP bind adrr port: %d", ntohs(_bindAddress.ia.sin_port)); + } @@ -105,9 +101,6 @@ namespace epics { if(_closed) return; _closed = true; - // to get out of blocking receive - wakeupMessage(); - errlogSevPrintf(errlogInfo, "UDP socket %s closed.", inetAddressToString(_bindAddress).c_str()); @@ -118,7 +111,14 @@ namespace epics { // wait for send thread to exit cleanly if (waitForThreadToComplete) - _shutdownEvent.wait(); + { + if (!_shutdownEvent.wait(5.0)) + { + errlogSevPrintf(errlogMajor, + "Receive thread for UDP socket %s has not exited.", + inetAddressToString(_bindAddress).c_str()); + } + } } void BlockingUDPTransport::enqueueSendRequest(TransportSender::shared_pointer const & sender) { @@ -212,10 +212,14 @@ namespace epics { processBuffer(thisTransport, fromAddress, _receiveBuffer); } } - else { - // 0 == socket remotely closed + else if (bytesRead == -1) { + + // timeout + if (errno == EAGAIN || errno == EWOULDBLOCK) + continue; + // log a 'recvfrom' error - if(!_closed && bytesRead==-1) + if(!_closed) errlogSevPrintf(errlogMajor, "Socket recv error: %s", strerror(errno)); close(true, false); @@ -287,20 +291,6 @@ namespace epics { return true; } - - void BlockingUDPTransport::wakeupMessage() - { - osiSockAddr addr; - addr.ia.sin_family = AF_INET; - addr.ia.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr.ia.sin_port = _bindAddress.ia.sin_port; - - // send a wakeup msg so the UDP recv thread will exit - sendto(_channel, static_cast(0), - 0, 0, &addr.sa, sizeof(addr.sa )); - } - - bool BlockingUDPTransport::send(ByteBuffer* buffer) { if(!_sendAddresses) return false; diff --git a/testApp/client/testStartStop.cpp b/testApp/client/testStartStop.cpp new file mode 100644 index 0000000..25cf027 --- /dev/null +++ b/testApp/client/testStartStop.cpp @@ -0,0 +1,14 @@ +#include +#include + +int main(int argc, char *argv[]) { + std::cout << "to start pvAccess ClientFactory" << std::endl; + ::epics::pvAccess::ClientFactory::start(); + std::cout << "do nothing after starting pvAccess ClientFactory" << std::endl; + + std::cout << "to stop pvAccess ClientFactory" << std::endl; + ::epics::pvAccess::ClientFactory::stop(); + std::cout << "finish test" << std::endl; + return 0; + +}