mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-10 01:25:21 +00:00
Fix curiosities in TimerDescriptor
This commit is contained in:
parent
d4055fc21b
commit
5ac26d2115
@ -1,11 +1,12 @@
|
|||||||
#if defined(OS_LINUX)
|
#if defined(OS_LINUX)
|
||||||
|
|
||||||
#include <Common/TimerDescriptor.h>
|
#include <Common/TimerDescriptor.h>
|
||||||
#include <Common/Exception.h>
|
#include <Common/Exception.h>
|
||||||
|
|
||||||
#include <sys/timerfd.h>
|
#include <sys/timerfd.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -19,15 +20,13 @@ namespace ErrorCodes
|
|||||||
|
|
||||||
TimerDescriptor::TimerDescriptor(int clockid, int flags)
|
TimerDescriptor::TimerDescriptor(int clockid, int flags)
|
||||||
{
|
{
|
||||||
timer_fd = timerfd_create(clockid, flags);
|
timer_fd = timerfd_create(clockid, flags | TFD_NONBLOCK);
|
||||||
if (timer_fd == -1)
|
if (timer_fd == -1)
|
||||||
throw Exception(ErrorCodes::CANNOT_CREATE_TIMER, "Cannot create timer_fd descriptor");
|
throw ErrnoException(ErrorCodes::CANNOT_CREATE_TIMER, "Cannot create timer_fd descriptor");
|
||||||
|
|
||||||
if (-1 == fcntl(timer_fd, F_SETFL, O_NONBLOCK))
|
|
||||||
throw ErrnoException(ErrorCodes::CANNOT_FCNTL, "Cannot set O_NONBLOCK for timer_fd");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TimerDescriptor::TimerDescriptor(TimerDescriptor && other) noexcept : timer_fd(other.timer_fd)
|
TimerDescriptor::TimerDescriptor(TimerDescriptor && other) noexcept
|
||||||
|
: timer_fd(other.timer_fd)
|
||||||
{
|
{
|
||||||
other.timer_fd = -1;
|
other.timer_fd = -1;
|
||||||
}
|
}
|
||||||
@ -43,13 +42,16 @@ TimerDescriptor::~TimerDescriptor()
|
|||||||
/// Do not check for result cause cannot throw exception.
|
/// Do not check for result cause cannot throw exception.
|
||||||
if (timer_fd != -1)
|
if (timer_fd != -1)
|
||||||
{
|
{
|
||||||
int err = close(timer_fd);
|
if (0 != ::close(timer_fd))
|
||||||
chassert(!err || errno == EINTR);
|
std::terminate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimerDescriptor::reset() const
|
void TimerDescriptor::reset() const
|
||||||
{
|
{
|
||||||
|
if (timer_fd == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
itimerspec spec;
|
itimerspec spec;
|
||||||
spec.it_interval.tv_nsec = 0;
|
spec.it_interval.tv_nsec = 0;
|
||||||
spec.it_interval.tv_sec = 0;
|
spec.it_interval.tv_sec = 0;
|
||||||
@ -66,18 +68,35 @@ void TimerDescriptor::reset() const
|
|||||||
|
|
||||||
void TimerDescriptor::drain() const
|
void TimerDescriptor::drain() const
|
||||||
{
|
{
|
||||||
|
if (timer_fd == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
/// It is expected that socket returns 8 bytes when readable.
|
/// It is expected that socket returns 8 bytes when readable.
|
||||||
/// Read in loop anyway cause signal may interrupt read call.
|
/// Read in loop anyway cause signal may interrupt read call.
|
||||||
|
|
||||||
|
/// man timerfd_create:
|
||||||
|
/// If the timer has already expired one or more times since its settings were last modified using timerfd_settime(),
|
||||||
|
/// or since the last successful read(2), then the buffer given to read(2) returns an unsigned 8-byte integer (uint64_t)
|
||||||
|
/// containing the number of expirations that have occurred.
|
||||||
|
/// (The returned value is in host byte order—that is, the native byte order for integers on the host machine.)
|
||||||
uint64_t buf;
|
uint64_t buf;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
ssize_t res = ::read(timer_fd, &buf, sizeof(buf));
|
ssize_t res = ::read(timer_fd, &buf, sizeof(buf));
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
|
/// man timerfd_create:
|
||||||
|
/// If no timer expirations have occurred at the time of the read(2),
|
||||||
|
/// then the call either blocks until the next timer expiration, or fails with the error EAGAIN
|
||||||
|
/// if the file descriptor has been made nonblocking
|
||||||
|
/// (via the use of the fcntl(2) F_SETFL operation to set the O_NONBLOCK flag).
|
||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (errno != EINTR)
|
/// A signal happened, need to retry.
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
throw ErrnoException(ErrorCodes::CANNOT_READ_FROM_SOCKET, "Cannot drain timer_fd");
|
throw ErrnoException(ErrorCodes::CANNOT_READ_FROM_SOCKET, "Cannot drain timer_fd");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,6 +104,8 @@ void TimerDescriptor::drain() const
|
|||||||
|
|
||||||
void TimerDescriptor::setRelative(uint64_t usec) const
|
void TimerDescriptor::setRelative(uint64_t usec) const
|
||||||
{
|
{
|
||||||
|
chassert(timer_fd >= 0);
|
||||||
|
|
||||||
static constexpr uint32_t TIMER_PRECISION = 1e6;
|
static constexpr uint32_t TIMER_PRECISION = 1e6;
|
||||||
|
|
||||||
itimerspec spec;
|
itimerspec spec;
|
||||||
@ -103,4 +124,5 @@ void TimerDescriptor::setRelative(Poco::Timespan timespan) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user