Commit 383448cd authored by Gabriel Charette's avatar Gabriel Charette Committed by Commit Bot

[base] Add TaskRunner::PostTaskAndReplyWithResult

As discussed @ https://groups.google.com/a/chromium.org/g/scheduler-dev/c/xQkcxeoMuyw

This is blocking migration of
base::PostTaskAndReplyWithResult(FROM_HERE, {BrowserThread::UI, ...);
to
content::GetUIThreadTaskRunner({})->PostTaskAndReplyWithResult(FROM_HERE, ...);

Tests copied from task_runner_util_unittest.cc.
Will migrate callers in a follow-up.

R=ajwong@chromium.org

Bug: 1026641
Change-Id: I6fe1b29238a23001d02b9d86da142dd071b39128
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2076423Reviewed-by: default avatarAlbert J. Wong <ajwong@chromium.org>
Commit-Queue: Gabriel Charette <gab@chromium.org>
Auto-Submit: Gabriel Charette <gab@chromium.org>
Cr-Commit-Position: refs/heads/master@{#746049}
parent 54ec1447
......@@ -2705,6 +2705,7 @@ test("base_unittests") {
"task/thread_pool/tracked_ref_unittest.cc",
"task/thread_pool/worker_thread_stack_unittest.cc",
"task/thread_pool/worker_thread_unittest.cc",
"task_runner_unittest.cc",
"task_runner_util_unittest.cc",
"template_util_unittest.cc",
"test/gmock_callback_support_unittest.cc",
......
......@@ -10,7 +10,9 @@
#include "base/base_export.h"
#include "base/callback.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/post_task_and_reply_with_result_internal.h"
#include "base/time/time.h"
namespace base {
......@@ -115,6 +117,36 @@ class BASE_EXPORT TaskRunner
OnceClosure task,
OnceClosure reply);
// When you have these methods
//
// R DoWorkAndReturn();
// void Callback(const R& result);
//
// and want to call them in a PostTaskAndReply kind of fashion where the
// result of DoWorkAndReturn is passed to the Callback, you can use
// PostTaskAndReplyWithResult as in this example:
//
// PostTaskAndReplyWithResult(
// target_thread_.task_runner(),
// FROM_HERE,
// BindOnce(&DoWorkAndReturn),
// BindOnce(&Callback));
template <typename TaskReturnType, typename ReplyArgType>
bool PostTaskAndReplyWithResult(const Location& from_here,
OnceCallback<TaskReturnType()> task,
OnceCallback<void(ReplyArgType)> reply) {
DCHECK(task);
DCHECK(reply);
// std::unique_ptr used to avoid the need of a default constructor.
auto* result = new std::unique_ptr<TaskReturnType>();
return PostTaskAndReply(
from_here,
BindOnce(&internal::ReturnAsParamAdapter<TaskReturnType>,
std::move(task), result),
BindOnce(&internal::ReplyAdapter<TaskReturnType, ReplyArgType>,
std::move(reply), Owned(result)));
}
protected:
friend struct TaskRunnerTraits;
......
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/task_runner_util.h"
#include <utility>
#include "base/bind.h"
#include "base/location.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace {
int ReturnFourtyTwo() {
return 42;
}
void StoreValue(int* destination, int value) {
*destination = value;
}
void StoreDoubleValue(double* destination, double value) {
*destination = value;
}
int g_foo_destruct_count = 0;
int g_foo_free_count = 0;
struct Foo {
~Foo() { ++g_foo_destruct_count; }
};
std::unique_ptr<Foo> CreateFoo() {
return std::unique_ptr<Foo>(new Foo);
}
void ExpectFoo(std::unique_ptr<Foo> foo) {
EXPECT_TRUE(foo.get());
std::unique_ptr<Foo> local_foo(std::move(foo));
EXPECT_TRUE(local_foo.get());
EXPECT_FALSE(foo.get());
}
struct FooDeleter {
void operator()(Foo* foo) const {
++g_foo_free_count;
delete foo;
}
};
std::unique_ptr<Foo, FooDeleter> CreateScopedFoo() {
return std::unique_ptr<Foo, FooDeleter>(new Foo);
}
void ExpectScopedFoo(std::unique_ptr<Foo, FooDeleter> foo) {
EXPECT_TRUE(foo.get());
std::unique_ptr<Foo, FooDeleter> local_foo(std::move(foo));
EXPECT_TRUE(local_foo.get());
EXPECT_FALSE(foo.get());
}
struct FooWithoutDefaultConstructor {
explicit FooWithoutDefaultConstructor(int value) : value(value) {}
int value;
};
FooWithoutDefaultConstructor CreateFooWithoutDefaultConstructor(int value) {
return FooWithoutDefaultConstructor(value);
}
void SaveFooWithoutDefaultConstructor(int* output_value,
FooWithoutDefaultConstructor input) {
*output_value = input.value;
}
class TaskRunnerTest : public testing::Test {
public:
TaskRunnerTest() = default;
void SetUp() override {
g_foo_destruct_count = 0;
g_foo_free_count = 0;
}
};
} // namespace
TEST_F(TaskRunnerTest, PostTaskAndReplyWithResult) {
int result = 0;
test::SingleThreadTaskEnvironment task_environment;
ThreadTaskRunnerHandle::Get()->PostTaskAndReplyWithResult(
FROM_HERE, BindOnce(&ReturnFourtyTwo), BindOnce(&StoreValue, &result));
RunLoop().RunUntilIdle();
EXPECT_EQ(42, result);
}
TEST_F(TaskRunnerTest, PostTaskAndReplyWithResultImplicitConvert) {
double result = 0;
test::SingleThreadTaskEnvironment task_environment;
ThreadTaskRunnerHandle::Get()->PostTaskAndReplyWithResult(
FROM_HERE, BindOnce(&ReturnFourtyTwo),
BindOnce(&StoreDoubleValue, &result));
RunLoop().RunUntilIdle();
EXPECT_DOUBLE_EQ(42.0, result);
}
TEST_F(TaskRunnerTest, PostTaskAndReplyWithResultPassed) {
test::SingleThreadTaskEnvironment task_environment;
ThreadTaskRunnerHandle::Get()->PostTaskAndReplyWithResult(
FROM_HERE, BindOnce(&CreateFoo), BindOnce(&ExpectFoo));
RunLoop().RunUntilIdle();
EXPECT_EQ(1, g_foo_destruct_count);
EXPECT_EQ(0, g_foo_free_count);
}
TEST_F(TaskRunnerTest, PostTaskAndReplyWithResultPassedFreeProc) {
test::SingleThreadTaskEnvironment task_environment;
ThreadTaskRunnerHandle::Get()->PostTaskAndReplyWithResult(
FROM_HERE, BindOnce(&CreateScopedFoo), BindOnce(&ExpectScopedFoo));
RunLoop().RunUntilIdle();
EXPECT_EQ(1, g_foo_destruct_count);
EXPECT_EQ(1, g_foo_free_count);
}
TEST_F(TaskRunnerTest, PostTaskAndReplyWithResultWithoutDefaultConstructor) {
const int kSomeVal = 17;
test::SingleThreadTaskEnvironment task_environment;
int actual = 0;
ThreadTaskRunnerHandle::Get()->PostTaskAndReplyWithResult(
FROM_HERE, BindOnce(&CreateFooWithoutDefaultConstructor, kSomeVal),
BindOnce(&SaveFooWithoutDefaultConstructor, &actual));
RunLoop().RunUntilIdle();
EXPECT_EQ(kSomeVal, actual);
}
} // namespace base
......@@ -9,13 +9,16 @@
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/post_task_and_reply_with_result_internal.h"
#include "base/task_runner.h"
// TODO: Remove these unused includes after fixing IWYU usage in
// affected files.
#include "base/bind_helpers.h"
#include "base/callback_helpers.h"
namespace base {
// When you have these methods
......@@ -32,6 +35,10 @@ namespace base {
// FROM_HERE,
// BindOnce(&DoWorkAndReturn),
// BindOnce(&Callback));
//
// DEPRECATED: Prefer calling|task_runner->PostTaskAndReplyWithResult(...)|
// directly.
// TODO(gab): Mass-migrate to the member method.
template <typename TaskReturnType, typename ReplyArgType>
bool PostTaskAndReplyWithResult(TaskRunner* task_runner,
const Location& from_here,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment