From f09b235fced37bbf4e25ecdd7463c78c29d0d3ef Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Fri, 24 Jan 2025 17:45:46 +0100 Subject: [PATCH] Keep implementation details of fdManager out of header file --- modules/libcom/src/fdmgr/fdManager.cpp | 166 ++++++++++++++++--------- modules/libcom/src/fdmgr/fdManager.h | 60 +-------- 2 files changed, 114 insertions(+), 112 deletions(-) diff --git a/modules/libcom/src/fdmgr/fdManager.cpp b/modules/libcom/src/fdmgr/fdManager.cpp index 7b1b128a2..d71160e1f 100644 --- a/modules/libcom/src/fdmgr/fdManager.cpp +++ b/modules/libcom/src/fdmgr/fdManager.cpp @@ -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 +#if defined(_WIN32) #define poll WSAPoll +#else +#include #endif static const short PollEvents[] = { // must match fdRegType @@ -38,9 +49,55 @@ static const short PollEvents[] = { // must match fdRegType #ifdef FDMGR_USE_SELECT #include -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 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 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(minDelay * mSecPerSec)); int i = 0; #endif @@ -162,20 +211,20 @@ LIBCOM_API void fdManager::process (double delay) tv.tv_sec = static_cast ( minDelay ); tv.tv_usec = static_cast ( (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); } // diff --git a/modules/libcom/src/fdmgr/fdManager.h b/modules/libcom/src/fdmgr/fdManager.h index a323ee1bb..518539bc4 100644 --- a/modules/libcom/src/fdmgr/fdManager.h +++ b/modules/libcom/src/fdmgr/fdManager.h @@ -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 -#if !defined(_WIN32) -#include -#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 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