/* Web Polygraph http://www.web-polygraph.org/
* (C) 2003-2006 The Measurement Factory
* Licensed under the Apache License, Version 2.0 */
#include "xstd/xstd.h"
#include "xstd/h/os_std.h"
#include "xstd/Assert.h"
#include "xstd/Select.h"
#include "xstd/gadgets.h"
FD_Set::FD_Set(): theMaxFD(-1), theResCount(0) {
FD_ZERO(&theSet);
FD_ZERO(&theReadySet);
}
FD_Set::~FD_Set() {
}
void FD_Set::fdLimit(int) {
}
void FD_Set::setFD(int fd, FileScanUser *u) {
Assert(fd >= 0 && u);
FD_SET(fd, &theSet);
if (fd > theMaxFD)
theMaxFD = fd;
theResCount++;
}
void FD_Set::clearFD(int fd) {
Assert(fd >= 0);
Assert(fd <= theMaxFD);
FD_CLR(fd, &theSet);
FD_CLR(fd, &theReadySet); // poll() cannot do that
if (fd == theMaxFD) {
while (theMaxFD >= 0 && !FD_ISSET(theMaxFD, &theSet)) {
theMaxFD--;
}
}
theResCount--;
}
/* Select */
Select::Select() {
}
void Select::configure(int fdLimit) {
FileScanner::configure(fdLimit);
theSets[dirRead].fdLimit(fdLimit);
theSets[dirWrite].fdLimit(fdLimit);
}
FileScanReserv Select::setFD(int fd, IODir dir, FileScanUser *u) {
theSets[dir].setFD(fd, u);
if (fd > theMaxFD)
theMaxFD = fd;
return FileScanner::setFD(fd, dir, u);
}
void Select::clearFD(int fd, IODir dir) {
theSets[dir].clearFD(fd);
if (fd == theMaxFD)
theMaxFD = Max(theSets[dirRead].maxFD(), theSets[dirWrite].maxFD());
FileScanner::clearFD(fd, dir);
}
bool Select::interestedUser(int idx, IODir dir) const {
return theSets[dir].isSet(idx) && theRegs[idx].blocked() != -dir;
}
FileScanUser *Select::readyUser(int idx, IODir dir, int &fd) {
fd = idx;
return theSets[dir].isReady(fd) ? theRegs[fd].user() : 0;
}
fd_set *Select::prepReadySet(IODir dir) {
if (fd_set *res = theSets[dir].prepReadySet()) {
for (int fd = 0; fd <= theMaxFD; ++fd) {
if (!interestedUser(fd, dir))
FD_CLR(fd, res);
}
return res;
}
return 0;
}
int Select::sweep(Time *timeout) {
// have to check all fds, cannot choose like poll() does
const int hotCount = theMaxFD+1;
fd_set *rdSet = prepReadySet(dirRead);
fd_set *wrSet = prepReadySet(dirWrite);
fd_set *excSet = 0;
# if defined(WIN32)
// MS Windows reports connect(2) failures via exception set
// collect exceptions and later "backport" to wrSet to fake
// Unix-like behavior
if (wrSet) {
static fd_set es;
es = *wrSet;
excSet = &es;
} else
if (!rdSet) {
// Windows select(2) fails if no FDs are checked for
// we must emulate sleep instead of calling select(2)
if (timeout)
sleep(timeout->sec());
return 0;
}
# endif
const int res = ::select(hotCount, rdSet, wrSet, excSet, timeout);
# if defined(WIN32)
if (res > 0 && excSet && wrSet) {
for (int fd = 0; fd < hotCount; ++fd) {
if (FD_ISSET(fd, excSet))
FD_SET(fd, wrSet);
}
}
# endif
return res <= 0 ? res : hotCount;
}
syntax highlighted by Code2HTML, v. 0.9.1