• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Chromium Authors
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/thread_pool/semaphore.h"
6 
7 #include <memory>
8 #include <vector>
9 
10 #include "base/functional/callback.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/synchronization/lock.h"
13 #include "base/test/bind.h"
14 #include "base/test/test_timeouts.h"
15 #include "base/threading/thread.h"
16 #include "base/time/time.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "testing/platform_test.h"
19 
20 namespace base {
21 
22 namespace {
23 
24 class SemaphoreTest : public PlatformTest {
25  protected:
CreateThreadWithTask(RepeatingClosure & thread_task)26   raw_ptr<Thread> CreateThreadWithTask(RepeatingClosure& thread_task) {
27     std::unique_ptr<Thread> thread = std::make_unique<Thread>(
28         StringPrintf("SemTestThread%d", threadcounter++));
29 
30     thread->Start();
31     thread->task_runner()->PostTask(FROM_HERE, thread_task);
32     threads_.push_back(std::move(thread));
33     return threads_.back().get();
34   }
35 
36   int threadcounter = 0;
37   WaitableEvent shutdown_event_{};
38   std::vector<std::unique_ptr<Thread>> threads_{};
39 };
40 
41 }  // namespace
42 
TEST_F(SemaphoreTest,TimedWaitFail)43 TEST_F(SemaphoreTest, TimedWaitFail) {
44   internal::Semaphore sem{0};
45   RepeatingClosure task = BindLambdaForTesting([&]() {
46     TimeTicks start_time = TimeTicks::Now();
47     EXPECT_FALSE(sem.TimedWait(TestTimeouts::tiny_timeout()));
48     EXPECT_GE(TimeTicks::Now() - start_time, TestTimeouts::tiny_timeout());
49   });
50 
51   CreateThreadWithTask(task)->FlushForTesting();
52 }
53 
TEST_F(SemaphoreTest,TimedWaitSuccess)54 TEST_F(SemaphoreTest, TimedWaitSuccess) {
55   internal::Semaphore sem{0};
56   RepeatingClosure task = BindLambdaForTesting(
57       [&]() { EXPECT_TRUE(sem.TimedWait(TestTimeouts::tiny_timeout())); });
58 
59   sem.Signal();
60   CreateThreadWithTask(task)->FlushForTesting();
61 }
62 
TEST_F(SemaphoreTest,PingPongCounter)63 TEST_F(SemaphoreTest, PingPongCounter) {
64   internal::Semaphore sem{0};
65   int counter = 0;
66   RepeatingClosure task = BindLambdaForTesting([&]() {
67     while (!shutdown_event_.IsSignaled()) {
68       sem.Wait();
69       {
70         if (shutdown_event_.IsSignaled()) {
71           return;
72         }
73       }
74       ++counter;
75       if (counter > 999) {
76         shutdown_event_.Signal();
77       }
78       sem.Signal();
79       PlatformThread::Sleep(Microseconds(100));
80     }
81   });
82 
83   sem.Signal();
84   raw_ptr<Thread> thread = CreateThreadWithTask(task);
85   raw_ptr<Thread> thread2 = CreateThreadWithTask(task);
86   thread->FlushForTesting();
87   thread2->FlushForTesting();
88   thread->Stop();
89   thread2->Stop();
90   EXPECT_EQ(counter, 1000);
91 }
92 
93 }  // namespace base
94