diff --git a/Net/include/Poco/Net/Socket.h b/Net/include/Poco/Net/Socket.h index 405c95600..868f04b8c 100644 --- a/Net/include/Poco/Net/Socket.h +++ b/Net/include/Poco/Net/Socket.h @@ -1,7 +1,7 @@ // // Socket.h // -// $Id: //poco/svn/Net/include/Poco/Net/Socket.h#3 $ +// $Id: //poco/1.3/Net/include/Poco/Net/Socket.h#3 $ // // Library: Net // Package: Sockets @@ -129,6 +129,10 @@ public: /// * readList contains those sockets ready for reading, /// * writeList contains those sockets ready for writing, /// * exceptList contains those sockets with a pending error. + /// + /// If the total number of sockets passed in readList, writeList and + /// exceptList is zero, select() will return immediately and the + /// return value will be 0. bool poll(const Poco::Timespan& timeout, int mode) const; /// Determines the status of the socket, using a diff --git a/Net/include/Poco/Net/SocketNotification.h b/Net/include/Poco/Net/SocketNotification.h index 055b89af6..2372b9050 100644 --- a/Net/include/Poco/Net/SocketNotification.h +++ b/Net/include/Poco/Net/SocketNotification.h @@ -1,7 +1,7 @@ // // SocketNotification.h // -// $Id: //poco/svn/Net/include/Poco/Net/SocketNotification.h#2 $ +// $Id: //poco/1.3/Net/include/Poco/Net/SocketNotification.h#2 $ // // Library: Net // Package: Reactor @@ -128,6 +128,19 @@ public: }; +class Net_API IdleNotification: public SocketNotification + /// This notification is sent when the SocketReactor does + /// not have any sockets to react to. +{ +public: + IdleNotification(SocketReactor* pReactor); + /// Creates the IdleNotification for the given SocketReactor. + + ~IdleNotification(); + /// Destroys the IdleNotification. +}; + + class Net_API ShutdownNotification: public SocketNotification /// This notification is sent when the SocketReactor is /// about to shut down. diff --git a/Net/include/Poco/Net/SocketReactor.h b/Net/include/Poco/Net/SocketReactor.h index 2d7112542..7005250dc 100644 --- a/Net/include/Poco/Net/SocketReactor.h +++ b/Net/include/Poco/Net/SocketReactor.h @@ -1,7 +1,7 @@ // // SocketReactor.h // -// $Id: //poco/svn/Net/include/Poco/Net/SocketReactor.h#2 $ +// $Id: //poco/1.3/Net/include/Poco/Net/SocketReactor.h#2 $ // // Library: Net // Package: Reactor @@ -90,7 +90,8 @@ class Net_API SocketReactor: public Poco::Runnable /// If an event is detected, the corresponding event handler /// is invoked. There are five event types (and corresponding /// notification classes) defined: ReadableNotification, WritableNotification, - /// ErrorNotification, TimeoutNotification and ShutdownNotification. + /// ErrorNotification, TimeoutNotification, IdleNotification and + /// ShutdownNotification. /// /// The ReadableNotification will be dispatched if a socket becomes /// readable. The WritableNotification will be dispatched if a socket @@ -100,9 +101,17 @@ class Net_API SocketReactor: public Poco::Runnable /// If the timeout expires and no event has occured, a /// TimeoutNotification will be dispatched to all event handlers /// registered for it. This is done in the onTimeout() method - /// which can be overridded by subclasses to perform custom + /// which can be overridden by subclasses to perform custom /// timeout processing. /// + /// If there are no sockets for the SocketReactor to pass to + /// Socket::select(), an IdleNotification will be dispatched to + /// all event handlers registered for it. This is done in the + /// onIdle() method which can be overridden by subclasses + /// to perform custom idle processing. Since onIdle() will be + /// called repeatedly in a loop, it is recommended to do a + /// short sleep or yield in the event handler. + /// /// Finally, when the SocketReactor is about to shut down (as a result /// of stop() being called), it dispatches a ShutdownNotification /// to all event handlers. This is done in the onShutdown() method @@ -174,6 +183,13 @@ protected: /// Can be overridden by subclasses. The default implementation /// dispatches the TimeoutNotification and thus should be called by overriding /// implementations. + + virtual void onIdle(); + /// Called if no sockets are available to call select() on. + /// + /// Can be overridden by subclasses. The default implementation + /// dispatches the IdleNotification and thus should be called by overriding + /// implementations. virtual void onShutdown(); /// Called when the SocketReactor is about to terminate. @@ -208,6 +224,7 @@ private: NotificationPtr _pWritableNotification; NotificationPtr _pErrorNotification; NotificationPtr _pTimeoutNotification; + NotificationPtr _pIdleNotification; NotificationPtr _pShutdownNotification; Poco::FastMutex _mutex; diff --git a/Net/src/Socket.cpp b/Net/src/Socket.cpp index fa42ab4ca..995068231 100644 --- a/Net/src/Socket.cpp +++ b/Net/src/Socket.cpp @@ -1,7 +1,7 @@ // // Socket.cpp // -// $Id: //poco/svn/Net/src/Socket.cpp#2 $ +// $Id: //poco/1.3/Net/src/Socket.cpp#4 $ // // Library: Net // Package: Sockets @@ -112,6 +112,7 @@ int Socket::select(SocketList& readList, SocketList& writeList, SocketList& exce nfd = int(it->sockfd()); FD_SET(it->sockfd(), &fdExcept); } + if (nfd == 0) return 0; Poco::Timespan remainingTime(timeout); int rc; do diff --git a/Net/src/SocketNotification.cpp b/Net/src/SocketNotification.cpp index 4f51dfb4f..706831fd8 100644 --- a/Net/src/SocketNotification.cpp +++ b/Net/src/SocketNotification.cpp @@ -1,7 +1,7 @@ // // SocketNotification.cpp // -// $Id: //poco/svn/Net/src/SocketNotification.cpp#2 $ +// $Id: //poco/1.3/Net/src/SocketNotification.cpp#2 $ // // Library: Net // Package: Reactor @@ -102,6 +102,17 @@ TimeoutNotification::~TimeoutNotification() } +IdleNotification::IdleNotification(SocketReactor* pReactor): + SocketNotification(pReactor) +{ +} + + +IdleNotification::~IdleNotification() +{ +} + + ShutdownNotification::ShutdownNotification(SocketReactor* pReactor): SocketNotification(pReactor) { diff --git a/Net/src/SocketReactor.cpp b/Net/src/SocketReactor.cpp index e920ff083..c07354994 100644 --- a/Net/src/SocketReactor.cpp +++ b/Net/src/SocketReactor.cpp @@ -1,7 +1,7 @@ // // SocketReactor.cpp // -// $Id: //poco/svn/Net/src/SocketReactor.cpp#2 $ +// $Id: //poco/1.3/Net/src/SocketReactor.cpp#2 $ // // Library: Net // Package: Reactor @@ -38,6 +38,7 @@ #include "Poco/Net/SocketNotification.h" #include "Poco/Net/SocketNotifier.h" #include "Poco/ErrorHandler.h" +#include "Poco/Thread.h" #include "Poco/Exception.h" @@ -57,6 +58,7 @@ SocketReactor::SocketReactor(): _pWritableNotification(new WritableNotification(this)), _pErrorNotification(new ErrorNotification(this)), _pTimeoutNotification(new TimeoutNotification(this)), + _pIdleNotification(new IdleNotification(this)), _pShutdownNotification(new ShutdownNotification(this)) { } @@ -69,6 +71,7 @@ SocketReactor::SocketReactor(const Poco::Timespan& timeout): _pWritableNotification(new WritableNotification(this)), _pErrorNotification(new ErrorNotification(this)), _pTimeoutNotification(new TimeoutNotification(this)), + _pIdleNotification(new IdleNotification(this)), _pShutdownNotification(new ShutdownNotification(this)) { } @@ -87,31 +90,60 @@ void SocketReactor::run() while (!_stop) { - readable.clear(); - writable.clear(); - except.clear(); + try { - FastMutex::ScopedLock lock(_mutex); - for (EventHandlerMap::iterator it = _handlers.begin(); it != _handlers.end(); ++it) + readable.clear(); + writable.clear(); + except.clear(); + int nSockets = 0; { - if (it->second->accepts(_pReadableNotification)) - readable.push_back(it->first); - if (it->second->accepts(_pWritableNotification)) - writable.push_back(it->first); - if (it->second->accepts(_pErrorNotification)) - except.push_back(it->first); + FastMutex::ScopedLock lock(_mutex); + for (EventHandlerMap::iterator it = _handlers.begin(); it != _handlers.end(); ++it) + { + if (it->second->accepts(_pReadableNotification)) + { + readable.push_back(it->first); + nSockets++; + } + if (it->second->accepts(_pWritableNotification)) + { + writable.push_back(it->first); + nSockets++; + } + if (it->second->accepts(_pErrorNotification)) + { + except.push_back(it->first); + nSockets++; + } + } } + if (nSockets == 0) + { + onIdle(); + } + else if (Socket::select(readable, writable, except, _timeout)) + { + for (Socket::SocketList::iterator it = readable.begin(); it != readable.end(); ++it) + dispatch(*it, _pReadableNotification); + for (Socket::SocketList::iterator it = writable.begin(); it != writable.end(); ++it) + dispatch(*it, _pWritableNotification); + for (Socket::SocketList::iterator it = except.begin(); it != except.end(); ++it) + dispatch(*it, _pErrorNotification); + } + else onTimeout(); } - if (Socket::select(readable, writable, except, _timeout)) + catch (Exception& exc) { - for (Socket::SocketList::iterator it = readable.begin(); it != readable.end(); ++it) - dispatch(*it, _pReadableNotification); - for (Socket::SocketList::iterator it = writable.begin(); it != writable.end(); ++it) - dispatch(*it, _pWritableNotification); - for (Socket::SocketList::iterator it = except.begin(); it != except.end(); ++it) - dispatch(*it, _pErrorNotification); + ErrorHandler::handle(exc); + } + catch (std::exception& exc) + { + ErrorHandler::handle(exc); + } + catch (...) + { + ErrorHandler::handle(); } - else onTimeout(); } onShutdown(); } @@ -172,6 +204,12 @@ void SocketReactor::onTimeout() } +void SocketReactor::onIdle() +{ + dispatch(_pIdleNotification); +} + + void SocketReactor::onShutdown() { dispatch(_pShutdownNotification); diff --git a/Net/testsuite/src/SocketTest.cpp b/Net/testsuite/src/SocketTest.cpp index d39cd0d02..7795c6940 100644 --- a/Net/testsuite/src/SocketTest.cpp +++ b/Net/testsuite/src/SocketTest.cpp @@ -1,7 +1,7 @@ // // SocketTest.cpp // -// $Id: //poco/svn/Net/testsuite/src/SocketTest.cpp#2 $ +// $Id: //poco/1.3/Net/testsuite/src/SocketTest.cpp#2 $ // // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. // and Contributors. @@ -425,6 +425,18 @@ void SocketTest::testSelect2() } +void SocketTest::testSelect3() +{ + Socket::SocketList readList; + Socket::SocketList writeList; + Socket::SocketList exceptList; + Timespan timeout(1000); + + int rc = Socket::select(readList, writeList, exceptList, timeout); + assert (rc == 0); +} + + void SocketTest::setUp() { } @@ -452,6 +464,7 @@ CppUnit::Test* SocketTest::suite() CppUnit_addTest(pSuite, SocketTest, testOptions); CppUnit_addTest(pSuite, SocketTest, testSelect); CppUnit_addTest(pSuite, SocketTest, testSelect2); + CppUnit_addTest(pSuite, SocketTest, testSelect3); return pSuite; } diff --git a/Net/testsuite/src/SocketTest.h b/Net/testsuite/src/SocketTest.h index 0e5917643..d9eb733c9 100644 --- a/Net/testsuite/src/SocketTest.h +++ b/Net/testsuite/src/SocketTest.h @@ -1,7 +1,7 @@ // // SocketTest.h // -// $Id: //poco/svn/Net/testsuite/src/SocketTest.h#2 $ +// $Id: //poco/1.3/Net/testsuite/src/SocketTest.h#2 $ // // Definition of the SocketTest class. // @@ -59,6 +59,7 @@ public: void testOptions(); void testSelect(); void testSelect2(); + void testSelect3(); void setUp(); void tearDown();