mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-24 00:49:46 +02:00
poll() support (tested on Solaris and Linux)
array delete policy for SharedPtr
This commit is contained in:
@@ -95,6 +95,20 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <class C>
|
||||||
|
class ReleaseArrayPolicy
|
||||||
|
/// The release policy for SharedPtr holding arrays.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void release(C* pObj)
|
||||||
|
/// Delete the object.
|
||||||
|
/// Note that pObj can be 0.
|
||||||
|
{
|
||||||
|
delete [] pObj;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
template <class C, class RC = ReferenceCounter, class RP = ReleasePolicy<C> >
|
template <class C, class RC = ReferenceCounter, class RP = ReleasePolicy<C> >
|
||||||
class SharedPtr
|
class SharedPtr
|
||||||
/// SharedPtr is a "smart" pointer for classes implementing
|
/// SharedPtr is a "smart" pointer for classes implementing
|
||||||
|
|||||||
@@ -134,9 +134,18 @@ public:
|
|||||||
/// exceptList is zero, select() will return immediately and the
|
/// exceptList is zero, select() will return immediately and the
|
||||||
/// return value will be 0.
|
/// return value will be 0.
|
||||||
|
|
||||||
|
static int poll(SocketList& readList, SocketList& writeList, SocketList& exceptList, const Poco::Timespan& timeout);
|
||||||
|
/// Provides same functionality as select() call on the platforms
|
||||||
|
/// that have poll() system call available. The advantage of using poll() over
|
||||||
|
/// select() is that the number of socket file descriptors scanned is dynamically
|
||||||
|
/// determined at runtime and is not subject to static maximum limitations like select().
|
||||||
|
///
|
||||||
|
/// For documentation, see
|
||||||
|
/// select(SocketList&, SocketList&, SocketList&, const Poco::Timespan&)
|
||||||
|
|
||||||
bool poll(const Poco::Timespan& timeout, int mode) const;
|
bool poll(const Poco::Timespan& timeout, int mode) const;
|
||||||
/// Determines the status of the socket, using a
|
/// Determines the status of the socket, using a
|
||||||
/// call to select().
|
/// call to poll() or select().
|
||||||
///
|
///
|
||||||
/// The mode argument is constructed by combining the values
|
/// The mode argument is constructed by combining the values
|
||||||
/// of the SelectMode enumeration.
|
/// of the SelectMode enumeration.
|
||||||
@@ -305,6 +314,23 @@ protected:
|
|||||||
/// Returns the socket descriptor for this socket.
|
/// Returns the socket descriptor for this socket.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
#if defined(POCO_HAVE_FD_POLL)
|
||||||
|
class FDCompare
|
||||||
|
/// Utility functor used to compare socket file descriptors.
|
||||||
|
/// Used in poll() member function.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FDCompare(int fd): _fd(fd) { }
|
||||||
|
inline bool operator()(const Socket& socket) const
|
||||||
|
{ return socket.sockfd() == _fd; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
FDCompare();
|
||||||
|
int _fd;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
SocketImpl* _pImpl;
|
SocketImpl* _pImpl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -176,6 +176,12 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: determine all platforms having poll() call
|
||||||
|
#if (POCO_OS == POCO_OS_SOLARIS) || (POCO_OS == POCO_OS_LINUX)
|
||||||
|
#define POCO_HAVE_FD_POLL 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if (POCO_OS == POCO_OS_HPUX) || (POCO_OS == POCO_OS_SOLARIS)
|
#if (POCO_OS == POCO_OS_HPUX) || (POCO_OS == POCO_OS_SOLARIS)
|
||||||
#define POCO_BROKEN_TIMEOUTS 1
|
#define POCO_BROKEN_TIMEOUTS 1
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -39,7 +39,13 @@
|
|||||||
#include "Poco/Timestamp.h"
|
#include "Poco/Timestamp.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <string.h> // FD_SET needs memset on some platforms, so we can't use <cstring>
|
#include <string.h> // FD_SET needs memset on some platforms, so we can't use <cstring>
|
||||||
|
#if defined(POCO_HAVE_FD_POLL)
|
||||||
|
#include "Poco/SharedPtr.h"
|
||||||
|
#include <poll.h>
|
||||||
|
typedef Poco::SharedPtr<pollfd,
|
||||||
|
Poco::ReferenceCounter,
|
||||||
|
Poco::ReleaseArrayPolicy<pollfd> > SharedPollArray;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco {
|
||||||
namespace Net {
|
namespace Net {
|
||||||
@@ -85,6 +91,96 @@ Socket::~Socket()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Socket::poll(SocketList& readList, SocketList& writeList, SocketList& exceptList, const Poco::Timespan& timeout)
|
||||||
|
{
|
||||||
|
#if !defined(POCO_HAVE_FD_POLL)
|
||||||
|
throw NotImplementedException("poll() is only available on POSIX platforms");
|
||||||
|
#else
|
||||||
|
nfds_t nfd = readList.size() + writeList.size() + exceptList.size();
|
||||||
|
if (0 == nfd) return 0;
|
||||||
|
|
||||||
|
SharedPollArray pPollArr = new pollfd[nfd];
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
for (SocketList::iterator it = readList.begin(); it != readList.end(); ++it)
|
||||||
|
{
|
||||||
|
pPollArr[idx].fd = int(it->sockfd());
|
||||||
|
pPollArr[idx++].events |= POLLIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketList::iterator begR = readList.begin();
|
||||||
|
SocketList::iterator endR = readList.end();
|
||||||
|
for (SocketList::iterator it = writeList.begin(); it != writeList.end(); ++it)
|
||||||
|
{
|
||||||
|
SocketList::iterator pos = std::find(begR, endR, *it);
|
||||||
|
if (pos != endR)
|
||||||
|
{
|
||||||
|
pPollArr[pos-begR].events |= POLLOUT;
|
||||||
|
--nfd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pPollArr[idx].fd = int(it->sockfd());
|
||||||
|
pPollArr[idx++].events |= POLLOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketList::iterator begW = writeList.begin();
|
||||||
|
SocketList::iterator endW = writeList.end();
|
||||||
|
for (SocketList::iterator it = exceptList.begin(); it != exceptList.end(); ++it)
|
||||||
|
{
|
||||||
|
SocketList::iterator pos = std::find(begR, endR, *it);
|
||||||
|
if (pos != endR) --nfd;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SocketList::iterator pos = std::find(begW, endW, *it);
|
||||||
|
if (pos != endW) --nfd;
|
||||||
|
else pPollArr[idx++].fd = int(it->sockfd());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Poco::Timespan remainingTime(timeout);
|
||||||
|
int rc;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Poco::Timestamp start;
|
||||||
|
rc = ::poll(pPollArr, nfd, timeout.totalMilliseconds());
|
||||||
|
if (rc < 0 && SocketImpl::lastError() == POCO_EINTR)
|
||||||
|
{
|
||||||
|
Poco::Timestamp end;
|
||||||
|
Poco::Timespan waited = end - start;
|
||||||
|
if (waited < remainingTime) remainingTime -= waited;
|
||||||
|
else remainingTime = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (rc < 0 && SocketImpl::lastError() == POCO_EINTR);
|
||||||
|
if (rc < 0) SocketImpl::error();
|
||||||
|
|
||||||
|
SocketList readyReadList;
|
||||||
|
SocketList readyWriteList;
|
||||||
|
SocketList readyExceptList;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
SocketList::iterator begE = exceptList.begin();
|
||||||
|
SocketList::iterator endE = exceptList.end();
|
||||||
|
for (int idx = 0; idx < nfd; ++idx)
|
||||||
|
{
|
||||||
|
SocketList::iterator slIt = std::find_if(begR, endR, Socket::FDCompare(pPollArr[idx].fd));
|
||||||
|
if (POLLIN & pPollArr[idx].revents && slIt != endR) readyReadList.push_back(*slIt);
|
||||||
|
slIt = std::find_if(begW, endW, Socket::FDCompare(pPollArr[idx].fd));
|
||||||
|
if (POLLOUT & pPollArr[idx].revents && slIt != endW) readyWriteList.push_back(*slIt);
|
||||||
|
slIt = std::find_if(begE, endE, Socket::FDCompare(pPollArr[idx].fd));
|
||||||
|
if (POLLERR & pPollArr[idx].revents && slIt != endE) readyExceptList.push_back(*slIt);
|
||||||
|
}
|
||||||
|
std::swap(readList, readyReadList);
|
||||||
|
std::swap(writeList, readyWriteList);
|
||||||
|
std::swap(exceptList, readyExceptList);
|
||||||
|
|
||||||
|
return readList.size() + writeList.size() + exceptList.size();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int Socket::select(SocketList& readList, SocketList& writeList, SocketList& exceptList, const Poco::Timespan& timeout)
|
int Socket::select(SocketList& readList, SocketList& writeList, SocketList& exceptList, const Poco::Timespan& timeout)
|
||||||
{
|
{
|
||||||
fd_set fdRead;
|
fd_set fdRead;
|
||||||
|
|||||||
@@ -40,6 +40,9 @@
|
|||||||
#include "Poco/NumberFormatter.h"
|
#include "Poco/NumberFormatter.h"
|
||||||
#include "Poco/Timestamp.h"
|
#include "Poco/Timestamp.h"
|
||||||
#include <string.h> // FD_SET needs memset on some platforms, so we can't use <cstring>
|
#include <string.h> // FD_SET needs memset on some platforms, so we can't use <cstring>
|
||||||
|
#if defined(POCO_HAVE_FD_POLL)
|
||||||
|
#include <poll.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
using Poco::IOException;
|
using Poco::IOException;
|
||||||
@@ -335,9 +338,37 @@ int SocketImpl::available()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SocketImpl::poll(const Poco::Timespan& timeout, int mode)
|
bool SocketImpl::poll(const Poco::Timespan& timeout, int mode)
|
||||||
{
|
{
|
||||||
|
#if defined(POCO_HAVE_FD_POLL)
|
||||||
|
|
||||||
|
pollfd pollBuf;
|
||||||
|
|
||||||
|
std::memset(&pollBuf, 0, sizeof(pollfd));
|
||||||
|
pollBuf.fd = _sockfd;
|
||||||
|
if (mode & SELECT_READ) pollBuf.events |= POLLIN;
|
||||||
|
if (mode & SELECT_WRITE) pollBuf.events |= POLLOUT;
|
||||||
|
|
||||||
|
Poco::Timespan remainingTime(timeout);
|
||||||
|
int rc;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Poco::Timestamp start;
|
||||||
|
rc = ::poll(&pollBuf, 1, remainingTime.totalMilliseconds());
|
||||||
|
|
||||||
|
if (rc < 0 && lastError() == POCO_EINTR)
|
||||||
|
{
|
||||||
|
Poco::Timestamp end;
|
||||||
|
Poco::Timespan waited = end - start;
|
||||||
|
if (waited < remainingTime)
|
||||||
|
remainingTime -= waited;
|
||||||
|
else
|
||||||
|
remainingTime = 0;
|
||||||
|
}
|
||||||
|
} while (rc < 0 && lastError() == POCO_EINTR);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
fd_set fdRead;
|
fd_set fdRead;
|
||||||
fd_set fdWrite;
|
fd_set fdWrite;
|
||||||
fd_set fdExcept;
|
fd_set fdExcept;
|
||||||
@@ -376,6 +407,9 @@ bool SocketImpl::poll(const Poco::Timespan& timeout, int mode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (rc < 0 && lastError() == POCO_EINTR);
|
while (rc < 0 && lastError() == POCO_EINTR);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
if (rc < 0) error();
|
if (rc < 0) error();
|
||||||
return rc > 0;
|
return rc > 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,7 +121,11 @@ void SocketReactor::run()
|
|||||||
{
|
{
|
||||||
onIdle();
|
onIdle();
|
||||||
}
|
}
|
||||||
|
#if defined(POCO_HAVE_FD_POLL)
|
||||||
|
else if (Socket::poll(readable, writable, except, _timeout))
|
||||||
|
#else
|
||||||
else if (Socket::select(readable, writable, except, _timeout))
|
else if (Socket::select(readable, writable, except, _timeout))
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
for (Socket::SocketList::iterator it = readable.begin(); it != readable.end(); ++it)
|
for (Socket::SocketList::iterator it = readable.begin(); it != readable.end(); ++it)
|
||||||
dispatch(*it, _pReadableNotification);
|
dispatch(*it, _pReadableNotification);
|
||||||
|
|||||||
@@ -335,6 +335,15 @@ void SocketTest::testOptions()
|
|||||||
|
|
||||||
|
|
||||||
void SocketTest::testSelect()
|
void SocketTest::testSelect()
|
||||||
|
{
|
||||||
|
doSelectOrPoll1(Socket::select);
|
||||||
|
#if defined(POCO_HAVE_FD_POLL)
|
||||||
|
doSelectOrPoll1(Socket::poll);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SocketTest::doSelectOrPoll1(SelectPtr pAction)
|
||||||
{
|
{
|
||||||
Timespan timeout(250000);
|
Timespan timeout(250000);
|
||||||
|
|
||||||
@@ -347,7 +356,7 @@ void SocketTest::testSelect()
|
|||||||
Socket::SocketList exceptList;
|
Socket::SocketList exceptList;
|
||||||
|
|
||||||
readList.push_back(ss);
|
readList.push_back(ss);
|
||||||
assert (Socket::select(readList, writeList, exceptList, timeout) == 0);
|
assert (pAction(readList, writeList, exceptList, timeout) == 0);
|
||||||
assert (readList.empty());
|
assert (readList.empty());
|
||||||
assert (writeList.empty());
|
assert (writeList.empty());
|
||||||
assert (exceptList.empty());
|
assert (exceptList.empty());
|
||||||
@@ -358,7 +367,7 @@ void SocketTest::testSelect()
|
|||||||
|
|
||||||
readList.push_back(ss);
|
readList.push_back(ss);
|
||||||
writeList.push_back(ss);
|
writeList.push_back(ss);
|
||||||
assert (Socket::select(readList, writeList, exceptList, timeout) == 2);
|
assert (pAction(readList, writeList, exceptList, timeout) == 2);
|
||||||
assert (!readList.empty());
|
assert (!readList.empty());
|
||||||
assert (!writeList.empty());
|
assert (!writeList.empty());
|
||||||
assert (exceptList.empty());
|
assert (exceptList.empty());
|
||||||
@@ -372,6 +381,15 @@ void SocketTest::testSelect()
|
|||||||
|
|
||||||
|
|
||||||
void SocketTest::testSelect2()
|
void SocketTest::testSelect2()
|
||||||
|
{
|
||||||
|
doSelectOrPoll2(Socket::select);
|
||||||
|
#if defined(POCO_HAVE_FD_POLL)
|
||||||
|
doSelectOrPoll2(Socket::poll);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SocketTest::doSelectOrPoll2(SelectPtr pAction)
|
||||||
{
|
{
|
||||||
Timespan timeout(100000);
|
Timespan timeout(100000);
|
||||||
|
|
||||||
@@ -386,7 +404,7 @@ void SocketTest::testSelect2()
|
|||||||
|
|
||||||
readList.push_back(ss1);
|
readList.push_back(ss1);
|
||||||
readList.push_back(ss2);
|
readList.push_back(ss2);
|
||||||
assert (Socket::select(readList, writeList, exceptList, timeout) == 0);
|
assert (pAction(readList, writeList, exceptList, timeout) == 0);
|
||||||
assert (readList.empty());
|
assert (readList.empty());
|
||||||
assert (writeList.empty());
|
assert (writeList.empty());
|
||||||
assert (exceptList.empty());
|
assert (exceptList.empty());
|
||||||
@@ -397,7 +415,7 @@ void SocketTest::testSelect2()
|
|||||||
|
|
||||||
readList.push_back(ss1);
|
readList.push_back(ss1);
|
||||||
readList.push_back(ss2);
|
readList.push_back(ss2);
|
||||||
assert (Socket::select(readList, writeList, exceptList, timeout) == 1);
|
assert (pAction(readList, writeList, exceptList, timeout) == 1);
|
||||||
|
|
||||||
assert (readList.size() == 1);
|
assert (readList.size() == 1);
|
||||||
assert (readList[0] == ss1);
|
assert (readList[0] == ss1);
|
||||||
@@ -413,7 +431,7 @@ void SocketTest::testSelect2()
|
|||||||
exceptList.clear();
|
exceptList.clear();
|
||||||
writeList.push_back(ss1);
|
writeList.push_back(ss1);
|
||||||
writeList.push_back(ss2);
|
writeList.push_back(ss2);
|
||||||
assert (Socket::select(readList, writeList, exceptList, timeout) == 2);
|
assert (pAction(readList, writeList, exceptList, timeout) == 2);
|
||||||
assert (readList.empty());
|
assert (readList.empty());
|
||||||
assert (writeList.size() == 2);
|
assert (writeList.size() == 2);
|
||||||
assert (writeList[0] == ss1);
|
assert (writeList[0] == ss1);
|
||||||
@@ -426,13 +444,22 @@ void SocketTest::testSelect2()
|
|||||||
|
|
||||||
|
|
||||||
void SocketTest::testSelect3()
|
void SocketTest::testSelect3()
|
||||||
|
{
|
||||||
|
doSelectOrPoll3(Socket::select);
|
||||||
|
#if defined(POCO_HAVE_FD_POLL)
|
||||||
|
doSelectOrPoll3(Socket::poll);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SocketTest::doSelectOrPoll3(SelectPtr pAction)
|
||||||
{
|
{
|
||||||
Socket::SocketList readList;
|
Socket::SocketList readList;
|
||||||
Socket::SocketList writeList;
|
Socket::SocketList writeList;
|
||||||
Socket::SocketList exceptList;
|
Socket::SocketList exceptList;
|
||||||
Timespan timeout(1000);
|
Timespan timeout(1000);
|
||||||
|
|
||||||
int rc = Socket::select(readList, writeList, exceptList, timeout);
|
int rc = pAction(readList, writeList, exceptList, timeout);
|
||||||
assert (rc == 0);
|
assert (rc == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,6 +492,5 @@ CppUnit::Test* SocketTest::suite()
|
|||||||
CppUnit_addTest(pSuite, SocketTest, testSelect);
|
CppUnit_addTest(pSuite, SocketTest, testSelect);
|
||||||
CppUnit_addTest(pSuite, SocketTest, testSelect2);
|
CppUnit_addTest(pSuite, SocketTest, testSelect2);
|
||||||
CppUnit_addTest(pSuite, SocketTest, testSelect3);
|
CppUnit_addTest(pSuite, SocketTest, testSelect3);
|
||||||
|
|
||||||
return pSuite;
|
return pSuite;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,14 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "Poco/Net/Net.h"
|
#include "Poco/Net/Net.h"
|
||||||
|
#include "Poco/Net/Socket.h"
|
||||||
#include "CppUnit/TestCase.h"
|
#include "CppUnit/TestCase.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Poco{
|
||||||
|
class Timespan;
|
||||||
|
}
|
||||||
|
|
||||||
class SocketTest: public CppUnit::TestCase
|
class SocketTest: public CppUnit::TestCase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -67,6 +72,14 @@ public:
|
|||||||
static CppUnit::Test* suite();
|
static CppUnit::Test* suite();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
typedef int (*SelectPtr)(Poco::Net::Socket::SocketList&,
|
||||||
|
Poco::Net::Socket::SocketList&,
|
||||||
|
Poco::Net::Socket::SocketList&,
|
||||||
|
const Poco::Timespan&);
|
||||||
|
|
||||||
|
void doSelectOrPoll1(SelectPtr);
|
||||||
|
void doSelectOrPoll2(SelectPtr);
|
||||||
|
void doSelectOrPoll3(SelectPtr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user