verdnatura-chat/ios/Pods/Flipper-Folly/folly/io/async/AsyncTimeout.h

283 lines
8.2 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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.
*/
#pragma once
#include <folly/io/async/EventBaseBackendBase.h>
#include <folly/io/async/TimeoutManager.h>
#include <folly/portability/Event.h>
#include <memory>
#include <utility>
namespace folly {
class EventBase;
class RequestContext;
/**
* AsyncTimeout is used to asynchronously wait for a timeout to occur.
*/
class AsyncTimeout {
public:
typedef TimeoutManager::InternalEnum InternalEnum;
/**
* Create a new AsyncTimeout object, driven by the specified TimeoutManager.
*/
explicit AsyncTimeout(TimeoutManager* timeoutManager);
explicit AsyncTimeout(EventBase* eventBase);
/**
* Create a new internal AsyncTimeout object.
*
* Internal timeouts are like regular timeouts, but will not stop the
* TimeoutManager loop from exiting if the only remaining events are internal
* timeouts.
*
* This is useful for implementing fallback timeouts to abort the
* TimeoutManager loop if the other events have not been processed within a
* specified time period: if the event loop takes too long the timeout will
* fire and can stop the event loop. However, if all other events complete,
* the event loop will exit even though the internal timeout is still
* installed.
*/
AsyncTimeout(TimeoutManager* timeoutManager, InternalEnum internal);
AsyncTimeout(EventBase* eventBase, InternalEnum internal);
/**
* Create a new AsyncTimeout object, not yet assigned to a TimeoutManager.
*
* attachEventBase() must be called prior to scheduling the timeout.
*/
AsyncTimeout();
AsyncTimeout(const AsyncTimeout&) = delete;
AsyncTimeout& operator=(const AsyncTimeout&) = delete;
/**
* AsyncTimeout destructor.
*
* The timeout will be automatically cancelled if it is running.
*/
virtual ~AsyncTimeout();
/**
* timeoutExpired() is invoked when the timeout period has expired.
*/
virtual void timeoutExpired() noexcept = 0;
/**
* Schedule the timeout to fire in the specified number of milliseconds.
*
* After the specified number of milliseconds has elapsed, timeoutExpired()
* will be invoked by the TimeoutManager's main loop.
*
* If the timeout is already running, it will be rescheduled with the
* new timeout value.
*
* @param milliseconds The timeout duration, in milliseconds.
*
* @return Returns true if the timeout was successfully scheduled,
* and false if an error occurred. After an error, the timeout is
* always unscheduled, even if scheduleTimeout() was just
* rescheduling an existing timeout.
*/
bool scheduleTimeout(uint32_t milliseconds);
bool scheduleTimeout(TimeoutManager::timeout_type timeout);
bool scheduleTimeoutHighRes(TimeoutManager::timeout_type_high_res timeout);
/**
* Cancel the timeout, if it is running.
*/
void cancelTimeout();
/**
* Returns true if the timeout is currently scheduled.
*/
bool isScheduled() const;
/**
* Attach the timeout to a TimeoutManager.
*
* This may only be called if the timeout is not currently attached to a
* TimeoutManager (either by using the default constructor, or by calling
* detachTimeoutManager()).
*
* This method must be invoked in the TimeoutManager's thread.
*
* The internal parameter specifies if this timeout should be treated as an
* internal event. TimeoutManager::loop() will return when there are no more
* non-internal events remaining.
*/
void attachTimeoutManager(
TimeoutManager* timeoutManager,
InternalEnum internal = InternalEnum::NORMAL);
void attachEventBase(
EventBase* eventBase,
InternalEnum internal = InternalEnum::NORMAL);
/**
* Detach the timeout from its TimeoutManager.
*
* This may only be called when the timeout is not running.
* Once detached, the timeout may not be scheduled again until it is
* re-attached to a EventBase by calling attachEventBase().
*
* This method must be called from the current TimeoutManager's thread.
*/
void detachTimeoutManager();
void detachEventBase();
const TimeoutManager* getTimeoutManager() {
return timeoutManager_;
}
/**
* Returns the internal handle to the event
*/
EventBaseBackendBase::Event* getEvent() {
return &event_;
}
/**
* Convenience function that wraps a function object as
* an AsyncTimeout instance and returns the wrapper.
*
* Specially useful when using lambdas as AsyncTimeout
* observers.
*
* Example:
*
* void foo(TimeoutManager &manager) {
* std::atomic_bool done = false;
*
* auto observer = AsyncTimeout::make(manager, [&] {
* std::cout << "hello, world!" << std::endl;
* done = true;
* });
*
* observer->scheduleTimeout(std::chrono::seconds(5));
*
* while (!done); // busy wait
* }
*
* @author: Marcelo Juchem <marcelo@fb.com>
*/
template <typename TCallback>
static std::unique_ptr<AsyncTimeout> make(
TimeoutManager& manager,
TCallback&& callback);
/**
* Convenience function that wraps a function object as
* an AsyncTimeout instance and returns the wrapper
* after scheduling it using the given TimeoutManager.
*
* This is equivalent to calling `make_async_timeout`
* followed by a `scheduleTimeout` on the resulting
* wrapper.
*
* Specially useful when using lambdas as AsyncTimeout
* observers.
*
* Example:
*
* void foo(TimeoutManager &manager) {
* std::atomic_bool done = false;
*
* auto observer = AsyncTimeout::schedule(
* std::chrono::seconds(5), manager, [&] {
* std::cout << "hello, world!" << std::endl;
* done = true;
* }
* );
*
* while (!done); // busy wait
* }
*
* @author: Marcelo Juchem <marcelo@fb.com>
*/
template <typename TCallback>
static std::unique_ptr<AsyncTimeout> schedule(
TimeoutManager::timeout_type timeout,
TimeoutManager& manager,
TCallback&& callback);
private:
static void libeventCallback(libevent_fd_t fd, short events, void* arg);
EventBaseBackendBase::Event event_;
/*
* Store a pointer to the TimeoutManager. We only use this
* for some assert() statements, to make sure that AsyncTimeout is always
* used from the correct thread.
*/
TimeoutManager* timeoutManager_;
// Save the request context for when the timeout fires.
std::shared_ptr<RequestContext> context_;
};
namespace detail {
/**
* Wraps a function object as an AsyncTimeout instance.
*
* @author: Marcelo Juchem <marcelo@fb.com>
*/
template <typename TCallback>
struct async_timeout_wrapper : public AsyncTimeout {
template <typename UCallback>
async_timeout_wrapper(TimeoutManager* manager, UCallback&& callback)
: AsyncTimeout(manager), callback_(std::forward<UCallback>(callback)) {}
void timeoutExpired() noexcept override {
static_assert(
noexcept(std::declval<TCallback>()()),
"callback must be declared noexcept, e.g.: `[]() noexcept {}`");
callback_();
}
private:
TCallback callback_;
};
} // namespace detail
template <typename TCallback>
std::unique_ptr<AsyncTimeout> AsyncTimeout::make(
TimeoutManager& manager,
TCallback&& callback) {
return std::unique_ptr<AsyncTimeout>(
new detail::async_timeout_wrapper<typename std::decay<TCallback>::type>(
std::addressof(manager), std::forward<TCallback>(callback)));
}
template <typename TCallback>
std::unique_ptr<AsyncTimeout> AsyncTimeout::schedule(
TimeoutManager::timeout_type timeout,
TimeoutManager& manager,
TCallback&& callback) {
auto wrapper = AsyncTimeout::make(manager, std::forward<TCallback>(callback));
wrapper->scheduleTimeout(timeout);
return wrapper;
}
} // namespace folly