#include <atomic>
#include <cerrno>
#include <chrono>
#ifdef __linux__
# define _GNU_SOURCE 1
# include <ctime>
# include <dlfcn.h>
# include "clock.hpp"
# include "log.hpp"
namespace ddwaf {
namespace {
# if defined(__aarch64__)
constexpr const char *VDSO_CLOCK_GETTIME = "__kernel_clock_gettime";
# else
constexpr const char *VDSO_CLOCK_GETTIME = "__vdso_clock_gettime";
# endif
using clock_gettime_t = int (*)(clockid_t, timespec *);
clock_gettime_t clock_gettime = &::clock_gettime;
}
monotonic_clock::time_point monotonic_clock::now() noexcept
{
struct timespec ts {};
const int ret = ddwaf::clock_gettime(CLOCK_MONOTONIC, &ts);
if (ret < 0) {
bool expected = false;
if (warning_issued.compare_exchange_strong(expected, true)) {
DDWAF_ERROR("clock_gettime failed. Errno {}", errno);
}
return time_point(std::chrono::seconds(0));
}
return time_point(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec));
}
std::atomic_bool monotonic_clock::warning_issued{};
struct VdsoInitializer {
VdsoInitializer() noexcept
: handle(dlopen("linux-vdso.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD))
{
if (handle != nullptr) {
void *p = dlsym(handle, VDSO_CLOCK_GETTIME);
if (p != nullptr) {
ddwaf::clock_gettime = reinterpret_cast<clock_gettime_t>(p);
}
}
}
~VdsoInitializer()
{
if (handle != nullptr) {
ddwaf::clock_gettime = &::clock_gettime;
dlclose(handle);
}
}
VdsoInitializer(const VdsoInitializer &) = delete;
VdsoInitializer &operator=(const VdsoInitializer &) = delete;
VdsoInitializer(VdsoInitializer &&) = delete;
VdsoInitializer &operator=(VdsoInitializer &&) = delete;
private:
void *handle;
};
static const VdsoInitializer vdso_initializer;
} #endif