|
reSIProcate/rutil
9694
|


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< FdPollItemFdSetInfo > | mItems |
| std::vector< FdSetIOObserver * > | mFdSetObservers |
| int | mLiveHeadIdx |
| int | mFreeHeadIdx |
| FdSet | mSelectSet |
Definition at line 117 of file FdPoll.cxx.
| 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");
}
}
}
| 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);
}

| 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);
}

| 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;
}

| 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;
}

| virtual const char* resip::FdPollImplFdSet::getImplName | ( | ) | const [inline, virtual] |
| 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);
}

| 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);
}

| 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;
}

| 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);
}

std::vector<FdSetIOObserver*> resip::FdPollImplFdSet::mFdSetObservers [protected] |
Definition at line 143 of file FdPoll.cxx.
Referenced by buildFdSetForObservers(), processFdSet(), registerFdSetIOObserver(), and unregisterFdSetIOObserver().
int resip::FdPollImplFdSet::mFreeHeadIdx [protected] |
Definition at line 153 of file FdPoll.cxx.
Referenced by addPollItem(), and buildFdSet().
std::vector<FdPollItemFdSetInfo> resip::FdPollImplFdSet::mItems [protected] |
Definition at line 142 of file FdPoll.cxx.
Referenced by addPollItem(), buildFdSet(), delPollItem(), modPollItem(), processFdSet(), and ~FdPollImplFdSet().
int resip::FdPollImplFdSet::mLiveHeadIdx [protected] |
Definition at line 152 of file FdPoll.cxx.
Referenced by addPollItem(), buildFdSet(), and processFdSet().
FdSet resip::FdPollImplFdSet::mSelectSet [protected] |
Definition at line 160 of file FdPoll.cxx.
Referenced by addPollItem(), killCache(), modPollItem(), and waitAndProcess().
1.7.5.1