blob: 78650cff7ac5239bb761216843a192bbae6ecda5 [file] [edit]
// Copyright 2023 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "async_loop.h"
#include "metrics.h" // For GetTimeMillis()
#include "util.h"
#ifdef _WIN32
#include "async_loop-win32.h"
#else
#include "async_loop-posix.h"
#endif
// static
std::string AsyncErrorToString(AsyncError error) {
return std::string(strerror(error));
}
static int64_t AsyncLoopGlobalClock() {
static bool init = false;
static int64_t start_ms = 0;
int64_t result = GetTimeMillis();
if (!init) {
start_ms = result;
init = true;
}
return result - start_ms;
}
// Global instance.
static std::unique_ptr<AsyncLoop> s_loop;
// static
AsyncLoop& AsyncLoop::Get() {
AsyncLoop* loop = s_loop.get();
if (!loop) {
loop = new AsyncLoop();
s_loop.reset(loop);
}
return *loop;
}
// static
std::unique_ptr<AsyncLoop> AsyncLoop::CreateLocal() {
return std::unique_ptr<AsyncLoop>(new AsyncLoop());
}
void AsyncLoop::Reset() {
impl_.reset(new AsyncLoop::Impl());
if (interrupt_catcher_count_ > 0)
impl_->EnableInterruptCatcher();
}
// static
void AsyncLoop::ResetForTesting() {
AsyncLoop* loop = s_loop.get();
if (loop)
loop->Reset();
}
AsyncLoop::AsyncLoop() : impl_(new AsyncLoop::Impl()) {}
AsyncLoop::~AsyncLoop() = default;
// static
int64_t AsyncLoop::NowMs() {
if (clock_)
return (*clock_)();
else
return AsyncLoopGlobalClock();
}
AsyncLoop::Clock* AsyncLoop::ChangeInternalClock(Clock* clock) {
Clock* result = clock_;
clock_ = clock;
return result;
}
AsyncLoop::ExitStatus AsyncLoop::RunOnce(int64_t timeout_ms) {
return impl_->RunOnce(timeout_ms, *this);
}
void AsyncLoop::ClearInterrupt() {
impl_->ClearInterrupt();
}
#ifndef _WIN32
int AsyncLoop::GetInterruptSignal() const {
return impl_->GetInterruptSignal();
}
sigset_t AsyncLoop::GetOldSignalMask() const {
return impl_->GetOldSignalMask();
}
#endif // !_WIN32
AsyncLoop::RunUntilState::RunUntilState(int64_t timeout_ms)
: timeout_ms_(timeout_ms) {}
bool AsyncLoop::RunUntilState::LoopAgain(AsyncLoop& async_loop) {
// Initialize expiration_ms_ the first time this method is called.
int64_t expiration_ms = -1;
if (timeout_ms_ >= 0)
expiration_ms = async_loop.NowMs() + timeout_ms_;
status_ = async_loop.RunOnce(timeout_ms_);
if (status_ != ExitSuccess) {
// Either an interrupt, timeout or idle exit.
// This is the end of the loop.
return false;
}
if (timeout_ms_ < 0) {
// Since no timeout was specified, just loop again
// after an async event.
return true;
}
// Adjust the timeout for the next invocation.
timeout_ms_ = expiration_ms - async_loop.NowMs();
if (timeout_ms_ >= 0) {
// There is still time left, so loop again.
return true;
}
// There is no time left, stop the loop reporting
// a real timeout.
timeout_ms_ = 0;
status_ = ExitTimeout;
return false;
}
void AsyncLoop::ChangeInterruptCatcher(bool increment) {
if (increment) {
if (++interrupt_catcher_count_ == 1)
impl_->EnableInterruptCatcher();
} else {
if (interrupt_catcher_count_ <= 0)
Fatal("Unbalanced ChangeInterruptCatcher() calls");
if (--interrupt_catcher_count_ == 0)
impl_->DisableInterruptCatcher();
}
}
///////////////////////////////////////////////////////////////////////////
///
/// AsyncHandle
///
void AsyncLoop::AttachHandle(AsyncHandleImpl* handle) {
impl_->AttachHandle(handle);
}
void AsyncLoop::DetachHandle(AsyncHandleImpl* handle) {
impl_->DetachHandle(handle);
}
void AsyncLoop::UpdateHandle(AsyncHandleImpl* handle) {
impl_->UpdateHandle(handle);
}
void AsyncLoop::CancelHandle(AsyncHandleImpl* handle) {
impl_->CancelHandle(handle);
}
// static
std::unique_ptr<AsyncHandle> AsyncHandle::Create(
ScopedHandle handle, AsyncLoop& async_loop,
AsyncHandle::Callback&& callback) {
return std::make_unique<AsyncHandleImpl>(std::move(handle), async_loop,
std::move(callback));
}
///////////////////////////////////////////////////////////////////////////
///
/// AsyncTimer
///
void AsyncLoop::AttachTimer(AsyncTimerImpl* timer) {
impl_->timers().AttachTimer(timer);
}
void AsyncLoop::DetachTimer(AsyncTimerImpl* timer) {
impl_->timers().DetachTimer(timer);
}
void AsyncLoop::UpdateTimer(AsyncTimerImpl* timer) {
impl_->timers().UpdateTimer(timer);
}
// static
std::unique_ptr<AsyncTimer> AsyncTimer::CreateWithExpiration(
int64_t expiration_ms, AsyncLoop& async_loop,
AsyncTimer::Callback&& callback) {
auto timer =
std::make_unique<AsyncTimerImpl>(async_loop, std::move(callback));
timer->SetExpirationMs(expiration_ms);
return timer;
}
// static
std::unique_ptr<AsyncTimer> AsyncTimer::CreateWithDuration(
int64_t duration_ms, AsyncLoop& async_loop,
AsyncTimer::Callback&& callback) {
auto timer =
std::make_unique<AsyncTimerImpl>(async_loop, std::move(callback));
timer->SetDurationMs(duration_ms);
return timer;
}
///////////////////////////////////////////////////////////////////////////
///
/// AsyncSigChild
///
#ifndef _WIN32
void AsyncLoop::SetSigChildCallback(AsyncSigChild::Callback&& cb) {
impl_->SetSigChildCallback(std::move(cb));
}
void AsyncLoop::ClearSigChildCallback() {
impl_->ClearSigChildCallback();
}
// static
std::unique_ptr<AsyncSigChild> AsyncSigChild::Create(AsyncLoop& async_loop,
Callback&& callback) {
return std::make_unique<AsyncSigChildImpl>(async_loop, std::move(callback));
}
#endif // !_WIN32
///////////////////////////////////////////////////////////////////////////
///
/// AsyncFdReady
///
#ifndef _WIN32
void AsyncLoop::AttachFdReady(AsyncFdReadyImpl* handle) {
impl_->AttachFdReady(handle);
}
void AsyncLoop::DetachFdReady(AsyncFdReadyImpl* handle) {
impl_->DetachFdReady(handle);
}
void AsyncLoop::UpdateFdReady(AsyncFdReadyImpl* handle) {
impl_->UpdateFdReady(handle);
}
std::unique_ptr<AsyncFdReadyFlags> AsyncFdReadyFlags::Create(
AsyncLoop& async_loop, int fd) {
return std::make_unique<AsyncFdReadyImpl>(async_loop, fd);
}
#endif // !_WIN32