Keep implementation details of fdManager out of header file
This commit is contained in:
@ -25,9 +25,20 @@
|
||||
#include "fdManager.h"
|
||||
#include "locationException.h"
|
||||
|
||||
#if !defined(FDMGR_USE_POLL) && !defined(FDMGR_USE_SELECT)
|
||||
#if defined(__linux__) || _WIN32_WINNT >= 0x600 || (defined(__rtems__) && !defined(RTEMS_LEGACY_STACK))
|
||||
#define FDMGR_USE_POLL
|
||||
#else
|
||||
#define FDMGR_USE_SELECT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef FDMGR_USE_POLL
|
||||
#ifdef _WIN32
|
||||
#include <vector>
|
||||
#if defined(_WIN32)
|
||||
#define poll WSAPoll
|
||||
#else
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
static const short PollEvents[] = { // must match fdRegType
|
||||
@ -38,9 +49,55 @@ static const short PollEvents[] = { // must match fdRegType
|
||||
|
||||
#ifdef FDMGR_USE_SELECT
|
||||
#include <algorithm>
|
||||
using std :: max;
|
||||
#endif
|
||||
|
||||
struct fdManagerPrivate {
|
||||
tsDLList < fdReg > regList;
|
||||
tsDLList < fdReg > activeList;
|
||||
resTable < fdReg, fdRegId > fdTbl;
|
||||
const double sleepQuantum;
|
||||
epicsTimerQueuePassive * pTimerQueue;
|
||||
bool processInProg;
|
||||
|
||||
#ifdef FDMGR_USE_POLL
|
||||
std::vector<struct pollfd> pollfds;
|
||||
#endif
|
||||
|
||||
#ifdef FDMGR_USE_SELECT
|
||||
fd_set fdSets[fdrNEnums];
|
||||
SOCKET maxFD;
|
||||
#endif
|
||||
|
||||
//
|
||||
// Set to fdreg when in call back
|
||||
// and nill otherwise
|
||||
//
|
||||
fdReg * pCBReg;
|
||||
fdManager & owner;
|
||||
|
||||
fdManagerPrivate(fdManager & owner);
|
||||
void lazyInitTimerQueue();
|
||||
};
|
||||
|
||||
fdManagerPrivate::fdManagerPrivate(fdManager & owner) :
|
||||
sleepQuantum(epicsThreadSleepQuantum()),
|
||||
pTimerQueue(0), processInProg(false),
|
||||
pCBReg(0), owner(owner)
|
||||
{}
|
||||
|
||||
inline void fdManagerPrivate::lazyInitTimerQueue ()
|
||||
{
|
||||
if (!pTimerQueue) {
|
||||
pTimerQueue = & epicsTimerQueuePassive::create(owner);
|
||||
}
|
||||
}
|
||||
|
||||
epicsTimer & fdManager::createTimer()
|
||||
{
|
||||
priv->lazyInitTimerQueue();
|
||||
return priv->pTimerQueue->createTimer();
|
||||
}
|
||||
|
||||
fdManager fileDescriptorManager;
|
||||
|
||||
static const unsigned mSecPerSec = 1000u;
|
||||
@ -53,19 +110,15 @@ static const unsigned uSecPerSec = 1000u * mSecPerSec;
|
||||
// will have the same sleep quantum
|
||||
//
|
||||
LIBCOM_API fdManager::fdManager () :
|
||||
sleepQuantum ( epicsThreadSleepQuantum () ),
|
||||
pTimerQueue ( 0 ), processInProg ( false ),
|
||||
#ifdef FDMGR_USE_SELECT
|
||||
fdSetsPtr ( new fd_set [fdrNEnums] ), maxFD ( 0 ),
|
||||
#endif
|
||||
pCBReg ( 0 )
|
||||
priv(new fdManagerPrivate(*this))
|
||||
{
|
||||
int status = osiSockAttach ();
|
||||
assert (status);
|
||||
|
||||
#ifdef FDMGR_USE_SELECT
|
||||
priv->maxFD = 0;
|
||||
for ( size_t i = 0u; i < fdrNEnums; i++ ) {
|
||||
FD_ZERO ( &fdSetsPtr[i] );
|
||||
FD_ZERO(&priv->fdSets[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -77,18 +130,15 @@ LIBCOM_API fdManager::~fdManager()
|
||||
{
|
||||
fdReg *pReg;
|
||||
|
||||
while ( (pReg = this->regList.get()) ) {
|
||||
while ((pReg = priv->regList.get())) {
|
||||
pReg->state = fdReg::limbo;
|
||||
pReg->destroy();
|
||||
}
|
||||
while ( (pReg = this->activeList.get()) ) {
|
||||
while ((pReg = priv->activeList.get())) {
|
||||
pReg->state = fdReg::limbo;
|
||||
pReg->destroy();
|
||||
}
|
||||
delete this->pTimerQueue;
|
||||
#ifdef FDMGR_USE_SELECT
|
||||
delete [] this->fdSetsPtr;
|
||||
#endif
|
||||
delete priv->pTimerQueue;
|
||||
osiSockRelease();
|
||||
}
|
||||
|
||||
@ -97,15 +147,14 @@ LIBCOM_API fdManager::~fdManager()
|
||||
//
|
||||
LIBCOM_API void fdManager::process (double delay)
|
||||
{
|
||||
this->lazyInitTimerQueue ();
|
||||
priv->lazyInitTimerQueue ();
|
||||
|
||||
//
|
||||
// no recursion
|
||||
//
|
||||
if (this->processInProg) {
|
||||
if (priv->processInProg)
|
||||
return;
|
||||
}
|
||||
this->processInProg = true;
|
||||
priv->processInProg = true;
|
||||
|
||||
//
|
||||
// One shot at expired timers prior to going into
|
||||
@ -114,35 +163,35 @@ LIBCOM_API void fdManager::process (double delay)
|
||||
// more than once here so that fd activity get serviced
|
||||
// in a reasonable length of time.
|
||||
//
|
||||
double minDelay = this->pTimerQueue->process(epicsTime::getCurrent());
|
||||
double minDelay = priv->pTimerQueue->process(epicsTime::getCurrent());
|
||||
|
||||
if ( minDelay >= delay ) {
|
||||
minDelay = delay;
|
||||
}
|
||||
|
||||
#ifdef FDMGR_USE_POLL
|
||||
pollfds.clear();
|
||||
priv->pollfds.clear();
|
||||
#endif
|
||||
|
||||
int ioPending = 0;
|
||||
tsDLIter < fdReg > iter = this->regList.firstIter ();
|
||||
tsDLIter<fdReg> iter = priv->regList.firstIter();
|
||||
while ( iter.valid () ) {
|
||||
++ioPending;
|
||||
|
||||
#ifdef FDMGR_USE_POLL
|
||||
#if __cplusplus >= 201100L
|
||||
pollfds.emplace_back(pollfd{.fd = iter->getFD(), .events = PollEvents[iter->getType()]});
|
||||
priv->pollfds.emplace_back(pollfd{.fd = iter->getFD(), .events = PollEvents[iter->getType()]});
|
||||
#else
|
||||
struct pollfd pollfd;
|
||||
pollfd.fd = iter->getFD();
|
||||
pollfd.events = PollEvents[iter->getType()];
|
||||
pollfd.revents = 0;
|
||||
pollfds.push_back(pollfd);
|
||||
priv->pollfds.push_back(pollfd);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef FDMGR_USE_SELECT
|
||||
FD_SET(iter->getFD(), &this->fdSetsPtr[iter->getType()]);
|
||||
FD_SET(iter->getFD(), &priv->fdSets[iter->getType()]);
|
||||
#endif
|
||||
++iter;
|
||||
}
|
||||
@ -152,7 +201,7 @@ LIBCOM_API void fdManager::process (double delay)
|
||||
if (minDelay * mSecPerSec > INT_MAX)
|
||||
minDelay = INT_MAX / mSecPerSec;
|
||||
|
||||
int status = poll(&pollfds.front(), // ancient C++ has no vector.data()
|
||||
int status = poll(&priv->pollfds.front(), // ancient C++ has no vector.data()
|
||||
ioPending, static_cast<int>(minDelay * mSecPerSec));
|
||||
int i = 0;
|
||||
#endif
|
||||
@ -162,20 +211,20 @@ LIBCOM_API void fdManager::process (double delay)
|
||||
tv.tv_sec = static_cast<time_t> ( minDelay );
|
||||
tv.tv_usec = static_cast<long> ( (minDelay-tv.tv_sec) * uSecPerSec );
|
||||
|
||||
fd_set * pReadSet = & this->fdSetsPtr[fdrRead];
|
||||
fd_set * pWriteSet = & this->fdSetsPtr[fdrWrite];
|
||||
fd_set * pExceptSet = & this->fdSetsPtr[fdrException];
|
||||
int status = select (this->maxFD, pReadSet, pWriteSet, pExceptSet, &tv);
|
||||
int status = select(priv->maxFD,
|
||||
&priv->fdSets[fdrRead],
|
||||
&priv->fdSets[fdrWrite],
|
||||
&priv->fdSets[fdrException], &tv);
|
||||
#endif
|
||||
|
||||
this->pTimerQueue->process(epicsTime::getCurrent());
|
||||
priv->pTimerQueue->process(epicsTime::getCurrent());
|
||||
|
||||
if ( status > 0 ) {
|
||||
|
||||
//
|
||||
// Look for activity
|
||||
//
|
||||
iter=this->regList.firstIter ();
|
||||
iter = priv->regList.firstIter ();
|
||||
while ( iter.valid () && status > 0 ) {
|
||||
tsDLIter < fdReg > tmp = iter;
|
||||
tmp++;
|
||||
@ -185,7 +234,8 @@ LIBCOM_API void fdManager::process (double delay)
|
||||
// changed the order of regList and pollfds by now.
|
||||
// But just in case...
|
||||
int isave = i;
|
||||
while (pollfds[i].fd != iter->getFD() || pollfds[i].events != PollEvents[iter->getType()])
|
||||
while (priv->pollfds[i].fd != iter->getFD() ||
|
||||
priv->pollfds[i].events != PollEvents[iter->getType()])
|
||||
{
|
||||
i++; // skip pollfd of removed items
|
||||
if (i >= ioPending) { // skip unknown (inserted?) items
|
||||
@ -197,15 +247,15 @@ LIBCOM_API void fdManager::process (double delay)
|
||||
}
|
||||
if (i >= ioPending) break; // any unhandled item stays in regList for next time
|
||||
|
||||
if (pollfds[i++].revents & PollEvents[iter->getType()]) {
|
||||
if (priv->pollfds[i++].revents & PollEvents[iter->getType()]) {
|
||||
#endif
|
||||
|
||||
#ifdef FDMGR_USE_SELECT
|
||||
if (FD_ISSET(iter->getFD(), &this->fdSetsPtr[iter->getType()])) {
|
||||
FD_CLR(iter->getFD(), &this->fdSetsPtr[iter->getType()]);
|
||||
if (FD_ISSET(iter->getFD(), &priv->fdSets[iter->getType()])) {
|
||||
FD_CLR(iter->getFD(), &priv->fdSets[iter->getType()]);
|
||||
#endif
|
||||
this->regList.remove(*iter);
|
||||
this->activeList.add(*iter);
|
||||
priv->regList.remove(*iter);
|
||||
priv->activeList.add(*iter);
|
||||
iter->state = fdReg::active;
|
||||
status--;
|
||||
}
|
||||
@ -217,7 +267,7 @@ LIBCOM_API void fdManager::process (double delay)
|
||||
// above list while in a "callBack()" routine
|
||||
//
|
||||
fdReg * pReg;
|
||||
while ( (pReg = this->activeList.get()) ) {
|
||||
while ((pReg = priv->activeList.get())) {
|
||||
pReg->state = fdReg::limbo;
|
||||
|
||||
//
|
||||
@ -225,21 +275,21 @@ LIBCOM_API void fdManager::process (double delay)
|
||||
// can detect if it was deleted
|
||||
// during the call back
|
||||
//
|
||||
this->pCBReg = pReg;
|
||||
priv->pCBReg = pReg;
|
||||
pReg->callBack();
|
||||
if (this->pCBReg != NULL) {
|
||||
if (priv->pCBReg != NULL) {
|
||||
//
|
||||
// check only after we see that it is non-null so
|
||||
// that we don't trigger bounds-checker dangling pointer
|
||||
// error
|
||||
//
|
||||
assert (this->pCBReg==pReg);
|
||||
this->pCBReg = 0;
|
||||
assert(priv->pCBReg == pReg);
|
||||
priv->pCBReg = NULL;
|
||||
if (pReg->onceOnly) {
|
||||
pReg->destroy();
|
||||
}
|
||||
else {
|
||||
this->regList.add(*pReg);
|
||||
priv->regList.add(*pReg);
|
||||
pReg->state = fdReg::pending;
|
||||
}
|
||||
}
|
||||
@ -252,7 +302,7 @@ LIBCOM_API void fdManager::process (double delay)
|
||||
// don't depend on flags being properly set if
|
||||
// an error is returned from select
|
||||
for ( size_t i = 0u; i < fdrNEnums; i++ ) {
|
||||
FD_ZERO ( &fdSetsPtr[i] );
|
||||
FD_ZERO(&priv->fdSets[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -282,9 +332,9 @@ LIBCOM_API void fdManager::process (double delay)
|
||||
* of select()
|
||||
*/
|
||||
epicsThreadSleep(minDelay);
|
||||
this->pTimerQueue->process(epicsTime::getCurrent());
|
||||
priv->pTimerQueue->process(epicsTime::getCurrent());
|
||||
}
|
||||
this->processInProg = false;
|
||||
priv->processInProg = false;
|
||||
}
|
||||
|
||||
//
|
||||
@ -336,16 +386,16 @@ void fdRegId::show ( unsigned level ) const
|
||||
void fdManager::installReg (fdReg ®)
|
||||
{
|
||||
#ifdef FDMGR_USE_SELECT
|
||||
this->maxFD = max ( this->maxFD, reg.getFD()+1 );
|
||||
priv->maxFD = std::max(priv->maxFD, reg.getFD()+1);
|
||||
#endif
|
||||
// Most applications will find that it's important to push here to
|
||||
// the front of the list so that transient writes get executed
|
||||
// first allowing incoming read protocol to find that outgoing
|
||||
// buffer space is newly available.
|
||||
this->regList.push ( reg );
|
||||
priv->regList.push(reg);
|
||||
reg.state = fdReg::pending;
|
||||
|
||||
int status = this->fdTbl.add ( reg );
|
||||
int status = priv->fdTbl.add(reg);
|
||||
if ( status != 0 ) {
|
||||
throwWithLocation ( fdInterestSubscriptionAlreadyExits () );
|
||||
}
|
||||
@ -358,7 +408,7 @@ void fdManager::removeReg (fdReg ®In)
|
||||
{
|
||||
fdReg *pItemFound;
|
||||
|
||||
pItemFound = this->fdTbl.remove (regIn);
|
||||
pItemFound = priv->fdTbl.remove(regIn);
|
||||
if (pItemFound!=®In) {
|
||||
errlogPrintf("fdManager::removeReg() bad fd registration object\n");
|
||||
return;
|
||||
@ -368,16 +418,16 @@ void fdManager::removeReg (fdReg ®In)
|
||||
// signal fdManager that the fdReg was deleted
|
||||
// during the call back
|
||||
//
|
||||
if (this->pCBReg == ®In) {
|
||||
this->pCBReg = 0;
|
||||
if (priv->pCBReg == ®In) {
|
||||
priv->pCBReg = NULL;
|
||||
}
|
||||
|
||||
switch (regIn.state) {
|
||||
case fdReg::active:
|
||||
this->activeList.remove (regIn);
|
||||
priv->activeList.remove(regIn);
|
||||
break;
|
||||
case fdReg::pending:
|
||||
this->regList.remove (regIn);
|
||||
priv->regList.remove(regIn);
|
||||
break;
|
||||
case fdReg::limbo:
|
||||
break;
|
||||
@ -390,7 +440,7 @@ void fdManager::removeReg (fdReg ®In)
|
||||
regIn.state = fdReg::limbo;
|
||||
|
||||
#ifdef FDMGR_USE_SELECT
|
||||
FD_CLR(regIn.getFD(), &this->fdSetsPtr[regIn.getType()]);
|
||||
FD_CLR(regIn.getFD(), &priv->fdSets[regIn.getType()]);
|
||||
#endif
|
||||
|
||||
}
|
||||
@ -406,7 +456,7 @@ void fdManager::reschedule ()
|
||||
|
||||
double fdManager::quantum ()
|
||||
{
|
||||
return this->sleepQuantum;
|
||||
return priv->sleepQuantum;
|
||||
}
|
||||
|
||||
//
|
||||
@ -418,7 +468,7 @@ LIBCOM_API fdReg *fdManager::lookUpFD (const SOCKET fd, const fdRegType type)
|
||||
return NULL;
|
||||
}
|
||||
fdRegId id (fd,type);
|
||||
return this->fdTbl.lookup(id);
|
||||
return priv->fdTbl.lookup(id);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -26,21 +26,6 @@
|
||||
#include "osiSock.h"
|
||||
#include "epicsTimer.h"
|
||||
|
||||
#if !defined(FDMGR_USE_POLL) && !defined(FDMGR_USE_SELECT)
|
||||
#if defined(__linux__) || _WIN32_WINNT >= 0x600 || (defined(__rtems__) && !defined(RTEMS_LEGACY_STACK))
|
||||
#define FDMGR_USE_POLL
|
||||
#else
|
||||
#define FDMGR_USE_SELECT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(FDMGR_USE_POLL)
|
||||
#include <vector>
|
||||
#if !defined(_WIN32)
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
enum fdRegType {fdrRead, fdrWrite, fdrException, fdrNEnums};
|
||||
|
||||
//
|
||||
@ -85,49 +70,29 @@ private:
|
||||
//
|
||||
// file descriptor manager
|
||||
//
|
||||
class fdManager : public epicsTimerQueueNotify {
|
||||
class LIBCOM_API fdManager : public epicsTimerQueueNotify {
|
||||
public:
|
||||
//
|
||||
// exceptions
|
||||
//
|
||||
class fdInterestSubscriptionAlreadyExits {};
|
||||
|
||||
LIBCOM_API fdManager ();
|
||||
LIBCOM_API virtual ~fdManager ();
|
||||
LIBCOM_API void process ( double delay ); // delay parameter is in seconds
|
||||
fdManager ();
|
||||
virtual ~fdManager ();
|
||||
void process ( double delay ); // delay parameter is in seconds
|
||||
|
||||
// returns NULL if the fd is unknown
|
||||
LIBCOM_API class fdReg *lookUpFD (const SOCKET fd, const fdRegType type);
|
||||
class fdReg *lookUpFD (const SOCKET fd, const fdRegType type);
|
||||
|
||||
epicsTimer & createTimer ();
|
||||
|
||||
private:
|
||||
tsDLList < fdReg > regList;
|
||||
tsDLList < fdReg > activeList;
|
||||
resTable < fdReg, fdRegId > fdTbl;
|
||||
const double sleepQuantum;
|
||||
epicsTimerQueuePassive * pTimerQueue;
|
||||
bool processInProg;
|
||||
struct fdManagerPrivate* priv;
|
||||
|
||||
#ifdef FDMGR_USE_POLL
|
||||
std::vector<struct pollfd> pollfds;
|
||||
#endif
|
||||
|
||||
#ifdef FDMGR_USE_SELECT
|
||||
fd_set * fdSetsPtr;
|
||||
SOCKET maxFD;
|
||||
#endif
|
||||
|
||||
//
|
||||
// Set to fdreg when in call back
|
||||
// and nill otherwise
|
||||
//
|
||||
fdReg * pCBReg;
|
||||
void reschedule ();
|
||||
double quantum ();
|
||||
void installReg (fdReg ®);
|
||||
void removeReg (fdReg ®);
|
||||
void lazyInitTimerQueue ();
|
||||
fdManager ( const fdManager & );
|
||||
fdManager & operator = ( const fdManager & );
|
||||
friend class fdReg;
|
||||
@ -210,18 +175,5 @@ inline resTableIndex fdRegId::hash () const
|
||||
return hashid;
|
||||
}
|
||||
|
||||
inline void fdManager::lazyInitTimerQueue ()
|
||||
{
|
||||
if ( ! this->pTimerQueue ) {
|
||||
this->pTimerQueue = & epicsTimerQueuePassive::create ( *this );
|
||||
}
|
||||
}
|
||||
|
||||
inline epicsTimer & fdManager::createTimer ()
|
||||
{
|
||||
this->lazyInitTimerQueue ();
|
||||
return this->pTimerQueue->createTimer ();
|
||||
}
|
||||
|
||||
#endif // fdManagerH_included
|
||||
|
||||
|
Reference in New Issue
Block a user