reSIProcate/rutil  9694
Public Member Functions | Protected Member Functions | Protected Attributes
resip::FdPollImplFdSet Class Reference
Inheritance diagram for resip::FdPollImplFdSet:
Inheritance graph
[legend]
Collaboration diagram for resip::FdPollImplFdSet:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 FdPollImplFdSet ()
 ~FdPollImplFdSet ()
virtual const char * getImplName () const
virtual FdPollItemHandle addPollItem (Socket fd, FdPollEventMask newMask, FdPollItemIf *item)
virtual void modPollItem (FdPollItemHandle handle, FdPollEventMask newMask)
virtual void delPollItem (FdPollItemHandle handle)
virtual void registerFdSetIOObserver (FdSetIOObserver &observer)
virtual void unregisterFdSetIOObserver (FdSetIOObserver &observer)
virtual bool waitAndProcess (int ms=0)
 Wait at most {ms} milliseconds.
virtual void buildFdSet (FdSet &fdSet)
virtual bool processFdSet (FdSet &fdset)

Protected Member Functions

virtual unsigned int buildFdSetForObservers (FdSet &fdSet)
void killCache (Socket fd)
 There is a boundary case: 1.

Protected Attributes

std::vector< FdPollItemFdSetInfomItems
std::vector< FdSetIOObserver * > mFdSetObservers
int mLiveHeadIdx
int mFreeHeadIdx
FdSet mSelectSet

Detailed Description

Definition at line 117 of file FdPoll.cxx.


Constructor & Destructor Documentation

FdPollImplFdSet::FdPollImplFdSet ( )

Definition at line 169 of file FdPoll.cxx.

   : mLiveHeadIdx(-1), mFreeHeadIdx(-1)
{
}
FdPollImplFdSet::~FdPollImplFdSet ( )

Definition at line 174 of file FdPoll.cxx.

References CritLog, resip::FdPollItemFdSetInfo::mItemObj, and mItems.

{
   // assert( mEvCacheLen == 0 );  // poll not active
   unsigned itemIdx;
   for (itemIdx=0; itemIdx < mItems.size(); itemIdx++)
   {
      FdPollItemFdSetInfo& info = mItems[itemIdx];
      if (info.mItemObj)
      {
         CritLog(<<"FdPollItem idx="<<itemIdx
               <<" not deleted prior to destruction");
      }
   }
}

Member Function Documentation

FdPollItemHandle FdPollImplFdSet::addPollItem ( Socket  fd,
FdPollEventMask  newMask,
FdPollItemIf item 
) [virtual]

Implements resip::FdPollGrp.

Definition at line 190 of file FdPoll.cxx.

References FPEM_Error, FPEM_Read, FPEM_Write, IMPL_FDSET_IdxToHandle, INVALID_SOCKET, resip::FdPollItemFdSetInfo::mEvMask, mFreeHeadIdx, resip::FdPollItemFdSetInfo::mItemObj, mItems, mLiveHeadIdx, resip::FdPollItemFdSetInfo::mNextIdx, mSelectSet, resip::FdPollItemFdSetInfo::mSocketFd, resip::FdSet::setExcept(), resip::FdSet::setRead(), and resip::FdSet::setWrite().

{
   // if this isn't true then the linked lists will get messed up
   assert(item);
   assert(fd!=INVALID_SOCKET);

   unsigned useIdx;
   if ( mFreeHeadIdx >= 0 )
   {
      useIdx = mFreeHeadIdx;
      mFreeHeadIdx = mItems[useIdx].mNextIdx;
   }
   else
   {
      useIdx = mItems.size();
      unsigned newsz = 10+useIdx + useIdx/3; // plus 30% margin
      // WATCHOUT: below may trigger re-allocation, invalidating any iters
      // We don't use iters (only indices), but need to watchout for
      // cached pointers
      mItems.resize(newsz);
      // push new items onto the free list
      unsigned itemIdx;
      for (itemIdx=useIdx+1; itemIdx < newsz; itemIdx++)
      {
         mItems[itemIdx].mNextIdx = mFreeHeadIdx;
         mFreeHeadIdx = itemIdx;
      }
   }
   FdPollItemFdSetInfo& info = mItems[useIdx];
   info.mItemObj = item;
   info.mSocketFd = fd;
   info.mEvMask = newMask;
   info.mNextIdx = mLiveHeadIdx;
   mLiveHeadIdx = useIdx;

   if ( info.mEvMask & FPEM_Read )
      mSelectSet.setRead(info.mSocketFd);
   if ( info.mEvMask & FPEM_Write )
      mSelectSet.setWrite(info.mSocketFd);
   if ( info.mEvMask & FPEM_Error )
      mSelectSet.setExcept(info.mSocketFd);

   return IMPL_FDSET_IdxToHandle(useIdx);
}

Here is the call graph for this function:

void FdPollImplFdSet::buildFdSet ( FdSet fdSet) [virtual]

Implements resip::FdPollGrp.

Definition at line 359 of file FdPoll.cxx.

References buildFdSetForObservers(), FPEM_Error, FPEM_Read, FPEM_Write, INVALID_SOCKET, resip::FdPollItemFdSetInfo::mEvMask, mFreeHeadIdx, resip::FdPollItemFdSetInfo::mItemObj, mItems, mLiveHeadIdx, resip::FdPollItemFdSetInfo::mNextIdx, resip::FdPollItemFdSetInfo::mSocketFd, resip::FdSet::setExcept(), resip::FdSet::setRead(), and resip::FdSet::setWrite().

{
   int* prevIdxRef=&mLiveHeadIdx;
   int loopCnt = 0;
   int itemIdx;

   // Step 1: build a new FdSet from the Items vector
   while ( (itemIdx = *prevIdxRef) != -1 )
   {
      assert( ++loopCnt < 99123123 );
      FdPollItemFdSetInfo& info = mItems[itemIdx];
      if ( info.mItemObj==0 )
      {
         // item was deleted, need to garbage collect
         assert( info.mEvMask==0 );
         // unlink from live list
         *prevIdxRef = info.mNextIdx;
         // link into free list
         info.mNextIdx = mFreeHeadIdx;
         mFreeHeadIdx = itemIdx;
         continue;
      }
      if ( info.mEvMask!=0 )
      {
         assert(info.mSocketFd!=INVALID_SOCKET);
         if ( info.mEvMask & FPEM_Read )
            fdset.setRead(info.mSocketFd);
         if ( info.mEvMask & FPEM_Write )
            fdset.setWrite(info.mSocketFd);
         if ( info.mEvMask & FPEM_Error )
            fdset.setExcept(info.mSocketFd);
      }
      prevIdxRef = &info.mNextIdx;
   }

   // Allow any FdSetIOObservers a crack at the FdSet; we can't really optimize
   // this part.
   buildFdSetForObservers(fdset);
}

Here is the call graph for this function:

unsigned int FdPollImplFdSet::buildFdSetForObservers ( FdSet fdSet) [protected, virtual]

Definition at line 400 of file FdPoll.cxx.

References mFdSetObservers, and resip::resipMin().

Referenced by buildFdSet(), and waitAndProcess().

{
   unsigned int ms=INT_MAX;
   for(std::vector<FdSetIOObserver*>::iterator o=mFdSetObservers.begin();
         o!=mFdSetObservers.end();++o)
   {
      (*o)->buildFdSet(fdset);
      ms = resipMin(ms, (*o)->getTimeTillNextProcessMS());
   }
   return ms;
}

Here is the call graph for this function:

void FdPollImplFdSet::delPollItem ( FdPollItemHandle  handle) [virtual]

Implements resip::FdPollGrp.

Definition at line 255 of file FdPoll.cxx.

References IMPL_FDSET_HandleToIdx, INVALID_SOCKET, killCache(), and mItems.

{
   int useIdx = IMPL_FDSET_HandleToIdx(handle);
   //DebugLog(<<"deleting epoll item fd="<<fd);
   assert(useIdx>=0 && ((unsigned)useIdx) < mItems.size());
   FdPollItemFdSetInfo& info = mItems[useIdx];
   assert(info.mSocketFd!=INVALID_SOCKET);
   assert(info.mItemObj);
   killCache(info.mSocketFd);
   // we don't change the lists here since the select loop might
   // be iterating. Just mark it as dead and gc it later.
   info.mSocketFd = INVALID_SOCKET;
   info.mItemObj = NULL;
   info.mEvMask = 0;
}

Here is the call graph for this function:

virtual const char* resip::FdPollImplFdSet::getImplName ( ) const [inline, virtual]

Implements resip::FdPollGrp.

Definition at line 123 of file FdPoll.cxx.

{ return "fdset"; }
void FdPollImplFdSet::killCache ( Socket  fd) [protected]

There is a boundary case: 1.

fdA and fdB are added to epoll 2. events occur on fdA and fdB 2. waitAndProcess() select and gets events for fdA and fdB 3. handler for fdA deletes fdB (closing fd) 5. handler (same or differnt) opens new fd, gets fd as fdB, and adds it to us but under different object 6. cache processes "old" fdB event masks but binds it to the new (wrong) object

For read or write events it would be relatively harmless to pass these events to the new object (all objects should be prepared to get EAGAIN). But passing an error event could incorrectly kill the wrong object.

To prevent this, we kill the events in the mSelectSet. In POSIX, I'm pretty sure this is always safe. In Windows, I don't know what happens if the fd isn't already in the FdSet.

Definition at line 315 of file FdPoll.cxx.

References resip::FdSet::clear(), and mSelectSet.

Referenced by delPollItem(), and modPollItem().

{
   mSelectSet.clear(fd);
}

Here is the call graph for this function:

void FdPollImplFdSet::modPollItem ( FdPollItemHandle  handle,
FdPollEventMask  newMask 
) [virtual]

Implements resip::FdPollGrp.

Definition at line 236 of file FdPoll.cxx.

References FPEM_Error, FPEM_Read, FPEM_Write, IMPL_FDSET_HandleToIdx, INVALID_SOCKET, killCache(), mItems, mSelectSet, resip::FdSet::setExcept(), resip::FdSet::setRead(), and resip::FdSet::setWrite().

{
   int useIdx = IMPL_FDSET_HandleToIdx(handle);
   assert(useIdx>=0 && ((unsigned)useIdx) < mItems.size());
   FdPollItemFdSetInfo& info = mItems[useIdx];
   assert(info.mSocketFd!=INVALID_SOCKET);
   assert(info.mItemObj);
   info.mEvMask = newMask;

   killCache(info.mSocketFd);
   if ( info.mEvMask & FPEM_Read )
      mSelectSet.setRead(info.mSocketFd);
   if ( info.mEvMask & FPEM_Write )
      mSelectSet.setWrite(info.mSocketFd);
   if ( info.mEvMask & FPEM_Error )
      mSelectSet.setExcept(info.mSocketFd);
}

Here is the call graph for this function:

bool FdPollImplFdSet::processFdSet ( FdSet fdset) [virtual]

Implements resip::FdPollGrp.

Definition at line 413 of file FdPoll.cxx.

References FPEM_Error, FPEM_Read, FPEM_Write, resip::FdSet::hasException(), INVALID_SOCKET, resip::FdPollItemFdSetInfo::mEvMask, mFdSetObservers, resip::FdPollItemFdSetInfo::mItemObj, mItems, mLiveHeadIdx, resip::FdPollItemFdSetInfo::mSocketFd, resip::FdPollGrp::processItem(), resip::FdSet::readyToRead(), and resip::FdSet::readyToWrite().

Referenced by waitAndProcess().

{
   bool didsomething = false;
   int itemIdx;
   int* prevIdxRef = &mLiveHeadIdx;
   int loopCnt = 0;

   // Step 3: Invoke callbacks
   // Could take advantage of early via numReady, but book keeping
   // seems tedious especially if items are deleted during walk
   while ( (itemIdx = *prevIdxRef) != -1 )
   {
      FdPollItemFdSetInfo& info = mItems[itemIdx];
      assert( ++loopCnt < 99123123 );
      if ( info.mEvMask!=0 && info.mItemObj!=0 )
      {
         FdPollEventMask usrMask = 0;
         assert(info.mSocketFd!=INVALID_SOCKET);
         if ( fdset.readyToRead(info.mSocketFd) )
            usrMask |= FPEM_Read;
         if ( fdset.readyToWrite(info.mSocketFd) )
            usrMask |= FPEM_Write;
         if ( fdset.hasException(info.mSocketFd) )
            usrMask |= FPEM_Error;

         // items's mask may have changed since select occured, so mask it again
         usrMask &= info.mEvMask;
         if ( usrMask )
         {
            processItem(info.mItemObj, usrMask);
            didsomething = true;
         }
      }
      // WATCHOUT: {info} may have moved due to add during processItem()
      // set pointer using index, not {info}
      prevIdxRef = &mItems[itemIdx].mNextIdx;
   }

   // Step 3.1: Invoke callbacks on any FdSetIOObservers
   for(std::vector<FdSetIOObserver*>::iterator o=mFdSetObservers.begin();
         o!=mFdSetObservers.end();++o)
   {
      // This is not strictly correct; we do not know if this observer actually
      // put any FDs in the set, or if any of these FDs ended up being ready.
      // Eventually, it would be nice to have process() return whether any 
      // actual IO was performed.
      didsomething=true;
      (*o)->process(fdset);
   }

   return didsomething;
}

Here is the call graph for this function:

void FdPollImplFdSet::registerFdSetIOObserver ( FdSetIOObserver observer) [virtual]

Implements resip::FdPollGrp.

Definition at line 272 of file FdPoll.cxx.

References mFdSetObservers.

{
   // .bwc. Could make this sorted. Probably not worth the trouble.
   mFdSetObservers.push_back(&observer);
}
void FdPollImplFdSet::unregisterFdSetIOObserver ( FdSetIOObserver observer) [virtual]

Implements resip::FdPollGrp.

Definition at line 279 of file FdPoll.cxx.

References mFdSetObservers.

{
   // .bwc. Could make this sorted. Probably not worth the trouble.
   for(std::vector<FdSetIOObserver*>::iterator o=mFdSetObservers.begin();
         o!=mFdSetObservers.end();++o)
   {
      if(*o==&observer)
      {
         mFdSetObservers.erase(o);
         return;
      }
   }
}
bool FdPollImplFdSet::waitAndProcess ( int  ms = 0) [virtual]

Wait at most {ms} milliseconds.

If any file activity has already occurs or occurs before {ms} expires, then FdPollItem will be informed (via cb method) and this method will return. Returns true iff any file activity occured. ms<0: wait forever, ms=0: don't wait, ms>0: wait this long NOTE: "forever" may be a little as 60sec or as much as forever

Implements resip::FdPollGrp.

Definition at line 322 of file FdPoll.cxx.

References buildFdSetForObservers(), CritLog, resip::getErrno(), mSelectSet, processFdSet(), resip::resipMin(), resip::FdSet::selectMilliSeconds(), and strerror().

{
   if(ms<0)
   {
      // On Linux, passing a NULL timeout ptr to select() will wait
      // forever, but I don't want to trust that on all platforms.
      // So use 60sec as approximation of "forever".
      // Use 60sec b/c fits in short.
      ms = 60*1000;
   }

   // Create copy; is cheaper than rebuilding from scratch every time.
   FdSet fdset(mSelectSet);
   ms = resipMin(buildFdSetForObservers(fdset), (unsigned int)ms);

   // Step 2: Select on our built FdSet
   int numReady = fdset.selectMilliSeconds(ms);
   if ( numReady < 0 )
   {
      int err = getErrno();
      if ( err!=EINTR )
      {
         CritLog(<<"select() failed: "<<strerror(err));
         assert(0);     // .kw. not sure correct behavior...
      }
      return false;
   }

   if ( numReady==0 )
   {
      return false;     // timer expired
   }

   return processFdSet(fdset);
}

Here is the call graph for this function:


Member Data Documentation

Definition at line 153 of file FdPoll.cxx.

Referenced by addPollItem(), and buildFdSet().

Definition at line 152 of file FdPoll.cxx.

Referenced by addPollItem(), buildFdSet(), and processFdSet().

Definition at line 160 of file FdPoll.cxx.

Referenced by addPollItem(), killCache(), modPollItem(), and waitAndProcess().


The documentation for this class was generated from the following file: