mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-15 03:21:09 +01:00
revert(SocketReactor): back to devel branch
This commit is contained in:
parent
d47db5aecc
commit
ac4f7fa8f7
@ -23,15 +23,10 @@
|
|||||||
#include "Poco/Net/PollSet.h"
|
#include "Poco/Net/PollSet.h"
|
||||||
#include "Poco/Runnable.h"
|
#include "Poco/Runnable.h"
|
||||||
#include "Poco/Timespan.h"
|
#include "Poco/Timespan.h"
|
||||||
#include "Poco/Timestamp.h"
|
|
||||||
#include "Poco/Observer.h"
|
#include "Poco/Observer.h"
|
||||||
#include "Poco/AutoPtr.h"
|
#include "Poco/AutoPtr.h"
|
||||||
#include "Poco/Mutex.h"
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <functional>
|
|
||||||
#include <deque>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco {
|
||||||
@ -119,10 +114,6 @@ class Net_API SocketReactor: public Poco::Runnable
|
|||||||
/// from event handlers.
|
/// from event handlers.
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::function<void()> CompletionHandler;
|
|
||||||
|
|
||||||
static const Timestamp::TimeDiff PERMANENT_COMPLETION_HANDLER;
|
|
||||||
|
|
||||||
SocketReactor();
|
SocketReactor();
|
||||||
/// Creates the SocketReactor.
|
/// Creates the SocketReactor.
|
||||||
|
|
||||||
@ -132,54 +123,6 @@ public:
|
|||||||
virtual ~SocketReactor();
|
virtual ~SocketReactor();
|
||||||
/// Destroys the SocketReactor.
|
/// Destroys the SocketReactor.
|
||||||
|
|
||||||
void addCompletionHandler(const CompletionHandler& ch, Timestamp::TimeDiff ms = PERMANENT_COMPLETION_HANDLER);
|
|
||||||
/// Adds a completion handler to the list of handlers
|
|
||||||
/// to be called after the next poll() completion.
|
|
||||||
/// Handler will be called until the specified expiration,
|
|
||||||
/// which defaults to immediately, ie. expiration after the
|
|
||||||
/// first invocation.
|
|
||||||
|
|
||||||
void addCompletionHandler(CompletionHandler&& ch, Timestamp::TimeDiff ms = PERMANENT_COMPLETION_HANDLER, int pos = -1);
|
|
||||||
/// Adds a completion handler to the list of handlers
|
|
||||||
/// to be called after the next poll() completion.
|
|
||||||
/// Handler will be called until the specified expiration,
|
|
||||||
/// which defaults to immediately, ie. expiration after the
|
|
||||||
/// first invocation.
|
|
||||||
|
|
||||||
void removeCompletionHandlers();
|
|
||||||
/// Removes all completion handlers.
|
|
||||||
|
|
||||||
int scheduledCompletionHandlers();
|
|
||||||
/// Returns the number of scheduled completion handlers.
|
|
||||||
|
|
||||||
int removeScheduledCompletionHandlers(int count = -1);
|
|
||||||
/// Removes the count scheduled completion handlers
|
|
||||||
/// from the front of the schedule queue.
|
|
||||||
/// Default is removal of all scheduled handlers.
|
|
||||||
|
|
||||||
int permanentCompletionHandlers();
|
|
||||||
/// Returns the number of scheduled completion handlers.
|
|
||||||
|
|
||||||
int removePermanentCompletionHandlers(int count = -1);
|
|
||||||
/// Removes the count permanent completion handlers
|
|
||||||
/// from the front of the schedule queue.
|
|
||||||
/// Default is removal of all scheduled handlers.
|
|
||||||
|
|
||||||
int poll(int* pHandled = 0);
|
|
||||||
/// Polls all registered sockets and calls their respective handlers.
|
|
||||||
/// If there are no handlers, an idle notification is dispatched.
|
|
||||||
/// If there are no readable sockets, a timeout notification is dispatched.
|
|
||||||
/// If pHandled is not null, after the call it contains the total number
|
|
||||||
/// of read/write/error socket handlers called.
|
|
||||||
/// Returns the number of completion handlers invoked.
|
|
||||||
|
|
||||||
int runOne();
|
|
||||||
/// Runs one handler, scheduled or permanent.
|
|
||||||
/// If there are no available handlers, it blocks
|
|
||||||
/// until the first handler is encountered and executed.
|
|
||||||
/// Returns 1 on successful handler invocation, 0 on
|
|
||||||
/// exception.
|
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
/// Runs the SocketReactor. The reactor will run
|
/// Runs the SocketReactor. The reactor will run
|
||||||
/// until stop() is called (in a separate thread).
|
/// until stop() is called (in a separate thread).
|
||||||
@ -256,14 +199,6 @@ protected:
|
|||||||
/// Can be overridden by subclasses to perform additional
|
/// Can be overridden by subclasses to perform additional
|
||||||
/// periodic tasks. The default implementation does nothing.
|
/// periodic tasks. The default implementation does nothing.
|
||||||
|
|
||||||
int onComplete(bool handleOne = false, bool expiredOnly = false);
|
|
||||||
/// Calls completion handler(s) (after poll() completes processing
|
|
||||||
/// or on runOne() invocation). If handleOne is true, returns
|
|
||||||
/// after first handler invocation.
|
|
||||||
/// Scheduled completion handlers are deleted after
|
|
||||||
/// invocation.
|
|
||||||
/// Returns number of handlers invoked.
|
|
||||||
|
|
||||||
void dispatch(const Socket& socket, SocketNotification* pNotification);
|
void dispatch(const Socket& socket, SocketNotification* pNotification);
|
||||||
/// Dispatches the given notification to all observers
|
/// Dispatches the given notification to all observers
|
||||||
/// registered for the given socket.
|
/// registered for the given socket.
|
||||||
@ -272,48 +207,15 @@ protected:
|
|||||||
/// Dispatches the given notification to all observers.
|
/// Dispatches the given notification to all observers.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef Poco::AutoPtr<SocketNotifier> NotifierPtr;
|
typedef Poco::AutoPtr<SocketNotifier> NotifierPtr;
|
||||||
typedef Poco::AutoPtr<SocketNotification> NotificationPtr;
|
typedef Poco::AutoPtr<SocketNotification> NotificationPtr;
|
||||||
typedef std::map<poco_socket_t, NotifierPtr> EventHandlerMap;
|
typedef std::map<poco_socket_t, NotifierPtr> EventHandlerMap;
|
||||||
typedef Poco::FastMutex FastMutexType;
|
typedef Poco::FastMutex MutexType;
|
||||||
typedef FastMutexType::ScopedLock FastScopedLock;
|
typedef MutexType::ScopedLock ScopedLock;
|
||||||
#ifdef POCO_HAVE_STD_ATOMICS
|
|
||||||
typedef Poco::SpinlockMutex SpinMutexType;
|
|
||||||
typedef SpinMutexType::ScopedLock SpinScopedLock;
|
|
||||||
#else
|
|
||||||
typedef Poco::FastMutex SpinMutexType;
|
|
||||||
typedef SpinMutexType::ScopedLock SpinScopedLock;
|
|
||||||
#endif // POCO_HAVE_STD_ATOMICS
|
|
||||||
typedef std::pair<CompletionHandler, Poco::Timestamp> CompletionHandlerEntry;
|
|
||||||
typedef std::deque<CompletionHandlerEntry> HandlerList;
|
|
||||||
|
|
||||||
bool hasSocketHandlers();
|
bool hasSocketHandlers();
|
||||||
void dispatch(NotifierPtr& pNotifier, SocketNotification* pNotification);
|
void dispatch(NotifierPtr& pNotifier, SocketNotification* pNotification);
|
||||||
NotifierPtr getNotifier(const Socket& socket, bool makeNew = false);
|
NotifierPtr getNotifier(const Socket& socket, bool makeNew = false);
|
||||||
bool isPermanent(const Poco::Timestamp& entry) const;
|
|
||||||
|
|
||||||
template <typename F>
|
|
||||||
int removeCompletionHandlers(F isType, int count)
|
|
||||||
/// Removes `count` completion handlers of the specified
|
|
||||||
/// type; if count is -1, removes all completion handlers
|
|
||||||
/// of the specified type.
|
|
||||||
{
|
|
||||||
int removed = 0;
|
|
||||||
SpinScopedLock lock(_completionMutex);
|
|
||||||
int left = count > -1 ? count : static_cast<int>(_complHandlers.size());
|
|
||||||
HandlerList::iterator it = _complHandlers.begin();
|
|
||||||
while (left && it != _complHandlers.end())
|
|
||||||
{
|
|
||||||
if (isType(it->second))
|
|
||||||
{
|
|
||||||
++removed;
|
|
||||||
it = _complHandlers.erase((it));
|
|
||||||
--left;
|
|
||||||
}
|
|
||||||
else ++it;
|
|
||||||
}
|
|
||||||
return removed;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@ -330,9 +232,7 @@ private:
|
|||||||
NotificationPtr _pTimeoutNotification;
|
NotificationPtr _pTimeoutNotification;
|
||||||
NotificationPtr _pIdleNotification;
|
NotificationPtr _pIdleNotification;
|
||||||
NotificationPtr _pShutdownNotification;
|
NotificationPtr _pShutdownNotification;
|
||||||
HandlerList _complHandlers;
|
MutexType _mutex;
|
||||||
FastMutexType _ioMutex;
|
|
||||||
SpinMutexType _completionMutex;
|
|
||||||
Poco::Thread* _pThread;
|
Poco::Thread* _pThread;
|
||||||
|
|
||||||
friend class SocketNotifier;
|
friend class SocketNotifier;
|
||||||
|
@ -18,11 +18,6 @@
|
|||||||
#include "Poco/ErrorHandler.h"
|
#include "Poco/ErrorHandler.h"
|
||||||
#include "Poco/Thread.h"
|
#include "Poco/Thread.h"
|
||||||
#include "Poco/Exception.h"
|
#include "Poco/Exception.h"
|
||||||
#include <memory>
|
|
||||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
|
||||||
#undef max
|
|
||||||
#endif
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
|
|
||||||
using Poco::Exception;
|
using Poco::Exception;
|
||||||
@ -33,10 +28,6 @@ namespace Poco {
|
|||||||
namespace Net {
|
namespace Net {
|
||||||
|
|
||||||
|
|
||||||
const Timestamp::TimeDiff SocketReactor::PERMANENT_COMPLETION_HANDLER =
|
|
||||||
std::numeric_limits<Timestamp::TimeDiff>::max();
|
|
||||||
|
|
||||||
|
|
||||||
SocketReactor::SocketReactor():
|
SocketReactor::SocketReactor():
|
||||||
_stop(false),
|
_stop(false),
|
||||||
_timeout(DEFAULT_TIMEOUT),
|
_timeout(DEFAULT_TIMEOUT),
|
||||||
@ -70,114 +61,6 @@ SocketReactor::~SocketReactor()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int SocketReactor::poll(int* pHandled)
|
|
||||||
{
|
|
||||||
int handled = 0;
|
|
||||||
int completed = 0;
|
|
||||||
if (!hasSocketHandlers()) onIdle();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool readable = false;
|
|
||||||
PollSet::SocketModeMap sm = _pollSet.poll(_timeout);
|
|
||||||
if (sm.size() > 0)
|
|
||||||
{
|
|
||||||
onBusy();
|
|
||||||
PollSet::SocketModeMap::iterator it = sm.begin();
|
|
||||||
PollSet::SocketModeMap::iterator end = sm.end();
|
|
||||||
for (; it != end; ++it)
|
|
||||||
{
|
|
||||||
if (it->second & PollSet::POLL_READ)
|
|
||||||
{
|
|
||||||
dispatch(it->first, _pReadableNotification);
|
|
||||||
readable = true;
|
|
||||||
++handled;
|
|
||||||
}
|
|
||||||
if (it->second & PollSet::POLL_WRITE)
|
|
||||||
{
|
|
||||||
dispatch(it->first, _pWritableNotification);
|
|
||||||
++handled;
|
|
||||||
}
|
|
||||||
if (it->second & PollSet::POLL_ERROR)
|
|
||||||
{
|
|
||||||
dispatch(it->first, _pErrorNotification);
|
|
||||||
++handled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!readable) onTimeout();
|
|
||||||
}
|
|
||||||
if (pHandled) *pHandled = handled;
|
|
||||||
if (hasSocketHandlers())
|
|
||||||
{
|
|
||||||
if (handled) completed = onComplete();
|
|
||||||
}
|
|
||||||
else completed = onComplete(false, true);
|
|
||||||
return completed;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int SocketReactor::onComplete(bool handleOne, bool expiredOnly)
|
|
||||||
{
|
|
||||||
std::unique_ptr<CompletionHandler> pCH;
|
|
||||||
int handled = 0;
|
|
||||||
{
|
|
||||||
HandlerList::iterator it = _complHandlers.begin();
|
|
||||||
while (it != _complHandlers.end())
|
|
||||||
{
|
|
||||||
std::size_t prevSize = 0;
|
|
||||||
// A completion handler may add new
|
|
||||||
// completion handler(s), so the mutex must
|
|
||||||
// be unlocked before the invocation.
|
|
||||||
{
|
|
||||||
SpinScopedLock lock(_completionMutex);
|
|
||||||
bool alwaysRun = isPermanent(it->second) && !expiredOnly;
|
|
||||||
bool isExpired = !alwaysRun && (Timestamp() > it->second);
|
|
||||||
if (isExpired)
|
|
||||||
{
|
|
||||||
pCH.reset(new CompletionHandler(std::move(it->first)));
|
|
||||||
it = _complHandlers.erase(it);
|
|
||||||
}
|
|
||||||
else if (alwaysRun)
|
|
||||||
{
|
|
||||||
pCH.reset(new CompletionHandler(it->first));
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
else ++it;
|
|
||||||
prevSize = _complHandlers.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pCH)
|
|
||||||
{
|
|
||||||
(*pCH)();
|
|
||||||
pCH.reset();
|
|
||||||
++handled;
|
|
||||||
if (handleOne) break;
|
|
||||||
}
|
|
||||||
// handler call may add or remove handlers;
|
|
||||||
// if so, we must start from the beginning
|
|
||||||
{
|
|
||||||
SpinScopedLock lock(_completionMutex);
|
|
||||||
if (prevSize != _complHandlers.size())
|
|
||||||
it = _complHandlers.begin();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return handled;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int SocketReactor::runOne()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
while (0 == onComplete(true));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
catch(...) {}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SocketReactor::run()
|
void SocketReactor::run()
|
||||||
{
|
{
|
||||||
_pThread = Thread::current();
|
_pThread = Thread::current();
|
||||||
@ -185,10 +68,32 @@ void SocketReactor::run()
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!poll())
|
if (!hasSocketHandlers())
|
||||||
{
|
{
|
||||||
if (!hasSocketHandlers())
|
onIdle();
|
||||||
Thread::trySleep(static_cast<long>(_timeout.totalMilliseconds()));
|
Thread::trySleep(static_cast<long>(_timeout.totalMilliseconds()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool readable = false;
|
||||||
|
PollSet::SocketModeMap sm = _pollSet.poll(_timeout);
|
||||||
|
if (sm.size() > 0)
|
||||||
|
{
|
||||||
|
onBusy();
|
||||||
|
PollSet::SocketModeMap::iterator it = sm.begin();
|
||||||
|
PollSet::SocketModeMap::iterator end = sm.end();
|
||||||
|
for (; it != end; ++it)
|
||||||
|
{
|
||||||
|
if (it->second & PollSet::POLL_READ)
|
||||||
|
{
|
||||||
|
dispatch(it->first, _pReadableNotification);
|
||||||
|
readable = true;
|
||||||
|
}
|
||||||
|
if (it->second & PollSet::POLL_WRITE) dispatch(it->first, _pWritableNotification);
|
||||||
|
if (it->second & PollSet::POLL_ERROR) dispatch(it->first, _pErrorNotification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!readable) onTimeout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception& exc)
|
catch (Exception& exc)
|
||||||
@ -212,7 +117,7 @@ bool SocketReactor::hasSocketHandlers()
|
|||||||
{
|
{
|
||||||
if (!_pollSet.empty())
|
if (!_pollSet.empty())
|
||||||
{
|
{
|
||||||
FastScopedLock lock(_ioMutex);
|
ScopedLock lock(_mutex);
|
||||||
for (auto& p: _handlers)
|
for (auto& p: _handlers)
|
||||||
{
|
{
|
||||||
if (p.second->accepts(_pReadableNotification) ||
|
if (p.second->accepts(_pReadableNotification) ||
|
||||||
@ -249,92 +154,11 @@ const Poco::Timespan& SocketReactor::getTimeout() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SocketReactor::addCompletionHandler(const CompletionHandler& ch, Timestamp::TimeDiff ms)
|
|
||||||
{
|
|
||||||
addCompletionHandler(CompletionHandler(ch), ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SocketReactor::addCompletionHandler(CompletionHandler&& ch, Timestamp::TimeDiff ms, int pos)
|
|
||||||
{
|
|
||||||
Poco::Timestamp expires = (ms != PERMANENT_COMPLETION_HANDLER) ? Timestamp() + ms*1000 : Timestamp(PERMANENT_COMPLETION_HANDLER);
|
|
||||||
|
|
||||||
if (pos == -1)
|
|
||||||
{
|
|
||||||
SpinScopedLock lock(_completionMutex);
|
|
||||||
_complHandlers.push_back({std::move(ch), expires});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (pos < 0) throw Poco::InvalidArgumentException("SocketReactor::addCompletionHandler()");
|
|
||||||
SpinScopedLock lock(_completionMutex);
|
|
||||||
_complHandlers.insert(_complHandlers.begin() + pos, {std::move(ch), expires});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SocketReactor::removeCompletionHandlers()
|
|
||||||
{
|
|
||||||
SpinScopedLock lock(_completionMutex);
|
|
||||||
_complHandlers.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int SocketReactor::scheduledCompletionHandlers()
|
|
||||||
{
|
|
||||||
int cnt = 0;
|
|
||||||
SpinScopedLock lock(_completionMutex);
|
|
||||||
HandlerList::iterator it = _complHandlers.begin();
|
|
||||||
for (; it != _complHandlers.end(); ++it)
|
|
||||||
{
|
|
||||||
if (!isPermanent(it->second)/*it->second != Timestamp(0)*/) ++cnt;
|
|
||||||
}
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int SocketReactor::removeScheduledCompletionHandlers(int count)
|
|
||||||
{
|
|
||||||
auto isScheduled = [this](const Timestamp& ts) { return !isPermanent(ts); };
|
|
||||||
return removeCompletionHandlers(isScheduled, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int SocketReactor::permanentCompletionHandlers()
|
|
||||||
{
|
|
||||||
int cnt = 0;
|
|
||||||
SpinScopedLock lock(_completionMutex);
|
|
||||||
HandlerList::iterator it = _complHandlers.begin();
|
|
||||||
for (; it != _complHandlers.end(); ++it)
|
|
||||||
{
|
|
||||||
if (isPermanent(it->second))
|
|
||||||
++cnt;
|
|
||||||
}
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int SocketReactor::removePermanentCompletionHandlers(int count)
|
|
||||||
{
|
|
||||||
auto perm = [this](const Timestamp& ts) { return isPermanent(ts); };
|
|
||||||
return removeCompletionHandlers(perm, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool SocketReactor::isPermanent(const Timestamp& entry) const
|
|
||||||
{
|
|
||||||
return entry == Timestamp(PERMANENT_COMPLETION_HANDLER);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SocketReactor::addEventHandler(const Socket& socket, const Poco::AbstractObserver& observer)
|
void SocketReactor::addEventHandler(const Socket& socket, const Poco::AbstractObserver& observer)
|
||||||
{
|
{
|
||||||
NotifierPtr pNotifier = getNotifier(socket, true);
|
NotifierPtr pNotifier = getNotifier(socket, true);
|
||||||
|
|
||||||
if (!pNotifier->hasObserver(observer))
|
if (!pNotifier->hasObserver(observer)) pNotifier->addObserver(this, observer);
|
||||||
{
|
|
||||||
pNotifier->addObserver(this, observer);
|
|
||||||
}
|
|
||||||
|
|
||||||
int mode = 0;
|
int mode = 0;
|
||||||
if (pNotifier->accepts(_pReadableNotification)) mode |= PollSet::POLL_READ;
|
if (pNotifier->accepts(_pReadableNotification)) mode |= PollSet::POLL_READ;
|
||||||
@ -358,7 +182,7 @@ SocketReactor::NotifierPtr SocketReactor::getNotifier(const Socket& socket, bool
|
|||||||
const SocketImpl* pImpl = socket.impl();
|
const SocketImpl* pImpl = socket.impl();
|
||||||
if (pImpl == nullptr) return 0;
|
if (pImpl == nullptr) return 0;
|
||||||
poco_socket_t sockfd = pImpl->sockfd();
|
poco_socket_t sockfd = pImpl->sockfd();
|
||||||
FastScopedLock lock(_ioMutex);
|
ScopedLock lock(_mutex);
|
||||||
|
|
||||||
EventHandlerMap::iterator it = _handlers.find(sockfd);
|
EventHandlerMap::iterator it = _handlers.find(sockfd);
|
||||||
if (it != _handlers.end()) return it->second;
|
if (it != _handlers.end()) return it->second;
|
||||||
@ -371,14 +195,14 @@ SocketReactor::NotifierPtr SocketReactor::getNotifier(const Socket& socket, bool
|
|||||||
void SocketReactor::removeEventHandler(const Socket& socket, const Poco::AbstractObserver& observer)
|
void SocketReactor::removeEventHandler(const Socket& socket, const Poco::AbstractObserver& observer)
|
||||||
{
|
{
|
||||||
const SocketImpl* pImpl = socket.impl();
|
const SocketImpl* pImpl = socket.impl();
|
||||||
if (pImpl == nullptr) { return; }
|
if (pImpl == nullptr) return;
|
||||||
NotifierPtr pNotifier = getNotifier(socket);
|
NotifierPtr pNotifier = getNotifier(socket);
|
||||||
if (pNotifier && pNotifier->hasObserver(observer))
|
if (pNotifier && pNotifier->hasObserver(observer))
|
||||||
{
|
{
|
||||||
if(pNotifier->countObservers() == 1)
|
if(pNotifier->countObservers() == 1)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
FastScopedLock lock(_ioMutex);
|
ScopedLock lock(_mutex);
|
||||||
_handlers.erase(pImpl->sockfd());
|
_handlers.erase(pImpl->sockfd());
|
||||||
}
|
}
|
||||||
_pollSet.remove(socket);
|
_pollSet.remove(socket);
|
||||||
@ -429,7 +253,7 @@ void SocketReactor::dispatch(SocketNotification* pNotification)
|
|||||||
{
|
{
|
||||||
std::vector<NotifierPtr> delegates;
|
std::vector<NotifierPtr> delegates;
|
||||||
{
|
{
|
||||||
FastScopedLock lock(_ioMutex);
|
ScopedLock lock(_mutex);
|
||||||
delegates.reserve(_handlers.size());
|
delegates.reserve(_handlers.size());
|
||||||
for (EventHandlerMap::iterator it = _handlers.begin(); it != _handlers.end(); ++it)
|
for (EventHandlerMap::iterator it = _handlers.begin(); it != _handlers.end(); ++it)
|
||||||
delegates.push_back(it->second);
|
delegates.push_back(it->second);
|
||||||
@ -445,7 +269,6 @@ void SocketReactor::dispatch(NotifierPtr& pNotifier, SocketNotification* pNotifi
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Socket s = pNotification->socket();
|
|
||||||
pNotifier->dispatch(pNotification);
|
pNotifier->dispatch(pNotification);
|
||||||
}
|
}
|
||||||
catch (Exception& exc)
|
catch (Exception& exc)
|
||||||
|
@ -9,27 +9,27 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "SocketReactorTest.h"
|
#include "SocketReactorTest.h"
|
||||||
#include "EchoServer.h"
|
|
||||||
#include "UDPEchoServer.h"
|
|
||||||
#include "CppUnit/TestCaller.h"
|
#include "CppUnit/TestCaller.h"
|
||||||
#include "CppUnit/TestSuite.h"
|
#include "CppUnit/TestSuite.h"
|
||||||
|
#include "Poco/Net/SocketReactor.h"
|
||||||
|
#include "Poco/Net/SocketNotification.h"
|
||||||
#include "Poco/Net/SocketConnector.h"
|
#include "Poco/Net/SocketConnector.h"
|
||||||
#include "Poco/Net/SocketAcceptor.h"
|
#include "Poco/Net/SocketAcceptor.h"
|
||||||
#include "Poco/Net/ParallelSocketAcceptor.h"
|
#include "Poco/Net/ParallelSocketAcceptor.h"
|
||||||
#include "Poco/Net/StreamSocket.h"
|
#include "Poco/Net/StreamSocket.h"
|
||||||
#include "Poco/Net/DatagramSocket.h"
|
|
||||||
#include "Poco/Net/ServerSocket.h"
|
#include "Poco/Net/ServerSocket.h"
|
||||||
#include "Poco/Timestamp.h"
|
#include "Poco/Net/SocketAddress.h"
|
||||||
|
#include "Poco/Observer.h"
|
||||||
#include "Poco/Exception.h"
|
#include "Poco/Exception.h"
|
||||||
|
#include "Poco/Thread.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using Poco::Net::SocketReactor;
|
using Poco::Net::SocketReactor;
|
||||||
using Poco::Net::SocketConnector;
|
using Poco::Net::SocketConnector;
|
||||||
using Poco::Net::SocketAcceptor;
|
using Poco::Net::SocketAcceptor;
|
||||||
using Poco::Net::ParallelSocketAcceptor;
|
using Poco::Net::ParallelSocketAcceptor;
|
||||||
using Poco::Net::StreamSocket;
|
using Poco::Net::StreamSocket;
|
||||||
using Poco::Net::DatagramSocket;
|
|
||||||
using Poco::Net::ServerSocket;
|
using Poco::Net::ServerSocket;
|
||||||
using Poco::Net::SocketAddress;
|
using Poco::Net::SocketAddress;
|
||||||
using Poco::Net::SocketNotification;
|
using Poco::Net::SocketNotification;
|
||||||
@ -40,7 +40,6 @@ using Poco::Net::ShutdownNotification;
|
|||||||
using Poco::Observer;
|
using Poco::Observer;
|
||||||
using Poco::IllegalStateException;
|
using Poco::IllegalStateException;
|
||||||
using Poco::Thread;
|
using Poco::Thread;
|
||||||
using Poco::Timestamp;
|
|
||||||
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -240,20 +239,20 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamSocket _socket;
|
StreamSocket _socket;
|
||||||
SocketReactor& _reactor;
|
SocketReactor& _reactor;
|
||||||
Observer<ClientServiceHandler, ReadableNotification> _or;
|
Observer<ClientServiceHandler, ReadableNotification> _or;
|
||||||
Observer<ClientServiceHandler, WritableNotification> _ow;
|
Observer<ClientServiceHandler, WritableNotification> _ow;
|
||||||
Observer<ClientServiceHandler, TimeoutNotification> _ot;
|
Observer<ClientServiceHandler, TimeoutNotification> _ot;
|
||||||
Observer<ClientServiceHandler, ShutdownNotification> _os;
|
Observer<ClientServiceHandler, ShutdownNotification> _os;
|
||||||
std::stringstream _str;
|
std::stringstream _str;
|
||||||
static std::string _data;
|
static std::string _data;
|
||||||
static bool _readableError;
|
static bool _readableError;
|
||||||
static bool _writableError;
|
static bool _writableError;
|
||||||
static bool _timeoutError;
|
static bool _timeoutError;
|
||||||
static bool _timeout;
|
static bool _timeout;
|
||||||
static bool _closeOnTimeout;
|
static bool _closeOnTimeout;
|
||||||
static bool _once;
|
static bool _once;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -370,55 +369,12 @@ namespace
|
|||||||
static Data _data;
|
static Data _data;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StreamSocket _socket;
|
StreamSocket _socket;
|
||||||
SocketReactor& _reactor;
|
SocketReactor& _reactor;
|
||||||
int _pos;
|
int _pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
DataServiceHandler::Data DataServiceHandler::_data;
|
DataServiceHandler::Data DataServiceHandler::_data;
|
||||||
|
|
||||||
class CompletionHandlerTestObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CompletionHandlerTestObject() = delete;
|
|
||||||
|
|
||||||
CompletionHandlerTestObject(SocketReactor& reactor, Timestamp::TimeDiff ms = SocketReactor::PERMANENT_COMPLETION_HANDLER):
|
|
||||||
_reactor(reactor),
|
|
||||||
_counter(0)
|
|
||||||
{
|
|
||||||
auto handler = [this] ()
|
|
||||||
{
|
|
||||||
++_counter;
|
|
||||||
};
|
|
||||||
_reactor.addCompletionHandler(handler, ms);
|
|
||||||
_reactor.addCompletionHandler(std::move(handler), ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addRecursiveCompletionHandler(int count)
|
|
||||||
{
|
|
||||||
_count = count;
|
|
||||||
if (!_handler)
|
|
||||||
{
|
|
||||||
_handler = [&] ()
|
|
||||||
{
|
|
||||||
if (_counter++ < _count)
|
|
||||||
_reactor.addCompletionHandler(_handler);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
_reactor.addCompletionHandler(_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
int counter()
|
|
||||||
{
|
|
||||||
return _counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
SocketReactor& _reactor;
|
|
||||||
int _counter;
|
|
||||||
int _count;
|
|
||||||
std::function<void()> _handler = nullptr;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -451,13 +407,6 @@ void SocketReactorTest::testSocketReactor()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SocketReactorTest::testSocketReactorPoll()
|
|
||||||
{
|
|
||||||
testIOHandler<EchoServer, StreamSocket>();
|
|
||||||
testIOHandler<UDPEchoServer, DatagramSocket>();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SocketReactorTest::testSetSocketReactor()
|
void SocketReactorTest::testSetSocketReactor()
|
||||||
{
|
{
|
||||||
SocketAddress ssa;
|
SocketAddress ssa;
|
||||||
@ -559,11 +508,11 @@ void SocketReactorTest::testDataCollection()
|
|||||||
" \"data\":"
|
" \"data\":"
|
||||||
" ["
|
" ["
|
||||||
" {"
|
" {"
|
||||||
" \"tag1\":"
|
" \"tag1\":"
|
||||||
" ["
|
" ["
|
||||||
" {\"val1\":123},"
|
" {\"val1\":123},"
|
||||||
" {\"val2\":\"abc\"}"
|
" {\"val2\":\"abc\"}"
|
||||||
" ]"
|
" ]"
|
||||||
" }"
|
" }"
|
||||||
" ]"
|
" ]"
|
||||||
"}\n");
|
"}\n");
|
||||||
@ -575,33 +524,33 @@ void SocketReactorTest::testDataCollection()
|
|||||||
" \"ts\":\"1524864652654321\","
|
" \"ts\":\"1524864652654321\","
|
||||||
" \"data\":"
|
" \"data\":"
|
||||||
" ["
|
" ["
|
||||||
" {"
|
" {"
|
||||||
" \"tag1\":"
|
" \"tag1\":"
|
||||||
" ["
|
" ["
|
||||||
" {"
|
" {"
|
||||||
" \"val1\":123,"
|
" \"val1\":123,"
|
||||||
" \"val2\":\"abc\","
|
" \"val2\":\"abc\","
|
||||||
" \"val3\":42.123"
|
" \"val3\":42.123"
|
||||||
" },"
|
" },"
|
||||||
" {"
|
" {"
|
||||||
" \"val1\":987,"
|
" \"val1\":987,"
|
||||||
" \"val2\":\"xyz\","
|
" \"val2\":\"xyz\","
|
||||||
" \"val3\":24.321"
|
" \"val3\":24.321"
|
||||||
" }"
|
" }"
|
||||||
" ],"
|
" ],"
|
||||||
" \"tag2\":"
|
" \"tag2\":"
|
||||||
" ["
|
" ["
|
||||||
" {"
|
" {"
|
||||||
" \"val1\":42.123,"
|
" \"val1\":42.123,"
|
||||||
" \"val2\":123,"
|
" \"val2\":123,"
|
||||||
" \"val3\":\"abc\""
|
" \"val3\":\"abc\""
|
||||||
" },"
|
" },"
|
||||||
" {"
|
" {"
|
||||||
" \"val1\":24.321,"
|
" \"val1\":24.321,"
|
||||||
" \"val2\":987,"
|
" \"val2\":987,"
|
||||||
" \"val3\":\"xyz\""
|
" \"val3\":\"xyz\""
|
||||||
" }"
|
" }"
|
||||||
" ]"
|
" ]"
|
||||||
" }"
|
" }"
|
||||||
" ]"
|
" ]"
|
||||||
"}\n";
|
"}\n";
|
||||||
@ -621,50 +570,6 @@ void SocketReactorTest::testDataCollection()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SocketReactorTest::testCompletionHandler()
|
|
||||||
{/*
|
|
||||||
SocketReactor reactor;
|
|
||||||
CompletionHandlerTestObject ch(reactor);
|
|
||||||
assert (reactor.permanentCompletionHandlers() == 2);
|
|
||||||
assert (reactor.scheduledCompletionHandlers() == 0);
|
|
||||||
assertTrue(ch.counter() == 0);
|
|
||||||
assertTrue(reactor.poll() == 2);
|
|
||||||
assertTrue(ch.counter() == 2);
|
|
||||||
ch.addRecursiveCompletionHandler(5);
|
|
||||||
assertTrue (reactor.permanentCompletionHandlers() == 3);
|
|
||||||
assertTrue (reactor.scheduledCompletionHandlers() == 0);
|
|
||||||
assertTrue(reactor.poll() == 7);
|
|
||||||
assertTrue(ch.counter() == 9);
|
|
||||||
assertTrue (reactor.permanentCompletionHandlers() == 4);
|
|
||||||
assertTrue (reactor.scheduledCompletionHandlers() == 0);
|
|
||||||
|
|
||||||
reactor.removePermanentCompletionHandlers();
|
|
||||||
assertTrue (reactor.poll() == 0);
|
|
||||||
assertTrue(ch.counter() == 9);
|
|
||||||
*/}
|
|
||||||
|
|
||||||
|
|
||||||
void SocketReactorTest::testTimedCompletionHandler()
|
|
||||||
{
|
|
||||||
SocketReactor reactor;
|
|
||||||
CompletionHandlerTestObject ch(reactor, 500);
|
|
||||||
assert (reactor.permanentCompletionHandlers() == 0);
|
|
||||||
assert (reactor.scheduledCompletionHandlers() == 2);
|
|
||||||
assertTrue(ch.counter() == 0);
|
|
||||||
reactor.poll();
|
|
||||||
assertTrue(ch.counter() == 0);
|
|
||||||
reactor.poll();
|
|
||||||
|
|
||||||
Thread::sleep(500);
|
|
||||||
reactor.poll();
|
|
||||||
assertTrue(ch.counter() == 2);
|
|
||||||
assert (reactor.permanentCompletionHandlers() == 0);
|
|
||||||
assert (reactor.scheduledCompletionHandlers() == 0);
|
|
||||||
reactor.poll();
|
|
||||||
assertTrue(ch.counter() == 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SocketReactorTest::setUp()
|
void SocketReactorTest::setUp()
|
||||||
{
|
{
|
||||||
ClientServiceHandler::setCloseOnTimeout(false);
|
ClientServiceHandler::setCloseOnTimeout(false);
|
||||||
@ -681,14 +586,11 @@ CppUnit::Test* SocketReactorTest::suite()
|
|||||||
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("SocketReactorTest");
|
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("SocketReactorTest");
|
||||||
|
|
||||||
CppUnit_addTest(pSuite, SocketReactorTest, testSocketReactor);
|
CppUnit_addTest(pSuite, SocketReactorTest, testSocketReactor);
|
||||||
CppUnit_addTest(pSuite, SocketReactorTest, testSocketReactorPoll);
|
|
||||||
CppUnit_addTest(pSuite, SocketReactorTest, testSetSocketReactor);
|
CppUnit_addTest(pSuite, SocketReactorTest, testSetSocketReactor);
|
||||||
CppUnit_addTest(pSuite, SocketReactorTest, testParallelSocketReactor);
|
CppUnit_addTest(pSuite, SocketReactorTest, testParallelSocketReactor);
|
||||||
CppUnit_addTest(pSuite, SocketReactorTest, testSocketConnectorFail);
|
CppUnit_addTest(pSuite, SocketReactorTest, testSocketConnectorFail);
|
||||||
CppUnit_addTest(pSuite, SocketReactorTest, testSocketConnectorTimeout);
|
CppUnit_addTest(pSuite, SocketReactorTest, testSocketConnectorTimeout);
|
||||||
CppUnit_addTest(pSuite, SocketReactorTest, testDataCollection);
|
CppUnit_addTest(pSuite, SocketReactorTest, testDataCollection);
|
||||||
CppUnit_addTest(pSuite, SocketReactorTest, testCompletionHandler);
|
|
||||||
CppUnit_addTest(pSuite, SocketReactorTest, testTimedCompletionHandler);
|
|
||||||
|
|
||||||
return pSuite;
|
return pSuite;
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,6 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "Poco/Net/Net.h"
|
#include "Poco/Net/Net.h"
|
||||||
#include "Poco/Thread.h"
|
|
||||||
#include "Poco/Observer.h"
|
|
||||||
#include "Poco/Net/SocketAddress.h"
|
|
||||||
#include "Poco/Net/SocketReactor.h"
|
|
||||||
#include "Poco/Net/SocketNotification.h"
|
|
||||||
#include "CppUnit/TestCase.h"
|
#include "CppUnit/TestCase.h"
|
||||||
|
|
||||||
|
|
||||||
@ -30,14 +25,11 @@ public:
|
|||||||
~SocketReactorTest();
|
~SocketReactorTest();
|
||||||
|
|
||||||
void testSocketReactor();
|
void testSocketReactor();
|
||||||
void testSocketReactorPoll();
|
|
||||||
void testSetSocketReactor();
|
void testSetSocketReactor();
|
||||||
void testParallelSocketReactor();
|
void testParallelSocketReactor();
|
||||||
void testSocketConnectorFail();
|
void testSocketConnectorFail();
|
||||||
void testSocketConnectorTimeout();
|
void testSocketConnectorTimeout();
|
||||||
void testDataCollection();
|
void testDataCollection();
|
||||||
void testCompletionHandler();
|
|
||||||
void testTimedCompletionHandler();
|
|
||||||
|
|
||||||
void setUp();
|
void setUp();
|
||||||
void tearDown();
|
void tearDown();
|
||||||
@ -45,127 +37,6 @@ public:
|
|||||||
static CppUnit::Test* suite();
|
static CppUnit::Test* suite();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
template <class SocketType>
|
|
||||||
class IOHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
IOHandler(const SocketType& socket, Poco::Net::SocketReactor& reactor):
|
|
||||||
_socket(socket),
|
|
||||||
_reactor(reactor),
|
|
||||||
_or(*this, &IOHandler::onReadable),
|
|
||||||
_ow(*this, &IOHandler::onWritable),
|
|
||||||
_ot(*this, &IOHandler::onTimeout),
|
|
||||||
_os(*this, &IOHandler::onShutdown)
|
|
||||||
{
|
|
||||||
_reactor.addEventHandler(_socket, _or);
|
|
||||||
_reactor.addEventHandler(_socket, _ow);
|
|
||||||
_reactor.addEventHandler(_socket, _ot);
|
|
||||||
_reactor.addEventHandler(_socket, _os);
|
|
||||||
}
|
|
||||||
|
|
||||||
~IOHandler()
|
|
||||||
{
|
|
||||||
_reactor.removeEventHandler(_socket, _or);
|
|
||||||
_reactor.removeEventHandler(_socket, _ow);
|
|
||||||
_reactor.removeEventHandler(_socket, _ot);
|
|
||||||
_reactor.removeEventHandler(_socket, _os);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onReadable(Poco::Net::ReadableNotification* pNf)
|
|
||||||
{
|
|
||||||
pNf->release();
|
|
||||||
char buffer[32];
|
|
||||||
int n = _socket.receiveBytes(buffer, sizeof(buffer));
|
|
||||||
if (n > 0) _data.append(buffer, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onWritable(Poco::Net::WritableNotification* pNf)
|
|
||||||
{
|
|
||||||
pNf->release();
|
|
||||||
_writable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onTimeout(Poco::Net::TimeoutNotification* pNf)
|
|
||||||
{
|
|
||||||
pNf->release();
|
|
||||||
_timeout = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onShutdown(Poco::Net::ShutdownNotification* pNf)
|
|
||||||
{
|
|
||||||
pNf->release();
|
|
||||||
_shutdown = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& data()
|
|
||||||
{
|
|
||||||
return _data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool writable() const
|
|
||||||
{
|
|
||||||
return _writable;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool timeout() const
|
|
||||||
{
|
|
||||||
return _timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool shutdown() const
|
|
||||||
{
|
|
||||||
return _shutdown;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
SocketType _socket;
|
|
||||||
Poco::Net::SocketReactor& _reactor;
|
|
||||||
Poco::Observer<IOHandler, Poco::Net::ReadableNotification> _or;
|
|
||||||
Poco::Observer<IOHandler, Poco::Net::WritableNotification> _ow;
|
|
||||||
Poco::Observer<IOHandler, Poco::Net::TimeoutNotification> _ot;
|
|
||||||
Poco::Observer<IOHandler, Poco::Net::ShutdownNotification> _os;
|
|
||||||
bool _writable = false;
|
|
||||||
bool _timeout = false;
|
|
||||||
bool _shutdown = false;
|
|
||||||
std::string _data;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename ServerType, typename SocketType>
|
|
||||||
void testIOHandler()
|
|
||||||
{
|
|
||||||
using Poco::Thread;
|
|
||||||
using Poco::Net::SocketReactor;
|
|
||||||
using Poco::Net::SocketAddress;
|
|
||||||
|
|
||||||
ServerType echoServer;
|
|
||||||
SocketType ds;
|
|
||||||
ds.connect(SocketAddress("127.0.0.1", echoServer.port()));
|
|
||||||
SocketReactor reactor;
|
|
||||||
IOHandler<SocketType> ih(ds, reactor);
|
|
||||||
int n = ds.sendBytes("hello", 5);
|
|
||||||
assertTrue (n == 5);
|
|
||||||
assertFalse(ih.writable());
|
|
||||||
Thread t; t.start(reactor);
|
|
||||||
Thread::sleep(500);
|
|
||||||
assertTrue(ih.writable());
|
|
||||||
assertFalse(ih.shutdown());
|
|
||||||
reactor.stop(); t.join();
|
|
||||||
assertTrue(ih.shutdown());
|
|
||||||
assertTrue (ih.data() == "hello");
|
|
||||||
n = ds.sendBytes("hello", 5);
|
|
||||||
assertTrue (n == 5);
|
|
||||||
while (ih.data().size() < 10)
|
|
||||||
{
|
|
||||||
reactor.poll();
|
|
||||||
Thread::sleep(10);
|
|
||||||
}
|
|
||||||
assertTrue (ih.data() == "hellohello");
|
|
||||||
reactor.poll();
|
|
||||||
assertTrue (ih.timeout());
|
|
||||||
ds.close();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user