ClickHouse/src/Common/TimerDescriptor.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

102 lines
2.6 KiB
C++
Raw Normal View History

2020-12-15 18:04:12 +00:00
#if defined(OS_LINUX)
2020-12-03 12:21:10 +00:00
#include <Common/TimerDescriptor.h>
#include <Common/Exception.h>
#include <base/defines.h>
2020-12-03 12:21:10 +00:00
#include <sys/timerfd.h>
2020-12-04 13:35:24 +00:00
#include <fcntl.h>
2020-12-03 12:21:10 +00:00
#include <unistd.h>
namespace DB
{
namespace ErrorCodes
{
extern const int CANNOT_CREATE_TIMER;
extern const int CANNOT_SET_TIMER_PERIOD;
extern const int CANNOT_FCNTL;
extern const int CANNOT_READ_FROM_SOCKET;
}
TimerDescriptor::TimerDescriptor(int clockid, int flags)
{
timer_fd = timerfd_create(clockid, flags);
if (timer_fd == -1)
throw Exception(ErrorCodes::CANNOT_CREATE_TIMER, "Cannot create timer_fd descriptor");
2020-12-04 13:35:24 +00:00
if (-1 == fcntl(timer_fd, F_SETFL, O_NONBLOCK))
throwFromErrno("Cannot set O_NONBLOCK for timer_fd", ErrorCodes::CANNOT_FCNTL);
2020-12-03 12:21:10 +00:00
}
TimerDescriptor::TimerDescriptor(TimerDescriptor && other) noexcept : timer_fd(other.timer_fd)
2021-02-15 13:21:36 +00:00
{
other.timer_fd = -1;
}
2020-12-03 12:21:10 +00:00
TimerDescriptor::~TimerDescriptor()
{
/// Do not check for result cause cannot throw exception.
2021-02-15 13:21:36 +00:00
if (timer_fd != -1)
{
int err = close(timer_fd);
chassert(!err || errno == EINTR);
}
2020-12-03 12:21:10 +00:00
}
void TimerDescriptor::reset() const
{
itimerspec spec;
spec.it_interval.tv_nsec = 0;
spec.it_interval.tv_sec = 0;
spec.it_value.tv_sec = 0;
spec.it_value.tv_nsec = 0;
if (-1 == timerfd_settime(timer_fd, 0 /*relative timer */, &spec, nullptr))
throwFromErrno("Cannot reset timer_fd", ErrorCodes::CANNOT_SET_TIMER_PERIOD);
/// Drain socket.
/// It may be possible that alarm happened and socket is readable.
drain();
}
void TimerDescriptor::drain() const
{
2020-12-04 13:35:24 +00:00
/// It is expected that socket returns 8 bytes when readable.
/// Read in loop anyway cause signal may interrupt read call.
uint64_t buf;
while (true)
2020-12-03 12:21:10 +00:00
{
2020-12-04 13:35:24 +00:00
ssize_t res = ::read(timer_fd, &buf, sizeof(buf));
if (res < 0)
2020-12-03 12:21:10 +00:00
{
2020-12-04 13:35:24 +00:00
if (errno == EAGAIN)
break;
if (errno != EINTR)
2020-12-03 12:21:10 +00:00
throwFromErrno("Cannot drain timer_fd", ErrorCodes::CANNOT_READ_FROM_SOCKET);
}
}
}
void TimerDescriptor::setRelative(uint64_t usec) const
2020-12-03 12:21:10 +00:00
{
static constexpr uint32_t TIMER_PRECISION = 1e6;
2020-12-03 12:21:10 +00:00
itimerspec spec;
spec.it_interval.tv_nsec = 0;
spec.it_interval.tv_sec = 0;
spec.it_value.tv_sec = usec / TIMER_PRECISION;
spec.it_value.tv_nsec = (usec % TIMER_PRECISION) * 1'000;
2020-12-03 12:21:10 +00:00
if (-1 == timerfd_settime(timer_fd, 0 /*relative timer */, &spec, nullptr))
throwFromErrno("Cannot set time for timer_fd", ErrorCodes::CANNOT_SET_TIMER_PERIOD);
}
void TimerDescriptor::setRelative(Poco::Timespan timespan) const
{
setRelative(timespan.totalMicroseconds());
}
2020-12-03 12:21:10 +00:00
}
2020-12-15 18:04:12 +00:00
#endif