Skip to content

Commit

Permalink
add judgement for conflicted ONE_SHOT flag in add_interests() (#422)
Browse files Browse the repository at this point in the history
improve logic in add_interests() and rm_interests()
  • Loading branch information
lihuiba authored Mar 21, 2024
1 parent a34a0fe commit fa89fc0
Showing 1 changed file with 57 additions and 42 deletions.
99 changes: 57 additions & 42 deletions io/epoll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ struct InFlightEvent {
void* error_data;
};

const static uint32_t EVENT_RWEO = EVENT_RWE | ONE_SHOT;

class EventEngineEPoll : public MasterEventEngine, public CascadingEventEngine, public ResetHandle {
public:
int _evfd = -1;
Expand Down Expand Up @@ -89,24 +91,25 @@ class EventEngineEPoll : public MasterEventEngine, public CascadingEventEngine,
DEFER(fd = -1);
return close(fd);
}
int ctl(int fd, int op, uint32_t events, int no_log_errno_1 = 0,
int no_log_errno_2 = 0) {
int ctl(int fd, int op, uint32_t events,
int ignore_error_1 = 0, int ignore_error_2 = 0) {
struct epoll_event ev;
ev.events = events; // EPOLLERR | EPOLLHUP always included
ev.data.u64 = fd;
int ret = epoll_ctl(_engine_fd, op, fd, &ev);
if (ret < 0) {
ERRNO err;
if (err.no != no_log_errno_1 &&
err.no != no_log_errno_2) { // deleting a non-existing fd is
// considered OK
// some errno may be ignored, such as deleting a non-existing fd, etc.
if ((ignore_error_1 == 0 || ignore_error_1 != err.no) &&
(ignore_error_2 == 0 || ignore_error_2 != err.no)) {
auto events = HEX(ev.events);
auto data = ev.data.ptr;
LOG_WARN("failed to call epoll_ctl(`, `, `, {`, `})",
VALUE(_engine_fd), VALUE(op), VALUE(fd), VALUE(events),
VALUE(data), err);
return -err.no;
}
return -err.no;
return 1; // error ignored
}
return 0;
}
Expand All @@ -115,38 +118,51 @@ class EventEngineEPoll : public MasterEventEngine, public CascadingEventEngine,
virtual int add_interest(Event e) override {
if (e.fd < 0)
LOG_ERROR_RETURN(EINVAL, -1, "invalid file descriptor ", e.fd);
if (unlikely(!e.interests))
return 0;
if (unlikely((size_t)e.fd >= _inflight_events.size()))
_inflight_events.resize(e.fd * 2);

e.interests &= EVENT_RWEO;
auto& entry = _inflight_events[e.fd];
auto intersection = e.interests & entry.interests & EVENT_RWE;
auto data = (entry.reader_data != e.data) * EVENT_READ |
(entry.writer_data != e.data) * EVENT_WRITE |
(entry.error_data != e.data) * EVENT_ERROR ;
if (intersection & data)
LOG_ERROR_RETURN(EALREADY, -1, "conflicted interest(s)");
auto eint = entry.interests & EVENT_RWEO;
int op;
if (!eint) {
eint = e.interests;
op = EPOLL_CTL_ADD;
} else {
if ((eint ^ e.interests) & ONE_SHOT)
LOG_ERROR_RETURN(EALREADY, -1, "conflicted ONE_SHOT flag");
auto intersection = e.interests & eint;
auto data = (entry.reader_data != e.data) * EVENT_READ |
(entry.writer_data != e.data) * EVENT_WRITE |
(entry.error_data != e.data) * EVENT_ERROR ;
if (intersection & data)
LOG_ERROR_RETURN(EALREADY, -1, "conflicted interest(s)");

eint |= e.interests;
op = EPOLL_CTL_MOD;
}

int ret;
auto eint = entry.interests;
auto x = (eint | e.interests) & EVENT_RWE;
auto events = evmap.translate_bitwisely(x);
if (likely(e.interests & ONE_SHOT)) {
auto events = evmap.translate_bitwisely(eint);
if (likely(eint & ONE_SHOT)) {
events |= EPOLLONESHOT;
if (likely(eint & ONE_SHOT)) {
ret = ctl(e.fd, EPOLL_CTL_MOD, events);
if (unlikely(ret < 0 && errno == ENOENT))
ret = ctl(e.fd, EPOLL_CTL_ADD, events);
} else {
if (eint != 0) LOG_ERROR_RETURN(EINVAL, -1, "conflicted interest(s) regarding ONE_SHOT");
ret = ctl(e.fd, EPOLL_CTL_ADD, events);
if (likely(op == EPOLL_CTL_MOD)) {
// This may falsely fail with errno == ENOENT,
// if the fd was closed and created again.
// We should suppress that specific error log
int ret = ctl(e.fd, op, events, ENOENT);
if (likely(ret == 0)) goto ok;
// in such cases, and `EPOLL_CTL_ADD` it again.
else if (ret > 0) op = EPOLL_CTL_ADD;
else /*if (ret < 0)*/ goto fail;
}
} else {
auto op = (eint & EVENT_RWE) ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
ret = ctl(e.fd, op, events);
}
if (ret < 0)
LOG_ERROR_RETURN(0, ret, "failed to add_interest()");
if (ctl(e.fd, op, events) < 0) { fail:
LOG_ERROR_RETURN(0, -1, "failed to add_interest()");
}

entry.interests |= e.interests;
ok: entry.interests |= eint;
if (e.interests & EVENT_READ) entry.reader_data = e.data;
if (e.interests & EVENT_WRITE) entry.writer_data = e.data;
if (e.interests & EVENT_ERROR) entry.error_data = e.data;
Expand All @@ -158,25 +174,24 @@ class EventEngineEPoll : public MasterEventEngine, public CascadingEventEngine,
LOG_ERROR_RETURN(EINVAL, -1, "invalid file descriptor ", e.fd);
if (unlikely(e.interests == 0)) return 0;
auto& entry = _inflight_events[e.fd];
auto eint = entry.interests & (EVENT_RWE | ONE_SHOT);
auto eint = entry.interests & EVENT_RWEO;
auto intersection = e.interests & eint;
if (intersection == 0) return 0;

auto remain = eint ^ intersection; // ^ is to flip intersected bits
if (remain == ONE_SHOT) {/* no need to epoll_ctl() */} else {
uint32_t op, events = 0;
if (remain) {
events = evmap.translate_bitwisely(remain);
if (remain & ONE_SHOT) events |= EPOLLONESHOT;
op = EPOLL_CTL_MOD;
} else {
op = EPOLL_CTL_DEL;
if (likely(remain == ONE_SHOT)) {
/* no need to epoll_ctl() */
} else if (likely(!remain)) {
if (ctl(e.fd, EPOLL_CTL_DEL, 0, ENOENT) < 0) { fail:
LOG_ERROR_RETURN(0, -1, "failed to rm_interest()");
}
if (ctl(e.fd, op, events) < 0)
LOG_ERROR_RETURN(0, -1, "failed to rm_interest()");
} else {
auto events = evmap.translate_bitwisely(remain);
if (remain & ONE_SHOT) events |= EPOLLONESHOT;
if (ctl(e.fd, EPOLL_CTL_MOD, events) < 0) goto fail;
}

entry.interests ^= intersection;
entry.interests ^= intersection; // ^ is to flip intersected bits
if (intersection & EVENT_READ) entry.reader_data = nullptr;
if (intersection & EVENT_WRITE) entry.writer_data = nullptr;
if (intersection & EVENT_ERROR) entry.error_data = nullptr;
Expand Down

0 comments on commit fa89fc0

Please sign in to comment.