#pragma implementation "Select.h" #include #ifndef FD_SETSIZE #define FD_SETSIZE 256 #endif #include #include #include #include #include #include #define TRACE 0 inline int SelectEvent::tst(int i) const { return i >= 0 && FD_ISSET(i,(fd_set *)fds); } inline void SelectEvent::set(int i) { FD_SET(i,(fd_set *)fds); } inline void SelectEvent::clr(int i) { FD_CLR(i,(fd_set *)fds); } void SelectEvent::handler() { for (SelectPoll *p = q; p; p = p->next) { if (tst(p->fd)) { p->handler(); if (modified) { modified = false; handler(); return; } } } } void SelectEvent::setall() { for (SelectPoll *p = q; p; p = p->next) if (p->fd >= 0) set(p->fd); } SelectEvent::SelectEvent(int fd_setsize) { setsize = fd_setsize; modified = false; if (setsize > FD_SETSIZE) setsize = FD_SETSIZE; fds = new fd_set; q = 0; FD_ZERO((fd_set *)fds); } SelectEvent::~SelectEvent() { delete (fd_set *)fds; } #if TRACE static inline ostream & operator << (ostream &o,SelectEvent &e) { e.printon(o); return o; } void SelectEvent::printon(ostream &out) { out << '('; for (int i = 0; i < setsize; ++i) if (tst(i)) out << ' ' << i; out << " )"; } #endif void SelectPoll::disarm() { if (fd == -1) return; head->del(*this); head->clr(fd); /* cerr << "disarm(" << fd << ")\r\n"; */ fd = -1; } void SelectPoll::arm(int f) { /* cerr << "arm(" << f << ")\r\n"; */ if (fd == -1) head->add(*this); else if (fd != f) head->clr(fd); fd = f; } SelectEvent SelectPoll::SelectRead; SelectEvent SelectPoll::SelectWrite; SelectEvent SelectPoll::SelectStat; int SelectPoll::getevent(unsigned to) { Signal::timeout.tv_sec = to; for (;;) { int rc = poll(to); if (rc < -1) // FIXME: should we return on handled signals? return rc; } } int SelectPoll::poll(unsigned to) { Timer::wait(Signal::timeout); /* our signal handler will set tv_sec to 0 to make select fall through */ int rc = Signal::check(); if (rc < -1) return rc; SelectRead.setall(); SelectWrite.setall(); SelectStat.setall(); #if TRACE cerr << " Read" << SelectRead << Signal::timeout.tv_sec << " Write" << SelectWrite << " Stat" << SelectStat << "\r\n"; #endif rc = select(SelectRead.setsize, // FIXME: really should be min (fd_set *)SelectRead.fds,(fd_set *)SelectWrite.fds,(fd_set *)SelectStat.fds,&Signal::timeout); if (rc > 0) { #if TRACE cerr << "*Read" << SelectRead << rc << "*Write" << SelectWrite << "*Stat" << SelectStat << "\r\n"; #endif SelectRead.handler(); SelectWrite.handler(); SelectStat.handler(); } else if (rc == 0) { // timed out //cerr << "Idle\r\n"; static bool inIdle = false; if (inIdle) Signal::timeout.tv_sec = to; /* wait a while */ else if (inIdle = true,EventPoll::IdleEvent.handler() == 0) { /* nothing to do */ inIdle = false; Signal::timeout.tv_sec = to; /* wait a while */ } } else rc = Signal::check(); return rc; } void SelectEvent::add(SelectPoll &r) { r.next = q; q = &r; } void SelectEvent::del(SelectPoll &r) { for (SelectPoll **p = &q; *p; p = &(*p)->next) { if (*p == &r) { *p = r.next; modified = true; return; } } }