Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2019 The Chromium Authors |
Etienne Pierre-doray | 9e8b40f | 2019-10-09 16:00:24 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "base/task/post_job.h" |
| 6 | |
Arthur Sonzogni | 0844a99 | 2024-12-12 11:36:20 | [diff] [blame] | 7 | #include <array> |
Etienne Pierre-doray | 9e8b40f | 2019-10-09 16:00:24 | [diff] [blame] | 8 | #include <atomic> |
Etienne Pierre-doray | 2a67d29 | 2020-09-03 05:18:52 | [diff] [blame] | 9 | #include <iterator> |
| 10 | #include <numeric> |
Etienne Pierre-doray | 9e8b40f | 2019-10-09 16:00:24 | [diff] [blame] | 11 | |
Etienne Pierre-doray | d88e66be | 2022-08-03 01:37:46 | [diff] [blame] | 12 | #include "base/barrier_closure.h" |
Guido Urdaneta | ef4e9194 | 2020-11-09 15:06:24 | [diff] [blame] | 13 | #include "base/test/bind.h" |
Etienne Pierre-doray | 9e8b40f | 2019-10-09 16:00:24 | [diff] [blame] | 14 | #include "base/test/gtest_util.h" |
| 15 | #include "base/test/task_environment.h" |
Etienne Pierre-doray | cfe0c45 | 2022-06-01 16:55:24 | [diff] [blame] | 16 | #include "base/test/test_timeouts.h" |
Etienne Pierre-doray | d88e66be | 2022-08-03 01:37:46 | [diff] [blame] | 17 | #include "base/test/test_waitable_event.h" |
Etienne Pierre-doray | cfe0c45 | 2022-06-01 16:55:24 | [diff] [blame] | 18 | #include "base/threading/platform_thread.h" |
Etienne Pierre-doray | 9e8b40f | 2019-10-09 16:00:24 | [diff] [blame] | 19 | #include "testing/gmock/include/gmock/gmock.h" |
| 20 | #include "testing/gtest/include/gtest/gtest.h" |
| 21 | |
| 22 | namespace base { |
| 23 | |
| 24 | TEST(PostJobTest, PostJobSimple) { |
| 25 | test::TaskEnvironment task_environment; |
| 26 | std::atomic_size_t num_tasks_to_run(4); |
Etienne Pierre-doray | 35b691e | 2020-01-31 14:36:10 | [diff] [blame] | 27 | auto handle = PostJob( |
Gabriel Charette | 7d5eac0 | 2020-01-28 13:37:13 | [diff] [blame] | 28 | FROM_HERE, {}, |
Etienne Pierre-doray | 35b691e | 2020-01-31 14:36:10 | [diff] [blame] | 29 | BindLambdaForTesting([&](JobDelegate* delegate) { --num_tasks_to_run; }), |
Etienne Pierre-doray | 2f52b351 | 2020-08-12 19:04:29 | [diff] [blame] | 30 | BindLambdaForTesting( |
| 31 | [&](size_t /*worker_count*/) -> size_t { return num_tasks_to_run; })); |
Etienne Pierre-doray | 9e8b40f | 2019-10-09 16:00:24 | [diff] [blame] | 32 | handle.Join(); |
Etienne Pierre-doray | cfe0c45 | 2022-06-01 16:55:24 | [diff] [blame] | 33 | EXPECT_EQ(num_tasks_to_run, 0U); |
| 34 | } |
| 35 | |
| 36 | TEST(PostJobTest, CreateJobSimple) { |
| 37 | test::TaskEnvironment task_environment; |
| 38 | std::atomic_size_t num_tasks_to_run(4); |
Etienne Pierre-doray | d88e66be | 2022-08-03 01:37:46 | [diff] [blame] | 39 | TestWaitableEvent threads_continue; |
| 40 | RepeatingClosure barrier = BarrierClosure( |
Sorin Jianu | d01ad7f | 2024-10-09 03:45:45 | [diff] [blame] | 41 | num_tasks_to_run, |
| 42 | BindLambdaForTesting([&threads_continue] { threads_continue.Signal(); })); |
Etienne Pierre-doray | cfe0c45 | 2022-06-01 16:55:24 | [diff] [blame] | 43 | bool job_started = false; |
| 44 | auto handle = |
| 45 | CreateJob(FROM_HERE, {}, BindLambdaForTesting([&](JobDelegate* delegate) { |
| 46 | EXPECT_TRUE(job_started); |
Etienne Pierre-doray | d88e66be | 2022-08-03 01:37:46 | [diff] [blame] | 47 | barrier.Run(); |
| 48 | threads_continue.Wait(); |
Etienne Pierre-doray | cfe0c45 | 2022-06-01 16:55:24 | [diff] [blame] | 49 | --num_tasks_to_run; |
| 50 | }), |
| 51 | BindLambdaForTesting([&](size_t /*worker_count*/) -> size_t { |
| 52 | EXPECT_TRUE(job_started); |
| 53 | return num_tasks_to_run; |
| 54 | })); |
| 55 | |
| 56 | PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
| 57 | EXPECT_EQ(num_tasks_to_run, 4U); |
| 58 | job_started = true; |
| 59 | handle.Join(); |
| 60 | EXPECT_EQ(num_tasks_to_run, 0U); |
Etienne Pierre-doray | 9e8b40f | 2019-10-09 16:00:24 | [diff] [blame] | 61 | } |
| 62 | |
Etienne Pierre-doray | 2a67d29 | 2020-09-03 05:18:52 | [diff] [blame] | 63 | // Verify that concurrent accesses with task_id as the only form of |
| 64 | // synchronisation doesn't trigger a race. |
| 65 | TEST(PostJobTest, TaskIds) { |
| 66 | static constexpr size_t kNumConcurrentThreads = 2; |
| 67 | static constexpr size_t kNumTasksToRun = 1000; |
| 68 | base::test::TaskEnvironment task_environment; |
| 69 | |
Arthur Sonzogni | 0844a99 | 2024-12-12 11:36:20 | [diff] [blame] | 70 | std::array<size_t, kNumConcurrentThreads> concurrent_array = {}; |
Etienne Pierre-doray | 2a67d29 | 2020-09-03 05:18:52 | [diff] [blame] | 71 | std::atomic_size_t remaining_tasks{kNumTasksToRun}; |
| 72 | base::JobHandle handle = base::PostJob( |
Javier Flores | 0d0d0a6 | 2021-03-24 12:07:06 | [diff] [blame] | 73 | FROM_HERE, {}, BindLambdaForTesting([&](base::JobDelegate* job) { |
Etienne Pierre-doray | 2a67d29 | 2020-09-03 05:18:52 | [diff] [blame] | 74 | uint8_t id = job->GetTaskId(); |
| 75 | size_t& slot = concurrent_array[id]; |
| 76 | slot++; |
| 77 | --remaining_tasks; |
| 78 | }), |
| 79 | BindLambdaForTesting([&remaining_tasks](size_t) { |
| 80 | return std::min(remaining_tasks.load(), kNumConcurrentThreads); |
| 81 | })); |
| 82 | handle.Join(); |
| 83 | EXPECT_EQ(kNumTasksToRun, std::accumulate(std::begin(concurrent_array), |
| 84 | std::end(concurrent_array), 0U)); |
| 85 | } |
| 86 | |
Gabriel Charette | 7d5eac0 | 2020-01-28 13:37:13 | [diff] [blame] | 87 | } // namespace base |