{
return fd;
}
+ FD_r(int nfd) : fd(nfd)
+ {
+ }
};
const static bool has_separate_rw_fd_watches = true;
events[i].flags = EV_ENABLE;
}
}
+ else if (events[i].filter == EVFILT_READ || events[i].filter == EVFILT_WRITE) {
+ int flags = events[i].filter == EVFILT_READ ? in_events : out_events;
+ Base::receiveFdEvent(*this, FD_r(events[i].ident), events[i].udata, flags);
+ events[i].flags = EV_DISABLE | EV_CLEAR;
+ // we use EV_CLEAR to clear the EOF status of fifos/pipes (and wait for
+ // another connection).
+ }
else {
- // int flags = 0;
- // (events[i].events & EPOLLIN) && (flags |= in_events);
- // (events[i].events & EPOLLHUP) && (flags |= in_events);
- // (events[i].events & EPOLLOUT) && (flags |= out_events);
- // (events[i].events & EPOLLERR) && (flags |= err_events);
- // Base::receiveFdEvent(*this, FD_r(), ptr, flags);
events[i].flags = EV_DISABLE;
}
}
close(kqfd);
}
- void disableFilter(short filterType, uintptr_t ident)
+ void setFilterEnabled(short filterType, uintptr_t ident, bool enable)
{
struct kevent kev;
- EV_SET(&kev, ident, filterType, EV_DISABLE, 0, 0, 0);
+ EV_SET(&kev, ident, filterType, enable ? EV_ENABLE : EV_DISABLE, 0, 0, 0);
kevent(kqfd, &kev, 1, nullptr, 0, nullptr);
}
+ void removeFilter(short filterType, uintptr_t ident)
+ {
+ struct kevent kev;
+ EV_SET(&kev, ident, filterType, EV_DELETE, 0, 0, 0);
+ kevent(kqfd, &kev, 1, nullptr, 0, nullptr);
+ }
+
// flags: in_events | out_events
void addFdWatch(int fd, void *userdata, int flags)
{
- //struct epoll_event epevent;
- // epevent.data.fd = fd;
- //epevent.data.ptr = userdata;
- //epevent.events = 0;
+ // TODO kqueue doesn't support EVFILE_WRITE on file fd's :/
- //if (flags & one_shot) {
- // epevent.events = EPOLLONESHOT;
- //}
- //if (flags & in_events) {
- // epevent.events |= EPOLLIN;
- //}
- //if (flags & out_events) {
- // epevent.events |= EPOLLOUT;
- //}
-
- //if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &epevent) == -1) {
- // throw new std::system_error(errno, std::system_category());
- //}
+ short filter = (flags & in_events) ? EVFILT_READ : EVFILT_WRITE;
+
+ struct kevent kev;
+ EV_SET(&kev, fd, filter, EV_ADD, 0, 0, userdata);
+ if (kevent(kqfd, &kev, 1, nullptr, 0, nullptr) == -1) {
+ throw new std::system_error(errno, std::system_category());
+ }
}
- void removeFdWatch(int fd)
- {
- //epoll_ctl(epfd, EPOLL_CTL_DEL, fd, nullptr);
+ void removeFdWatch(int fd, int flags)
+ {
+ removeFilter((flags & in_events) ? EVFILT_READ : EVFILT_WRITE, fd);
}
- void removeFdWatch_nolock(int fd)
+ void removeFdWatch_nolock(int fd, int flags)
{
- removeFdWatch(fd);
+ removeFdWatch(fd, flags);
}
- // Note this will *replace* the old flags with the new, that is,
- // it can enable *or disable* read/write events.
void enableFdWatch(int fd, void *userdata, int flags)
{
- //struct epoll_event epevent;
- // epevent.data.fd = fd;
- //epevent.data.ptr = userdata;
- //epevent.events = 0;
-
- //if (flags & one_shot) {
- // epevent.events = EPOLLONESHOT;
- //}
- //if (flags & in_events) {
- // epevent.events |= EPOLLIN;
- //}
- //if (flags & out_events) {
- // epevent.events |= EPOLLOUT;
- //}
-
- //if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &epevent) == -1) {
- // throw new std::system_error(errno, std::system_category());
- //}
+ setFilterEnabled((flags & in_events) ? EVFILT_READ : EVFILT_WRITE, fd, true);
}
void enableFdWatch_nolock(int fd, void *userdata, int flags)
enableFdWatch(fd, userdata, flags);
}
- void disableFdWatch(int fd)
+ void disableFdWatch(int fd, int flags)
{
- //struct epoll_event epevent;
- // epevent.data.fd = fd;
- //epevent.data.ptr = nullptr;
- //epevent.events = 0;
-
- // Epoll documentation says that hangup will still be reported, need to check
- // whether this is really the case. Suspect it is really only the case if
- // EPOLLIN is set.
- //if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &epevent) == -1) {
- // throw new std::system_error(errno, std::system_category());
- //}
+ setFilterEnabled((flags & in_events) ? EVFILT_READ : EVFILT_WRITE, fd, false);
}
- void disableFdWatch_nolock(int fd)
+ void disableFdWatch_nolock(int fd, int flags)
{
- // TODO
+ disableFdWatch(fd, flags);
}
// Note signal should be masked before call.
sigdelset(&sigmask, rsigno);
// TODO accumulate and disable multiple filters with a single kevents call
// rather than disabling each individually
- disableFilter(EVFILT_SIGNAL, rsigno);
+ setFilterEnabled(EVFILT_SIGNAL, rsigno, false);
}
Base::receiveSignal(siginfo, sigdataMap[rsigno]);
rsigno = sigtimedwait(&sigmask, &siginfo.info, &timeout);
loop_mech.removeSignalWatch(signo);
waitqueue_node<T_Mutex> qnode;
- getAttnLock(qnode);
+ getAttnLock(qnode);
EventDispatch<T_Mutex, LoopTraits> & ed = (EventDispatch<T_Mutex, LoopTraits> &) loop_mech;
ed.issueDelete(callBack);
loop_mech.enableFdWatch(fd, watcher, watch_flags | one_shot);
}
else {
- loop_mech.disableFdWatch(fd);
+ loop_mech.disableFdWatch(fd, watch_flags);
}
}
loop_mech.enableFdWatch_nolock(fd, watcher, watch_flags | one_shot);
}
else {
- loop_mech.disableFdWatch_nolock(fd);
+ loop_mech.disableFdWatch_nolock(fd, watch_flags);
}
}
void deregister(BaseFdWatcher *callback, int fd)
{
- loop_mech.removeFdWatch(fd);
+ loop_mech.removeFdWatch(fd, callback->watch_flags);
waitqueue_node<T_Mutex> qnode;
- getAttnLock(qnode);
+ getAttnLock(qnode);
EventDispatch<T_Mutex, LoopTraits> & ed = (EventDispatch<T_Mutex, LoopTraits> &) loop_mech;
ed.issueDelete(callback);
// TODO
}
else {
- loop_mech.removeFdWatch(fd);
+ loop_mech.removeFdWatch(fd, callback->watch_flags);
}
waitqueue_node<T_Mutex> qnode;
- getAttnLock(qnode);
+ getAttnLock(qnode);
EventDispatch<T_Mutex, LoopTraits> & ed = (EventDispatch<T_Mutex, LoopTraits> &) loop_mech;
ed.issueDelete(callback);
}
else {
// both removed: actually remove
- loop_mech.removeFdWatch_nolock(bdfw->watch_fd);
+ loop_mech.removeFdWatch_nolock(bdfw->watch_fd, 0 /* not used */);
return Rearm::REMOVE;
}
}
else {
// TODO this will need flags for such a loop, since it can't
// otherwise distinguish which channel watch to remove
- loop_mech.removeFdWatch_nolock(bdfw->watch_fd);
+ loop_mech.removeFdWatch_nolock(bdfw->watch_fd, bdfw->watch_flags);
}
}
else if (rearmType == Rearm::DISARM) {
(bfw->watch_flags & (in_events | out_events)) | one_shot);
}
else if (rearmType == Rearm::REMOVE) {
- loop_mech.removeFdWatch_nolock(bfw->watch_fd);
+ loop_mech.removeFdWatch_nolock(bfw->watch_fd, bfw->watch_flags);
}
return rearmType;
}
if (LoopTraits::has_separate_rw_fd_watches) {
// TODO this will need flags for such a loop, since it can't
// otherwise distinguish which channel watch to remove
- loop_mech.removeFdWatch_nolock(bdfw->watch_fd);
+ loop_mech.removeFdWatch_nolock(bdfw->watch_fd, bdfw->watch_flags);
return bdfw->read_removed ? Rearm::REMOVE : Rearm::NOOP;
}
else {
}
else {
// both removed: actually remove
- loop_mech.removeFdWatch_nolock(bdfw->watch_fd);
+ loop_mech.removeFdWatch_nolock(bdfw->watch_fd, 0 /* not used */);
return Rearm::REMOVE;
}
}
bool is_multi_watch = false;
BaseBidiFdWatcher *bbfw = nullptr;
+ // (Above variables are initialised only to silence compiler warnings).
+
// Read/manipulate watch_flags (if necessary) *before* we release the lock:
if (pqueue->watchType == WatchType::FD) {
BaseFdWatcher *bfw = static_cast<BaseFdWatcher *>(pqueue);
ed.lock.unlock();
- // (Above variables are initialised only to silence compiler warnings).
-
// Note that we select actions based on the type of the watch, as determined by the watchType
// member. In some ways this screams out for polmorphism; a virtual function could be overridden
// by each of the watcher types. I've instead used switch/case because I think it will perform
default: ;
}
- if (pqueue->deleteme) rearmType = Rearm::REMOVE; // makes the watchRemoved() callback get called.
-
- if (rearmType == Rearm::REMOVE) {
+ if (pqueue->deleteme || rearmType == Rearm::REMOVE) {
ed.lock.unlock();
(is_multi_watch ? bbfw : pqueue)->watchRemoved();
ed.lock.lock();