2015-10-28 03:21:28 +08:00
|
|
|
#pragma once
|
|
|
|
|
2017-10-09 16:53:03 +08:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fmt/format.h>
|
|
|
|
#include <glog/logging.h>
|
2015-10-28 03:21:28 +08:00
|
|
|
#include <malloc.h>
|
|
|
|
#include <sys/epoll.h>
|
|
|
|
|
2016-08-11 11:47:30 +08:00
|
|
|
#include "io/network/socket.hpp"
|
2017-04-19 21:52:20 +08:00
|
|
|
#include "utils/exceptions.hpp"
|
2017-02-18 18:54:37 +08:00
|
|
|
#include "utils/likely.hpp"
|
2015-10-28 03:21:28 +08:00
|
|
|
|
2017-03-06 20:37:51 +08:00
|
|
|
namespace io::network {
|
2015-10-28 03:21:28 +08:00
|
|
|
|
2017-03-06 20:37:51 +08:00
|
|
|
/**
|
|
|
|
* Wrapper class for epoll.
|
|
|
|
* Creates an object that listens on file descriptor status changes.
|
|
|
|
* see: man 4 epoll
|
|
|
|
*/
|
2017-02-18 18:54:37 +08:00
|
|
|
class Epoll {
|
|
|
|
public:
|
|
|
|
using Event = struct epoll_event;
|
|
|
|
|
2017-11-09 20:46:37 +08:00
|
|
|
explicit Epoll(int flags) : epoll_fd_(epoll_create1(flags)) {
|
2017-10-09 16:53:03 +08:00
|
|
|
// epoll_create1 returns an error if there is a logical error in our code
|
|
|
|
// (for example invalid flags) or if there is irrecoverable error. In both
|
|
|
|
// cases it is best to terminate.
|
|
|
|
CHECK(epoll_fd_ != -1) << "Error on epoll_create1, errno: " << errno
|
|
|
|
<< ", message: " << strerror(errno);
|
2017-02-18 18:54:37 +08:00
|
|
|
}
|
2015-10-28 03:21:28 +08:00
|
|
|
|
2017-10-09 16:53:03 +08:00
|
|
|
void Add(int fd, Event *event) {
|
|
|
|
auto status = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, event);
|
|
|
|
// epoll_ctl can return an error on our logical error or on irrecoverable
|
|
|
|
// error. There is a third possibility that some system limit is reached. In
|
|
|
|
// that case we could return an erorr and close connection. Chances of
|
|
|
|
// reaching system limit in normally working memgraph is extremely unlikely,
|
|
|
|
// so it is correct to terminate even in that case.
|
|
|
|
CHECK(!status) << "Error on epoll_ctl, errno: " << errno
|
|
|
|
<< ", message: " << strerror(errno);
|
2017-02-18 18:54:37 +08:00
|
|
|
}
|
|
|
|
|
2017-06-21 17:29:13 +08:00
|
|
|
int Wait(Event *events, int max_events, int timeout) {
|
2017-10-09 16:53:03 +08:00
|
|
|
auto num_events = epoll_wait(epoll_fd_, events, max_events, timeout);
|
|
|
|
// If this check fails there was logical error in our code.
|
|
|
|
CHECK(num_events != -1 || errno == EINTR)
|
|
|
|
<< "Error on epoll_wait, errno: " << errno
|
|
|
|
<< ", message: " << strerror(errno);
|
|
|
|
// num_events can be -1 if errno was EINTR (epoll_wait interrupted by signal
|
|
|
|
// handler). We treat that as no events, so we return 0.
|
|
|
|
return num_events == -1 ? 0 : num_events;
|
2017-02-18 18:54:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2017-10-17 20:05:08 +08:00
|
|
|
const int epoll_fd_;
|
2017-02-18 18:54:37 +08:00
|
|
|
};
|
2017-11-09 20:46:37 +08:00
|
|
|
} // namespace io::network
|