diff --git a/pvAccessApp/remote/blockingTCP.h b/pvAccessApp/remote/blockingTCP.h index 60a66ea..5dc4163 100644 --- a/pvAccessApp/remote/blockingTCP.h +++ b/pvAccessApp/remote/blockingTCP.h @@ -39,29 +39,6 @@ using epics::pvData::int64; namespace epics { namespace pvAccess { -struct null_deleter -{ - void operator()(void const *) const {} -}; - -// standard performance on set/clear, use of tr1::shared_ptr lock-free counter for get -// alternative is to use boost::atomic -class AtomicBoolean -{ - public: - AtomicBoolean() : counter(static_cast(0), null_deleter()) {}; - - void set() { mutex.lock(); setp = counter; mutex.unlock(); } - void clear() { mutex.lock(); setp.reset(); mutex.unlock(); } - - bool get() const { return counter.use_count() == 2; } - private: - std::tr1::shared_ptr counter; - std::tr1::shared_ptr setp; - epics::pvData::Mutex mutex; -}; - - //class MonitorSender; enum ReceiveStage { diff --git a/pvAccessApp/remote/blockingUDP.h b/pvAccessApp/remote/blockingUDP.h index ac9a58f..1f368b2 100644 --- a/pvAccessApp/remote/blockingUDP.h +++ b/pvAccessApp/remote/blockingUDP.h @@ -54,8 +54,7 @@ namespace epics { virtual ~BlockingUDPTransport(); virtual bool isClosed() { - epics::pvData::Lock guard(_mutex); - return _closed; + return _closed.get(); } virtual const osiSockAddr* getRemoteAddress() const { @@ -210,7 +209,7 @@ namespace epics { } protected: - bool _closed; + AtomicBoolean _closed; /** * Response handler. diff --git a/pvAccessApp/remote/blockingUDPTransport.cpp b/pvAccessApp/remote/blockingUDPTransport.cpp index 9512831..be6a98d 100644 --- a/pvAccessApp/remote/blockingUDPTransport.cpp +++ b/pvAccessApp/remote/blockingUDPTransport.cpp @@ -44,7 +44,7 @@ namespace epics { auto_ptr& responseHandler, SOCKET channel, osiSockAddr& bindAddress, short remoteTransportRevision) : - _closed(false), + _closed(), _responseHandler(responseHandler), _channel(channel), _bindAddress(bindAddress), @@ -108,8 +108,8 @@ namespace epics { void BlockingUDPTransport::close(bool forced, bool waitForThreadToComplete) { { Lock guard(_mutex); - if(_closed) return; - _closed = true; + if(_closed.get()) return; + _closed.set(); LOG(logLevelDebug, "UDP socket %s closed.", @@ -178,14 +178,8 @@ namespace epics { try { - while(true) + while(!_closed.get()) { - _mutex.lock(); - bool closed = _closed; - _mutex.unlock(); - if (unlikely(closed)) - break; - // we poll to prevent blocking indefinitely // data ready to be read @@ -237,10 +231,7 @@ namespace epics { continue; // log a 'recvfrom' error - _mutex.lock(); - closed = _closed; - _mutex.unlock(); - if(!closed) + if(!_closed.get()) { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); diff --git a/pvAccessApp/remote/remote.h b/pvAccessApp/remote/remote.h index ac3b8ce..830bd56 100644 --- a/pvAccessApp/remote/remote.h +++ b/pvAccessApp/remote/remote.h @@ -596,6 +596,28 @@ namespace epics { }; + struct AtomicBoolean_null_deleter + { + void operator()(void const *) const {} + }; + + // standard performance on set/clear, use of tr1::shared_ptr lock-free counter for get + // alternative is to use boost::atomic + class AtomicBoolean + { + public: + AtomicBoolean() : counter(static_cast(0), AtomicBoolean_null_deleter()) {}; + + void set() { mutex.lock(); setp = counter; mutex.unlock(); } + void clear() { mutex.lock(); setp.reset(); mutex.unlock(); } + + bool get() const { return counter.use_count() == 2; } + private: + std::tr1::shared_ptr counter; + std::tr1::shared_ptr setp; + epics::pvData::Mutex mutex; + }; + } } diff --git a/testApp/utils/Makefile b/testApp/utils/Makefile index 96f2e5c..22f8291 100644 --- a/testApp/utils/Makefile +++ b/testApp/utils/Makefile @@ -7,6 +7,7 @@ PROD_HOST += testUtils testUtils_SRCS += hexDumpTest.cpp testUtils_SRCS += wildcharMatcherTest.cpp testUtils_SRCS += inetAddressUtilsTest.cpp +testUtils_SRCS += atomicBooleanTest.cpp testUtils_LIBS += pvAccess pvData Com gtest_main endif diff --git a/testApp/utils/atomicBooleanTest.cpp b/testApp/utils/atomicBooleanTest.cpp new file mode 100644 index 0000000..3cde575 --- /dev/null +++ b/testApp/utils/atomicBooleanTest.cpp @@ -0,0 +1,16 @@ +#include + +#include + +using namespace epics::pvAccess; + +TEST(atomicBooleanTest, atomicBoolean) +{ + AtomicBoolean ab; + + EXPECT_FALSE(ab.get()); + ab.set(); + EXPECT_TRUE(ab.get()); + ab.clear(); + EXPECT_FALSE(ab.get()); +}