From 409b476b2b893172ab02cdb267964fbda740d353 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Thu, 5 Aug 1999 16:08:00 +0000 Subject: [PATCH] updated to reflect resource table API changes --- src/libCom/fdManager.cc | 230 ++++++++++++--------------------- src/libCom/fdManager.h | 160 ++++++++++++----------- src/libCom/fdmgr/fdManager.cpp | 230 ++++++++++++--------------------- src/libCom/fdmgr/fdManager.h | 160 ++++++++++++----------- 4 files changed, 346 insertions(+), 434 deletions(-) diff --git a/src/libCom/fdManager.cc b/src/libCom/fdManager.cc index 0edccbe4e..4fdb7e199 100644 --- a/src/libCom/fdManager.cc +++ b/src/libCom/fdManager.cc @@ -1,52 +1,38 @@ -// -// $Id$ -// -// -// $Log$ -// Revision 1.14 1998/06/16 02:06:32 jhill -// lazy init sock lib when its a static build & recoverfrom select differences in winsock -// -// Revision 1.13 1998/05/29 20:22:44 jhill -// made hashing routine portable -// -// Revision 1.12 1998/02/05 21:12:09 jhill -// removed questionable inline -// -// Revision 1.11 1997/08/05 00:37:00 jhill -// removed warnings -// -// Revision 1.10 1997/06/25 05:45:49 jhill -// cleaned up pc port -// -// Revision 1.9 1997/06/13 09:39:09 jhill -// fixed warnings -// -// Revision 1.8 1997/05/29 21:37:38 tang -// add ifdef for select call to support HP-UX -// -// Revision 1.7 1997/05/27 14:53:11 tang -// fd_set cast in select for both Hp and Sun -// -// Revision 1.6 1997/05/08 19:49:12 tang -// added int * cast in select for HP port compatibility -// -// Revision 1.5 1997/04/23 17:22:57 jhill -// fixed WIN32 DLL symbol exports -// -// Revision 1.4 1997/04/10 19:45:33 jhill -// API changes and include with not <> -// -// Revision 1.3 1996/11/02 02:04:42 jhill -// fixed several subtle bugs -// -// Revision 1.2 1996/09/04 21:50:16 jhill -// added hashed fd to fdi convert -// -// Revision 1.1 1996/08/13 22:48:23 jhill -// dfMgr =>fdManager -// -// +/* + * $Id$ + * + * File descriptor management C++ class library + * (for multiplexing IO in a single threaded environment) + * + * Author Jeffrey O. Hill + * johill@lanl.gov + * 505 665 1831 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + * + * + * + */ // // @@ -67,8 +53,9 @@ #define epicsExportSharedSymbols #define instantiateRecourceLib #include "osiTimer.h" -#include "fdManager.h" #include "osiSleep.h" +#include "tsMinMax.h" +#include "fdManager.h" #include "bsdSocketResource.h" // @@ -83,7 +70,6 @@ // This explicitly instantiates the template class's member // functions used by fdManager // - // // instantiated by "fdManager fileDescriptorManager;" statement below? // (according to ms vis C++) // @@ -95,7 +81,8 @@ epicsShareDef fdManager fileDescriptorManager; // // fdManager::fdManager() // -epicsShareFunc fdManager::fdManager() +epicsShareFunc fdManager::fdManager() : + fdTbl (1<maxFD = 0; this->processInProg = 0u; this->pCBReg = 0; - // - // should throw an exception here - // when most compilers are implementing - // exceptions - // - assert (this->fdTbl.init(0x100)>=0); } // @@ -123,11 +104,11 @@ epicsShareFunc fdManager::~fdManager() fdReg *pReg; while ( (pReg = this->regList.get()) ) { - pReg->state = fdrLimbo; + pReg->state = fdReg::limbo; pReg->destroy(); } while ( (pReg = this->activeList.get()) ) { - pReg->state = fdrLimbo; + pReg->state = fdReg::limbo; pReg->destroy(); } bsdSockRelease(); @@ -136,13 +117,10 @@ epicsShareFunc fdManager::~fdManager() // // fdManager::process() // -epicsShareFunc void fdManager::process (const osiTime &delay) +epicsShareFunc void fdManager::process (double delay) { - static const tsDLIterBD eol; // end of list - tsDLIterBD iter; - tsDLIterBD tmp; - osiTime minDelay; - osiTime zeroDelay; + static const tsDLIterBD eol (0); // end of list + double minDelay; fdReg *pReg; struct timeval tv; int status; @@ -163,23 +141,25 @@ epicsShareFunc void fdManager::process (const osiTime &delay) // more than once here so that fd activity get serviced // in a reasonable length of time. // - minDelay = staticTimerQueue.delayToFirstExpire(); - if (zeroDelay>=minDelay) { - staticTimerQueue.process(); - minDelay = staticTimerQueue.delayToFirstExpire(); + minDelay = osiDefaultTimerQueue.delayToFirstExpire(); + if (minDelay<=0.0) { + osiDefaultTimerQueue.process(); + minDelay = osiDefaultTimerQueue.delayToFirstExpire(); } if (minDelay>=delay) { minDelay = delay; } - for (iter=this->regList.first(); iter!=eol; ++iter) { + tsDLIterBD iter (this->regList.first()); + while (iter!=eol) { FD_SET(iter->getFD(), &this->fdSets[iter->getType()]); ioPending = 1; + ++iter; } - tv.tv_sec = minDelay.getSecTruncToLong (); - tv.tv_usec = minDelay.getUSecTruncToLong (); + tv.tv_sec = static_cast (minDelay); + tv.tv_usec = static_cast ((minDelay-tv.tv_sec)*osiTime::uSecPerSec); /* * win32 requires this (others will @@ -198,10 +178,10 @@ epicsShareFunc void fdManager::process (const osiTime &delay) } else { status = select (this->maxFD, &this->fdSets[fdrRead], - &this->fdSets[fdrWrite], &this->fdSets[fdrExcp], &tv); + &this->fdSets[fdrWrite], &this->fdSets[fdrException], &tv); } - staticTimerQueue.process(); + osiDefaultTimerQueue.process(); if (status==0) { this->processInProg = 0; return; @@ -223,13 +203,13 @@ epicsShareFunc void fdManager::process (const osiTime &delay) // iter=this->regList.first(); while (iter!=eol) { - tmp = iter; + tsDLIterBD tmp = iter; tmp++; if (FD_ISSET(iter->getFD(), &this->fdSets[iter->getType()])) { FD_CLR(iter->getFD(), &this->fdSets[iter->getType()]); this->regList.remove(*iter); this->activeList.add(*iter); - iter->state = fdrActive; + iter->state = fdReg::active; } iter=tmp; } @@ -239,10 +219,10 @@ epicsShareFunc void fdManager::process (const osiTime &delay) // above list while in a "callBack()" routine // while ( (pReg = this->activeList.get()) ) { - pReg->state = fdrLimbo; + pReg->state = fdReg::limbo; // - // Tag current reg so that we + // Tag current fdReg so that we // can detect if it was deleted // during the call back // @@ -261,7 +241,7 @@ epicsShareFunc void fdManager::process (const osiTime &delay) } else { this->regList.add(*pReg); - pReg->state = fdrPending; + pReg->state = fdReg::pending; } } } @@ -282,7 +262,7 @@ epicsShareFunc void fdReg::destroy() // epicsShareFunc fdReg::~fdReg() { - fileDescriptorManager.removeReg(*this); + this->manager.removeReg(*this); } // @@ -311,66 +291,27 @@ void fdRegId::show(unsigned level) const } // -// fdRegId::resourceHash() -// -resTableIndex fdRegId::resourceHash (unsigned) const -{ - resTableIndex hashid = (unsigned) this->fd; - - // - // This assumes worst case hash table index width of 1 bit. - // We will iterate this loop 5 times on a 32 bit architecture. - // - // A good optimizer will unroll this loop? - // Experiments using the microsoft compiler show that this isnt - // slower than switching on the architecture size and urolling the - // loop explicitly (that solution has resulted in portability - // problems in the past). - // - for (unsigned i=(CHAR_BIT*sizeof(unsigned))/2u; i>0u; i >>= 1u) { - hashid ^= (hashid>>i); - } - - // - // evenly distribute based on the type of interest also - // - hashid ^= this->type; - - // - // the result here is always masked to the - // proper size after it is returned to the resource class - // - return hashid; -} - -// -// fdManager::installReg() +// fdManager::installReg () // epicsShareFunc void fdManager::installReg (fdReg ®) { - int status; - - this->maxFD = fdManagerMaxInt(this->maxFD, reg.getFD()+1); - this->regList.add(reg); - reg.state = fdrPending; - status = this->fdTbl.add(reg); - if (status) { - fprintf (stderr, - "**** Warning - duplicate fdReg object\n"); - fprintf (stderr, - "**** will not be seen by fdManager::lookUpFD()\n"); - } + this->maxFD = tsMax(this->maxFD, reg.getFD()+1); + this->regList.add (reg); + reg.state = fdReg::pending; + if (this->fdTbl.add (reg)!=0) { + throw fdInterestSubscriptionAlreadyExits(); + } } // -// fdManager::removeReg() +// fdManager::removeReg () // -void fdManager::removeReg(fdReg ®) +void fdManager::removeReg (fdReg ®In) { fdReg *pItemFound; - pItemFound = this->fdTbl.remove(reg); - if (pItemFound!=®) { + pItemFound = this->fdTbl.remove (regIn); + if (pItemFound!=®In) { fprintf(stderr, "fdManager::removeReg() bad fd registration object\n"); return; @@ -380,18 +321,18 @@ void fdManager::removeReg(fdReg ®) // signal fdManager that the fdReg was deleted // during the call back // - if (this->pCBReg == ®) { + if (this->pCBReg == ®In) { this->pCBReg = 0; } - switch (reg.state) { - case fdrActive: - this->activeList.remove(reg); + switch (regIn.state) { + case fdReg::active: + this->activeList.remove (regIn); break; - case fdrPending: - this->regList.remove(reg); + case fdReg::pending: + this->regList.remove (regIn); break; - case fdrLimbo: + case fdReg::limbo: break; default: // @@ -399,15 +340,15 @@ void fdManager::removeReg(fdReg ®) // assert(0); } - reg.state = fdrLimbo; + regIn.state = fdReg::limbo; - FD_CLR(reg.getFD(), &this->fdSets[reg.getType()]); + FD_CLR(regIn.getFD(), &this->fdSets[regIn.getType()]); } // // lookUpFD() // -epicsShareFunc fdReg *fdManager::lookUpFD(const SOCKET fd, const fdRegType type) +epicsShareFunc fdReg *fdManager::lookUpFD (const SOCKET fd, const fdRegType type) { if (fd<0) { return NULL; @@ -420,13 +361,14 @@ epicsShareFunc fdReg *fdManager::lookUpFD(const SOCKET fd, const fdRegType type) // fdReg::fdReg() // fdReg::fdReg (const SOCKET fdIn, const fdRegType typIn, - const unsigned onceOnlyIn) : - fdRegId(fdIn,typIn), state(fdrLimbo), onceOnly(onceOnlyIn) -{ + const bool onceOnlyIn, fdManager &managerIn) : + fdRegId (fdIn,typIn), state (limbo), + onceOnly (onceOnlyIn), manager (managerIn) +{ if (!FD_IN_FDSET(fdIn)) { fprintf (stderr, "%s: fd > FD_SETSIZE ignored\n", __FILE__); return; } - fileDescriptorManager.installReg(*this); + this->manager.installReg (*this); } diff --git a/src/libCom/fdManager.h b/src/libCom/fdManager.h index 65edc39d5..922b0b145 100644 --- a/src/libCom/fdManager.h +++ b/src/libCom/fdManager.h @@ -1,8 +1,8 @@ /* * $Id$ * - * File descriptor management C++ class library - * (for multiplexing IO in a single threaded environment) + * File descriptor management C++ class library + * (for multiplexing IO in a single threaded environment) * * Author Jeffrey O. Hill * johill@lanl.gov @@ -30,96 +30,93 @@ * Argonne National Laboratory * * - * History - * $Log$ - * Revision 1.10 1998/10/23 19:47:12 jhill - * fixed inline is too big warning - * - * Revision 1.9 1998/06/16 02:04:07 jhill - * fixed spelling - * - * Revision 1.8 1998/02/05 21:12:10 jhill - * removed questionable inline - * - * Revision 1.7 1997/08/05 00:37:01 jhill - * removed warnings - * - * Revision 1.6 1997/06/25 05:45:50 jhill - * cleaned up pc port - * - * Revision 1.5 1997/04/23 17:22:58 jhill - * fixed WIN32 DLL symbol exports - * - * Revision 1.4 1997/04/10 19:45:38 jhill - * API changes and include with not <> - * - * Revision 1.3 1996/11/02 02:04:41 jhill - * fixed several subtle bugs - * - * Revision 1.2 1996/09/04 21:50:16 jhill - * added hashed fd to fdi convert - * - * Revision 1.1 1996/08/13 22:48:21 jhill - * dfMgr =>fdManager - * * */ #ifndef fdManagerH_included #define fdManagerH_included -#include - #include "shareLib.h" // reset share lib defines #include "tsDLList.h" #include "resourceLib.h" #include "osiTime.h" #include "osiSock.h" -enum fdRegType {fdrRead, fdrWrite, fdrExcp, fdRegTypeNElem}; -enum fdRegState {fdrActive, fdrPending, fdrLimbo}; +static const unsigned hashTableIndexBits = 8; +enum fdRegType {fdrRead, fdrWrite, fdrException, fdrNEnums}; + +// +// fdRegId +// +// file descriptor interest id +// class epicsShareClass fdRegId { public: + fdRegId (const SOCKET fdIn, const fdRegType typeIn) : fd(fdIn), type(typeIn) {} - SOCKET getFD () + SOCKET getFD () const { return this->fd; } - fdRegType getType () + fdRegType getType () const { return this->type; } - int operator == (const fdRegId &idIn) + bool operator == (const fdRegId &idIn) const { return this->fd == idIn.fd && this->type==idIn.type; } - resTableIndex resourceHash (unsigned nBitsId) const; + resTableIndex hash (unsigned nBitsId) const; + + // + // this must allow at least enough bits for all states + // in type "fdRegType". The actual size of the table + // is used because it improves performance. + // + static unsigned minIndexBitWidth () + { + return hashTableIndexBits; + } + + static unsigned maxIndexBitWidth () + { + return sizeof(SOCKET)*CHAR_BIT; + } virtual void show (unsigned level) const; private: - const SOCKET fd; - const fdRegType type; + const SOCKET fd; + const fdRegType type; }; +class fdManager; + +// +// default file descriptor manager +// +epicsShareExtern fdManager fileDescriptorManager; + // // fdReg +// // file descriptor registration // -class fdReg : public tsDLNode, public fdRegId, public tsSLNode { - friend class fdManager; +class fdReg : public fdRegId, private tsDLNode, private tsSLNode { + friend class fdManager; public: - epicsShareFunc fdReg (const SOCKET fdIn, const fdRegType typ, - const unsigned onceOnly=0); + + epicsShareFunc fdReg (const SOCKET fdIn, const fdRegType type, + const bool onceOnly=false, fdManager &manager = fileDescriptorManager); epicsShareFunc virtual ~fdReg (); - epicsShareFunc virtual void show(unsigned level) const; + epicsShareFunc virtual void show (unsigned level) const; // // Called by the file descriptor manager: @@ -131,7 +128,9 @@ public: // fdReg::destroy() does a "delete this" // epicsShareFunc virtual void destroy (); + private: + enum state {active, pending, limbo}; // // called when there is activity on the fd @@ -142,57 +141,72 @@ private: // epicsShareFunc virtual void callBack ()=0; - unsigned char state; // fdRegState goes here - unsigned char onceOnly; + unsigned char state; // state enums go here + unsigned char onceOnly; + fdManager &manager; }; // // fdManager +// // file descriptor manager // class fdManager { friend class fdReg; public: + // + // exceptions + // + class fdInterestSubscriptionAlreadyExits {}; + epicsShareFunc fdManager(); epicsShareFunc ~fdManager(); - epicsShareFunc void process (const osiTime &delay); + epicsShareFunc void process (double delay); // delay parameter is in seconds // // returns NULL if the fd is unknown // - epicsShareFunc fdReg *lookUpFD(const SOCKET fd, const fdRegType type); -private: - tsDLList regList; - tsDLList activeList; - resTable fdTbl; - fd_set fdSets[fdRegTypeNElem]; + epicsShareFunc fdReg *lookUpFD(const SOCKET fd, const fdRegType type); - int maxFD; - unsigned processInProg; +private: + tsDLList regList; + tsDLList activeList; + resTable fdTbl; + fd_set fdSets[fdrNEnums]; + + SOCKET maxFD; + unsigned processInProg; // // Set to fdreg when in call back // and nill otherwise // - fdReg *pCBReg; + fdReg *pCBReg; epicsShareFunc void installReg (fdReg ®); - void removeReg (fdReg ®); + epicsShareFunc void removeReg (fdReg ®); }; -epicsShareExtern fdManager fileDescriptorManager; - // -// fdManagerMaxInt () +// fdRegId::hash() // -inline int fdManagerMaxInt (int a, int b) +inline resTableIndex fdRegId::hash (unsigned) const { - if (a>b) { - return a; - } - else { - return b; - } + resTableIndex hashid; + + hashid = resTableIntHash + (this->fd); + + // + // also evenly distribute based on the type of fdRegType + // + hashid ^= this->type; + + // + // the result here is always masked to the + // proper size after it is returned to the resource class + // + return hashid; } - + #endif // fdManagerH_included diff --git a/src/libCom/fdmgr/fdManager.cpp b/src/libCom/fdmgr/fdManager.cpp index 0edccbe4e..4fdb7e199 100644 --- a/src/libCom/fdmgr/fdManager.cpp +++ b/src/libCom/fdmgr/fdManager.cpp @@ -1,52 +1,38 @@ -// -// $Id$ -// -// -// $Log$ -// Revision 1.14 1998/06/16 02:06:32 jhill -// lazy init sock lib when its a static build & recoverfrom select differences in winsock -// -// Revision 1.13 1998/05/29 20:22:44 jhill -// made hashing routine portable -// -// Revision 1.12 1998/02/05 21:12:09 jhill -// removed questionable inline -// -// Revision 1.11 1997/08/05 00:37:00 jhill -// removed warnings -// -// Revision 1.10 1997/06/25 05:45:49 jhill -// cleaned up pc port -// -// Revision 1.9 1997/06/13 09:39:09 jhill -// fixed warnings -// -// Revision 1.8 1997/05/29 21:37:38 tang -// add ifdef for select call to support HP-UX -// -// Revision 1.7 1997/05/27 14:53:11 tang -// fd_set cast in select for both Hp and Sun -// -// Revision 1.6 1997/05/08 19:49:12 tang -// added int * cast in select for HP port compatibility -// -// Revision 1.5 1997/04/23 17:22:57 jhill -// fixed WIN32 DLL symbol exports -// -// Revision 1.4 1997/04/10 19:45:33 jhill -// API changes and include with not <> -// -// Revision 1.3 1996/11/02 02:04:42 jhill -// fixed several subtle bugs -// -// Revision 1.2 1996/09/04 21:50:16 jhill -// added hashed fd to fdi convert -// -// Revision 1.1 1996/08/13 22:48:23 jhill -// dfMgr =>fdManager -// -// +/* + * $Id$ + * + * File descriptor management C++ class library + * (for multiplexing IO in a single threaded environment) + * + * Author Jeffrey O. Hill + * johill@lanl.gov + * 505 665 1831 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + * + * + * + */ // // @@ -67,8 +53,9 @@ #define epicsExportSharedSymbols #define instantiateRecourceLib #include "osiTimer.h" -#include "fdManager.h" #include "osiSleep.h" +#include "tsMinMax.h" +#include "fdManager.h" #include "bsdSocketResource.h" // @@ -83,7 +70,6 @@ // This explicitly instantiates the template class's member // functions used by fdManager // - // // instantiated by "fdManager fileDescriptorManager;" statement below? // (according to ms vis C++) // @@ -95,7 +81,8 @@ epicsShareDef fdManager fileDescriptorManager; // // fdManager::fdManager() // -epicsShareFunc fdManager::fdManager() +epicsShareFunc fdManager::fdManager() : + fdTbl (1<maxFD = 0; this->processInProg = 0u; this->pCBReg = 0; - // - // should throw an exception here - // when most compilers are implementing - // exceptions - // - assert (this->fdTbl.init(0x100)>=0); } // @@ -123,11 +104,11 @@ epicsShareFunc fdManager::~fdManager() fdReg *pReg; while ( (pReg = this->regList.get()) ) { - pReg->state = fdrLimbo; + pReg->state = fdReg::limbo; pReg->destroy(); } while ( (pReg = this->activeList.get()) ) { - pReg->state = fdrLimbo; + pReg->state = fdReg::limbo; pReg->destroy(); } bsdSockRelease(); @@ -136,13 +117,10 @@ epicsShareFunc fdManager::~fdManager() // // fdManager::process() // -epicsShareFunc void fdManager::process (const osiTime &delay) +epicsShareFunc void fdManager::process (double delay) { - static const tsDLIterBD eol; // end of list - tsDLIterBD iter; - tsDLIterBD tmp; - osiTime minDelay; - osiTime zeroDelay; + static const tsDLIterBD eol (0); // end of list + double minDelay; fdReg *pReg; struct timeval tv; int status; @@ -163,23 +141,25 @@ epicsShareFunc void fdManager::process (const osiTime &delay) // more than once here so that fd activity get serviced // in a reasonable length of time. // - minDelay = staticTimerQueue.delayToFirstExpire(); - if (zeroDelay>=minDelay) { - staticTimerQueue.process(); - minDelay = staticTimerQueue.delayToFirstExpire(); + minDelay = osiDefaultTimerQueue.delayToFirstExpire(); + if (minDelay<=0.0) { + osiDefaultTimerQueue.process(); + minDelay = osiDefaultTimerQueue.delayToFirstExpire(); } if (minDelay>=delay) { minDelay = delay; } - for (iter=this->regList.first(); iter!=eol; ++iter) { + tsDLIterBD iter (this->regList.first()); + while (iter!=eol) { FD_SET(iter->getFD(), &this->fdSets[iter->getType()]); ioPending = 1; + ++iter; } - tv.tv_sec = minDelay.getSecTruncToLong (); - tv.tv_usec = minDelay.getUSecTruncToLong (); + tv.tv_sec = static_cast (minDelay); + tv.tv_usec = static_cast ((minDelay-tv.tv_sec)*osiTime::uSecPerSec); /* * win32 requires this (others will @@ -198,10 +178,10 @@ epicsShareFunc void fdManager::process (const osiTime &delay) } else { status = select (this->maxFD, &this->fdSets[fdrRead], - &this->fdSets[fdrWrite], &this->fdSets[fdrExcp], &tv); + &this->fdSets[fdrWrite], &this->fdSets[fdrException], &tv); } - staticTimerQueue.process(); + osiDefaultTimerQueue.process(); if (status==0) { this->processInProg = 0; return; @@ -223,13 +203,13 @@ epicsShareFunc void fdManager::process (const osiTime &delay) // iter=this->regList.first(); while (iter!=eol) { - tmp = iter; + tsDLIterBD tmp = iter; tmp++; if (FD_ISSET(iter->getFD(), &this->fdSets[iter->getType()])) { FD_CLR(iter->getFD(), &this->fdSets[iter->getType()]); this->regList.remove(*iter); this->activeList.add(*iter); - iter->state = fdrActive; + iter->state = fdReg::active; } iter=tmp; } @@ -239,10 +219,10 @@ epicsShareFunc void fdManager::process (const osiTime &delay) // above list while in a "callBack()" routine // while ( (pReg = this->activeList.get()) ) { - pReg->state = fdrLimbo; + pReg->state = fdReg::limbo; // - // Tag current reg so that we + // Tag current fdReg so that we // can detect if it was deleted // during the call back // @@ -261,7 +241,7 @@ epicsShareFunc void fdManager::process (const osiTime &delay) } else { this->regList.add(*pReg); - pReg->state = fdrPending; + pReg->state = fdReg::pending; } } } @@ -282,7 +262,7 @@ epicsShareFunc void fdReg::destroy() // epicsShareFunc fdReg::~fdReg() { - fileDescriptorManager.removeReg(*this); + this->manager.removeReg(*this); } // @@ -311,66 +291,27 @@ void fdRegId::show(unsigned level) const } // -// fdRegId::resourceHash() -// -resTableIndex fdRegId::resourceHash (unsigned) const -{ - resTableIndex hashid = (unsigned) this->fd; - - // - // This assumes worst case hash table index width of 1 bit. - // We will iterate this loop 5 times on a 32 bit architecture. - // - // A good optimizer will unroll this loop? - // Experiments using the microsoft compiler show that this isnt - // slower than switching on the architecture size and urolling the - // loop explicitly (that solution has resulted in portability - // problems in the past). - // - for (unsigned i=(CHAR_BIT*sizeof(unsigned))/2u; i>0u; i >>= 1u) { - hashid ^= (hashid>>i); - } - - // - // evenly distribute based on the type of interest also - // - hashid ^= this->type; - - // - // the result here is always masked to the - // proper size after it is returned to the resource class - // - return hashid; -} - -// -// fdManager::installReg() +// fdManager::installReg () // epicsShareFunc void fdManager::installReg (fdReg ®) { - int status; - - this->maxFD = fdManagerMaxInt(this->maxFD, reg.getFD()+1); - this->regList.add(reg); - reg.state = fdrPending; - status = this->fdTbl.add(reg); - if (status) { - fprintf (stderr, - "**** Warning - duplicate fdReg object\n"); - fprintf (stderr, - "**** will not be seen by fdManager::lookUpFD()\n"); - } + this->maxFD = tsMax(this->maxFD, reg.getFD()+1); + this->regList.add (reg); + reg.state = fdReg::pending; + if (this->fdTbl.add (reg)!=0) { + throw fdInterestSubscriptionAlreadyExits(); + } } // -// fdManager::removeReg() +// fdManager::removeReg () // -void fdManager::removeReg(fdReg ®) +void fdManager::removeReg (fdReg ®In) { fdReg *pItemFound; - pItemFound = this->fdTbl.remove(reg); - if (pItemFound!=®) { + pItemFound = this->fdTbl.remove (regIn); + if (pItemFound!=®In) { fprintf(stderr, "fdManager::removeReg() bad fd registration object\n"); return; @@ -380,18 +321,18 @@ void fdManager::removeReg(fdReg ®) // signal fdManager that the fdReg was deleted // during the call back // - if (this->pCBReg == ®) { + if (this->pCBReg == ®In) { this->pCBReg = 0; } - switch (reg.state) { - case fdrActive: - this->activeList.remove(reg); + switch (regIn.state) { + case fdReg::active: + this->activeList.remove (regIn); break; - case fdrPending: - this->regList.remove(reg); + case fdReg::pending: + this->regList.remove (regIn); break; - case fdrLimbo: + case fdReg::limbo: break; default: // @@ -399,15 +340,15 @@ void fdManager::removeReg(fdReg ®) // assert(0); } - reg.state = fdrLimbo; + regIn.state = fdReg::limbo; - FD_CLR(reg.getFD(), &this->fdSets[reg.getType()]); + FD_CLR(regIn.getFD(), &this->fdSets[regIn.getType()]); } // // lookUpFD() // -epicsShareFunc fdReg *fdManager::lookUpFD(const SOCKET fd, const fdRegType type) +epicsShareFunc fdReg *fdManager::lookUpFD (const SOCKET fd, const fdRegType type) { if (fd<0) { return NULL; @@ -420,13 +361,14 @@ epicsShareFunc fdReg *fdManager::lookUpFD(const SOCKET fd, const fdRegType type) // fdReg::fdReg() // fdReg::fdReg (const SOCKET fdIn, const fdRegType typIn, - const unsigned onceOnlyIn) : - fdRegId(fdIn,typIn), state(fdrLimbo), onceOnly(onceOnlyIn) -{ + const bool onceOnlyIn, fdManager &managerIn) : + fdRegId (fdIn,typIn), state (limbo), + onceOnly (onceOnlyIn), manager (managerIn) +{ if (!FD_IN_FDSET(fdIn)) { fprintf (stderr, "%s: fd > FD_SETSIZE ignored\n", __FILE__); return; } - fileDescriptorManager.installReg(*this); + this->manager.installReg (*this); } diff --git a/src/libCom/fdmgr/fdManager.h b/src/libCom/fdmgr/fdManager.h index 65edc39d5..922b0b145 100644 --- a/src/libCom/fdmgr/fdManager.h +++ b/src/libCom/fdmgr/fdManager.h @@ -1,8 +1,8 @@ /* * $Id$ * - * File descriptor management C++ class library - * (for multiplexing IO in a single threaded environment) + * File descriptor management C++ class library + * (for multiplexing IO in a single threaded environment) * * Author Jeffrey O. Hill * johill@lanl.gov @@ -30,96 +30,93 @@ * Argonne National Laboratory * * - * History - * $Log$ - * Revision 1.10 1998/10/23 19:47:12 jhill - * fixed inline is too big warning - * - * Revision 1.9 1998/06/16 02:04:07 jhill - * fixed spelling - * - * Revision 1.8 1998/02/05 21:12:10 jhill - * removed questionable inline - * - * Revision 1.7 1997/08/05 00:37:01 jhill - * removed warnings - * - * Revision 1.6 1997/06/25 05:45:50 jhill - * cleaned up pc port - * - * Revision 1.5 1997/04/23 17:22:58 jhill - * fixed WIN32 DLL symbol exports - * - * Revision 1.4 1997/04/10 19:45:38 jhill - * API changes and include with not <> - * - * Revision 1.3 1996/11/02 02:04:41 jhill - * fixed several subtle bugs - * - * Revision 1.2 1996/09/04 21:50:16 jhill - * added hashed fd to fdi convert - * - * Revision 1.1 1996/08/13 22:48:21 jhill - * dfMgr =>fdManager - * * */ #ifndef fdManagerH_included #define fdManagerH_included -#include - #include "shareLib.h" // reset share lib defines #include "tsDLList.h" #include "resourceLib.h" #include "osiTime.h" #include "osiSock.h" -enum fdRegType {fdrRead, fdrWrite, fdrExcp, fdRegTypeNElem}; -enum fdRegState {fdrActive, fdrPending, fdrLimbo}; +static const unsigned hashTableIndexBits = 8; +enum fdRegType {fdrRead, fdrWrite, fdrException, fdrNEnums}; + +// +// fdRegId +// +// file descriptor interest id +// class epicsShareClass fdRegId { public: + fdRegId (const SOCKET fdIn, const fdRegType typeIn) : fd(fdIn), type(typeIn) {} - SOCKET getFD () + SOCKET getFD () const { return this->fd; } - fdRegType getType () + fdRegType getType () const { return this->type; } - int operator == (const fdRegId &idIn) + bool operator == (const fdRegId &idIn) const { return this->fd == idIn.fd && this->type==idIn.type; } - resTableIndex resourceHash (unsigned nBitsId) const; + resTableIndex hash (unsigned nBitsId) const; + + // + // this must allow at least enough bits for all states + // in type "fdRegType". The actual size of the table + // is used because it improves performance. + // + static unsigned minIndexBitWidth () + { + return hashTableIndexBits; + } + + static unsigned maxIndexBitWidth () + { + return sizeof(SOCKET)*CHAR_BIT; + } virtual void show (unsigned level) const; private: - const SOCKET fd; - const fdRegType type; + const SOCKET fd; + const fdRegType type; }; +class fdManager; + +// +// default file descriptor manager +// +epicsShareExtern fdManager fileDescriptorManager; + // // fdReg +// // file descriptor registration // -class fdReg : public tsDLNode, public fdRegId, public tsSLNode { - friend class fdManager; +class fdReg : public fdRegId, private tsDLNode, private tsSLNode { + friend class fdManager; public: - epicsShareFunc fdReg (const SOCKET fdIn, const fdRegType typ, - const unsigned onceOnly=0); + + epicsShareFunc fdReg (const SOCKET fdIn, const fdRegType type, + const bool onceOnly=false, fdManager &manager = fileDescriptorManager); epicsShareFunc virtual ~fdReg (); - epicsShareFunc virtual void show(unsigned level) const; + epicsShareFunc virtual void show (unsigned level) const; // // Called by the file descriptor manager: @@ -131,7 +128,9 @@ public: // fdReg::destroy() does a "delete this" // epicsShareFunc virtual void destroy (); + private: + enum state {active, pending, limbo}; // // called when there is activity on the fd @@ -142,57 +141,72 @@ private: // epicsShareFunc virtual void callBack ()=0; - unsigned char state; // fdRegState goes here - unsigned char onceOnly; + unsigned char state; // state enums go here + unsigned char onceOnly; + fdManager &manager; }; // // fdManager +// // file descriptor manager // class fdManager { friend class fdReg; public: + // + // exceptions + // + class fdInterestSubscriptionAlreadyExits {}; + epicsShareFunc fdManager(); epicsShareFunc ~fdManager(); - epicsShareFunc void process (const osiTime &delay); + epicsShareFunc void process (double delay); // delay parameter is in seconds // // returns NULL if the fd is unknown // - epicsShareFunc fdReg *lookUpFD(const SOCKET fd, const fdRegType type); -private: - tsDLList regList; - tsDLList activeList; - resTable fdTbl; - fd_set fdSets[fdRegTypeNElem]; + epicsShareFunc fdReg *lookUpFD(const SOCKET fd, const fdRegType type); - int maxFD; - unsigned processInProg; +private: + tsDLList regList; + tsDLList activeList; + resTable fdTbl; + fd_set fdSets[fdrNEnums]; + + SOCKET maxFD; + unsigned processInProg; // // Set to fdreg when in call back // and nill otherwise // - fdReg *pCBReg; + fdReg *pCBReg; epicsShareFunc void installReg (fdReg ®); - void removeReg (fdReg ®); + epicsShareFunc void removeReg (fdReg ®); }; -epicsShareExtern fdManager fileDescriptorManager; - // -// fdManagerMaxInt () +// fdRegId::hash() // -inline int fdManagerMaxInt (int a, int b) +inline resTableIndex fdRegId::hash (unsigned) const { - if (a>b) { - return a; - } - else { - return b; - } + resTableIndex hashid; + + hashid = resTableIntHash + (this->fd); + + // + // also evenly distribute based on the type of fdRegType + // + hashid ^= this->type; + + // + // the result here is always masked to the + // proper size after it is returned to the resource class + // + return hashid; } - + #endif // fdManagerH_included