/* * $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 * * * History * $Log$ * 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 "tsDLList.h" #include "resourceLib.h" #include "osiTime.h" #include "osiSock.h" enum fdRegType {fdrRead, fdrWrite, fdrExcp, fdRegTypeNElem}; enum fdRegState {fdrActive, fdrPending, fdrLimbo}; class epicsShareClass fdRegId { public: fdRegId (const int fdIn, const fdRegType typeIn) : fd(fdIn), type(typeIn) {} int getFD() { return this->fd; } fdRegType getType() { return this->type; } int operator == (const fdRegId &idIn) { return this->fd == idIn.fd && this->type==idIn.type; } resTableIndex resourceHash(unsigned nBitsId) const { unsigned src = (unsigned) this->fd; resTableIndex hashid; hashid = src; src = src >> nBitsId; while (src) { hashid = hashid ^ src; src = src >> nBitsId; } hashid = hashid ^ this->type; // // the result here is always masked to the // proper size after it is returned to the resource class // return hashid; } virtual void show(unsigned level) const; private: const int fd; const fdRegType type; }; // // fdReg // file descriptor registration // class epicsShareClass fdReg : public tsDLNode, public fdRegId, public tsSLNode { friend class fdManager; public: inline fdReg (const int fdIn, const fdRegType typ, const unsigned onceOnly=0); virtual ~fdReg (); virtual void show(unsigned level) const; // // Called by the file descriptor manager: // 1) If the fdManager is deleted and there are still // fdReg objects attached // 2) Immediately after calling "callBack()" if // the constructor specified "onceOnly" // // fdReg::destroy() does a "delete this" // virtual void destroy (); private: // // called when there is activity on the fd // NOTES // 1) the fdManager will call this only once during the // lifetime of a fdReg object if the constructor // specified "onceOnly" // virtual void callBack ()=0; unsigned char state; // fdRegState goes here unsigned char onceOnly; }; class epicsShareClass fdManager { friend class fdReg; public: fdManager(); ~fdManager(); void process (const osiTime &delay); // // returns NULL if the fd is unknown // inline fdReg *lookUpFD(const int fd, const fdRegType type); private: tsDLList regList; tsDLList activeList; fd_set fdSets[fdRegTypeNElem]; int maxFD; unsigned processInProg; // // Set to fdreg when in call back // and nill ortherwise // fdReg *pCBReg; inline void installReg (fdReg ®); inline void removeReg (fdReg ®); resTable fdTbl; }; epicsShareExtern fdManager fileDescriptorManager; // // lookUpFD() // inline fdReg *fdManager::lookUpFD(const int fd, const fdRegType type) { if (fd<0) { return NULL; } fdRegId id (fd,type); return this->fdTbl.lookup(id); } // // fdManagerMaxInt () // inline int fdManagerMaxInt (int a, int b) { if (a>b) { return a; } else { return b; } } // // fdManager::installReg() // inline 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"); } } // // fdManager::removeReg() // inline void fdManager::removeReg(fdReg ®) { fdReg *pItemFound; // // signal fdManager that the fdReg was deleted // during the call back // if (this->pCBReg == ®) { this->pCBReg = 0; } FD_CLR(reg.getFD(), &this->fdSets[reg.getType()]); pItemFound = this->fdTbl.remove(reg); assert (pItemFound==®); switch (reg.state) { case fdrActive: this->activeList.remove(reg); break; case fdrPending: this->regList.remove(reg); break; case fdrLimbo: break; default: assert(0); } reg.state = fdrLimbo; } // // fdReg::fdReg() // inline fdReg::fdReg (const int fdIn, const fdRegType typIn, const unsigned onceOnlyIn) : fdRegId(fdIn,typIn), state(fdrLimbo), onceOnly(onceOnlyIn) { assert (fdIn>=0); if (!FD_IN_FDSET(fdIn)) { fprintf (stderr, "%s: fd > FD_SETSIZE ignored\n", __FILE__); return; } fileDescriptorManager.installReg(*this); } #endif // fdManagerH_included