mirror of
https://github.com/clearlinux/folly.git
synced 2026-09-01 11:15:52 +00:00
Convenience functions to wrap a lambda as an AsyncTimeout.
Summary: see title Test Plan: unit tests added Reviewed By: davejwatson@fb.com Subscribers: folly-diffs@, yfeldblum, chalfant, andrewcox FB internal diff: D2000579 Signature: t1:2000579:1430345677:1d7a78f94bcd8b0912423ca4987a4048c103241c
This commit is contained in:
committed by
Praveen Kumar Ramakrishnan
parent
7f413ec31d
commit
e4c703f058
@@ -81,14 +81,14 @@ AsyncTimeout::~AsyncTimeout() {
|
||||
cancelTimeout();
|
||||
}
|
||||
|
||||
bool AsyncTimeout::scheduleTimeout(std::chrono::milliseconds timeout) {
|
||||
bool AsyncTimeout::scheduleTimeout(TimeoutManager::timeout_type timeout) {
|
||||
assert(timeoutManager_ != nullptr);
|
||||
context_ = RequestContext::saveContext();
|
||||
return timeoutManager_->scheduleTimeout(this, timeout);
|
||||
}
|
||||
|
||||
bool AsyncTimeout::scheduleTimeout(uint32_t milliseconds) {
|
||||
return scheduleTimeout(std::chrono::milliseconds(milliseconds));
|
||||
return scheduleTimeout(TimeoutManager::timeout_type(milliseconds));
|
||||
}
|
||||
|
||||
void AsyncTimeout::cancelTimeout() {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <event.h>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace folly {
|
||||
|
||||
@@ -98,7 +99,7 @@ class AsyncTimeout : private boost::noncopyable {
|
||||
* rescheduling an existing timeout.
|
||||
*/
|
||||
bool scheduleTimeout(uint32_t milliseconds);
|
||||
bool scheduleTimeout(std::chrono::milliseconds timeout);
|
||||
bool scheduleTimeout(TimeoutManager::timeout_type timeout);
|
||||
|
||||
/**
|
||||
* Cancel the timeout, if it is running.
|
||||
@@ -151,6 +152,72 @@ class AsyncTimeout : private boost::noncopyable {
|
||||
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(int fd, short events, void* arg);
|
||||
|
||||
@@ -167,4 +234,59 @@ class AsyncTimeout : private boost::noncopyable {
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
} // folly
|
||||
|
||||
@@ -781,7 +781,7 @@ void EventBase::detachTimeoutManager(AsyncTimeout* obj) {
|
||||
}
|
||||
|
||||
bool EventBase::scheduleTimeout(AsyncTimeout* obj,
|
||||
std::chrono::milliseconds timeout) {
|
||||
TimeoutManager::timeout_type timeout) {
|
||||
assert(isInEventBaseThread());
|
||||
// Set up the timeval and add the event
|
||||
struct timeval tv;
|
||||
|
||||
@@ -575,7 +575,7 @@ bool runImmediatelyOrRunInEventBaseThreadAndWait(const Cob& fn);
|
||||
|
||||
void detachTimeoutManager(AsyncTimeout* obj) override;
|
||||
|
||||
bool scheduleTimeout(AsyncTimeout* obj, std::chrono::milliseconds timeout)
|
||||
bool scheduleTimeout(AsyncTimeout* obj, TimeoutManager::timeout_type timeout)
|
||||
override;
|
||||
|
||||
void cancelTimeout(AsyncTimeout* obj) override;
|
||||
|
||||
@@ -34,6 +34,8 @@ class AsyncTimeout;
|
||||
*/
|
||||
class TimeoutManager {
|
||||
public:
|
||||
typedef std::chrono::milliseconds timeout_type;
|
||||
|
||||
enum class InternalEnum {
|
||||
INTERNAL,
|
||||
NORMAL
|
||||
@@ -52,7 +54,7 @@ class TimeoutManager {
|
||||
* Schedules AsyncTimeout to fire after `timeout` milliseconds
|
||||
*/
|
||||
virtual bool scheduleTimeout(AsyncTimeout* obj,
|
||||
std::chrono::milliseconds timeout) = 0;
|
||||
timeout_type timeout) = 0;
|
||||
|
||||
/**
|
||||
* Cancels the AsyncTimeout, if scheduled
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2015 Facebook, Inc.
|
||||
*
|
||||
* 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 <folly/io/async/AsyncTimeout.h>
|
||||
#include <folly/io/async/EventBase.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace folly {
|
||||
|
||||
TEST(AsyncTimeout, make) {
|
||||
int value = 0;
|
||||
int const expected = 10;
|
||||
EventBase manager;
|
||||
|
||||
auto observer = AsyncTimeout::make(
|
||||
manager,
|
||||
[&]() noexcept { value = expected; }
|
||||
);
|
||||
|
||||
observer->scheduleTimeout(std::chrono::milliseconds(100));
|
||||
|
||||
manager.loop();
|
||||
|
||||
EXPECT_EQ(expected, value);
|
||||
}
|
||||
|
||||
TEST(AsyncTimeout, schedule) {
|
||||
int value = 0;
|
||||
int const expected = 10;
|
||||
EventBase manager;
|
||||
|
||||
auto observer = AsyncTimeout::schedule(
|
||||
std::chrono::milliseconds(100),
|
||||
manager,
|
||||
[&]() noexcept { value = expected; }
|
||||
);
|
||||
|
||||
manager.loop();
|
||||
|
||||
EXPECT_EQ(expected, value);
|
||||
}
|
||||
|
||||
TEST(AsyncTimeout, cancel_make) {
|
||||
int value = 0;
|
||||
int const expected = 10;
|
||||
EventBase manager;
|
||||
|
||||
auto observer = AsyncTimeout::make(
|
||||
manager,
|
||||
[&]() noexcept { value = expected; }
|
||||
);
|
||||
|
||||
observer->scheduleTimeout(std::chrono::milliseconds(100));
|
||||
observer->cancelTimeout();
|
||||
|
||||
manager.loop();
|
||||
|
||||
EXPECT_NE(expected, value);
|
||||
}
|
||||
|
||||
TEST(AsyncTimeout, cancel_schedule) {
|
||||
int value = 0;
|
||||
int const expected = 10;
|
||||
EventBase manager;
|
||||
|
||||
auto observer = AsyncTimeout::schedule(
|
||||
std::chrono::milliseconds(100),
|
||||
manager,
|
||||
[&]() noexcept { value = expected; }
|
||||
);
|
||||
|
||||
observer->cancelTimeout();
|
||||
|
||||
manager.loop();
|
||||
|
||||
EXPECT_NE(expected, value);
|
||||
}
|
||||
|
||||
} // namespace folly {
|
||||
Reference in New Issue
Block a user