/**
* Copyright (C) Mellanox Technologies Ltd. 2018. ALL RIGHTS RESERVED.
*
* See file LICENSE for terms.
*/
#include "sa_util.h"
#include <sys/epoll.h>
#include <sys/time.h>
#include <unistd.h>
#include <cstring>
#include <climits>
error::error(const std::string& message) : m_message(message) {
}
error::~error() throw() {
}
const char* error::what() const throw() {
return m_message.c_str();
}
sys_error::~sys_error() throw() {
}
sys_error::sys_error(const std::string& message, int errn) :
error(message + ": " + strerror(errn) + " (" + std::to_string(errn) + ")") {
}
file_desc::file_desc(int fd) : m_fd(fd) {
}
file_desc::~file_desc() {
int ret = ::close(m_fd);
if (ret < 0) {
fprintf(stderr, "Warning: failed to close fd %d: %m", m_fd);
}
}
file_desc::operator int() const {
return m_fd;
}
evpoll_set::evpoll_set() : file_desc(create_epfd()) {
}
void evpoll_set::add(int fd, uint32_t ev_flags) {
struct epoll_event ev;
memset(&ev, 0, sizeof(ev));
ev.events = ev_flags;
ev.data.fd = fd;
int ret = ::epoll_ctl(*this, EPOLL_CTL_ADD, fd, &ev);
if (ret != 0) {
throw sys_error("failed to add fd to epoll", errno);
}
}
void evpoll_set::wait(std::vector<event>& events, int timeout_ms) const {
static const size_t maxevents = 32;
struct epoll_event ev_array[maxevents];
LOG_DEBUG << "epoll_wait with timeout " << timeout_ms << " milliseconds";
int ret = epoll_wait(*this, ev_array, maxevents, timeout_ms);
if (ret < 0) {
if (errno != EINTR) {
throw sys_error("epoll_wait failed", errno);
}
} else {
for (int i = 0; i < ret; ++i) {
event ev = { ev_array[i].data.fd, ev_array[i].events };
events.push_back(ev);
}
}
}
int evpoll_set::create_epfd() {
int fd = epoll_create(1);
if (fd < 0) {
throw sys_error("failed to create epoll set", errno);
}
return fd;
}
log::level_t log::m_log_level = INFO;
log::log(log::level_t level, const std::string& file, int line) :
m_enabled(level <= m_log_level) {
if (m_enabled) {
struct timeval tv;
gettimeofday(&tv, NULL);
char cstr[64];
snprintf(cstr, sizeof(cstr), "[%lu.%06lu] %12s:%-5d",
tv.tv_sec, tv.tv_usec, basename(file.c_str()), line);
m_msg << cstr << " " << level_str(level) << " ";
}
}
log::~log() {
if (m_enabled) {
m_msg << std::endl;
std::cout << m_msg.str() << std::flush;
}
}
std::string log::level_str(log::level_t level) {
switch (level) {
case INFO:
return "INFO ";
case DEBUG:
return "DEBUG";
default:
throw error("invalid log level");
}
}
void log::more_verbose() {
if (m_log_level == INFO) {
m_log_level = DEBUG;
}
}