| /* | 
 |  * Copyright (C) 2023 The Android Open Source Project | 
 |  * | 
 |  * 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 "perfetto/ext/base//threading/thread_pool.h" | 
 | #include <atomic> | 
 | #include <condition_variable> | 
 | #include <mutex> | 
 |  | 
 | #include "perfetto/ext/base/waitable_event.h" | 
 | #include "test/gtest_and_gmock.h" | 
 |  | 
 | namespace perfetto { | 
 | namespace base { | 
 | namespace { | 
 |  | 
 | struct ThreadLatch { | 
 |   base::WaitableEvent notify; | 
 |   base::WaitableEvent wait; | 
 |   bool task_started = false; | 
 | }; | 
 |  | 
 | TEST(ThreadPoolTest, SequentialQueueing) { | 
 |   ThreadLatch first; | 
 |   ThreadLatch second; | 
 |   base::ThreadPool pool(1); | 
 |  | 
 |   pool.PostTask([&first] { | 
 |     first.task_started = true; | 
 |     first.notify.Notify(); | 
 |     first.wait.Wait(); | 
 |   }); | 
 |  | 
 |   pool.PostTask([&second] { | 
 |     second.task_started = true; | 
 |     second.notify.Notify(); | 
 |     second.wait.Wait(); | 
 |   }); | 
 |  | 
 |   first.notify.Wait(); | 
 |   ASSERT_TRUE(first.task_started); | 
 |   ASSERT_FALSE(second.task_started); | 
 |   first.wait.Notify(); | 
 |  | 
 |   second.notify.Wait(); | 
 |   ASSERT_TRUE(second.task_started); | 
 |   second.wait.Notify(); | 
 | } | 
 |  | 
 | TEST(ThreadPoolTest, ParallelSecondFinishFirst) { | 
 |   base::ThreadPool pool(2); | 
 |  | 
 |   ThreadLatch first; | 
 |   pool.PostTask([&first] { | 
 |     first.wait.Wait(); | 
 |     first.task_started = true; | 
 |     first.notify.Notify(); | 
 |   }); | 
 |  | 
 |   ThreadLatch second; | 
 |   pool.PostTask([&second] { | 
 |     second.wait.Wait(); | 
 |     second.task_started = true; | 
 |     second.notify.Notify(); | 
 |   }); | 
 |  | 
 |   second.wait.Notify(); | 
 |   second.notify.Wait(); | 
 |   ASSERT_TRUE(second.task_started); | 
 |  | 
 |   first.wait.Notify(); | 
 |   first.notify.Wait(); | 
 |   ASSERT_TRUE(first.task_started); | 
 | } | 
 |  | 
 | TEST(ThreadPoolTest, StressTest) { | 
 |   std::mutex mu; | 
 |   std::condition_variable cv; | 
 |   uint32_t count = 0; | 
 |   base::ThreadPool pool(128); | 
 |   for (uint32_t i = 0; i < 1024; ++i) { | 
 |     pool.PostTask([&mu, &count, &cv] { | 
 |       std::lock_guard<std::mutex> guard(mu); | 
 |       if (++count == 1024) { | 
 |         cv.notify_one(); | 
 |       } | 
 |     }); | 
 |   } | 
 |  | 
 |   std::unique_lock<std::mutex> lock(mu); | 
 |   cv.wait(lock, [&count]() { return count == 1024u; }); | 
 | } | 
 |  | 
 | }  // namespace | 
 | }  // namespace base | 
 | }  // namespace perfetto |