tdlight/tdutils/td/utils/port/detail/skip_eintr.h
2022-01-01 03:35:39 +03:00

64 lines
1.4 KiB
C++

//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#if TD_PORT_POSIX
#include "td/utils/common.h"
#include "td/utils/Time.h"
#include <cerrno>
#include <type_traits>
#endif
namespace td {
#if TD_PORT_POSIX
namespace detail {
template <class F>
auto skip_eintr(F &&f) {
decltype(f()) res;
static_assert(std::is_integral<decltype(res)>::value, "integral type expected");
do {
errno = 0; // just in case
res = f();
} while (res < 0 && errno == EINTR);
return res;
}
template <class F>
auto skip_eintr_cstr(F &&f) {
char *res;
do {
errno = 0; // just in case
res = f();
} while (res == nullptr && errno == EINTR);
return res;
}
template <class F>
auto skip_eintr_timeout(F &&f, int32 timeout_ms) {
decltype(f(timeout_ms)) res;
static_assert(std::is_integral<decltype(res)>::value, "integral type expected");
auto start = Timestamp::now();
auto left_timeout_ms = timeout_ms;
while (true) {
errno = 0; // just in case
res = f(left_timeout_ms);
if (res >= 0 || errno != EINTR) {
break;
}
left_timeout_ms =
static_cast<int32>(td::max((start.at() - Timestamp::now().at()) * 1000 + timeout_ms + 1 - 1e-9, 0.0));
}
return res;
}
} // namespace detail
#endif
} // namespace td