#include <boost/noncopyable.hpp>
#include <event.h>
#include <memory>
+#include <utility>
namespace folly {
* 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.
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);
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
--- /dev/null
+/*
+ * 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 {