1*9356374aSAndroid Build Coastguard Worker // Copyright 2017 The Abseil Authors.
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker
15*9356374aSAndroid Build Coastguard Worker #include "absl/synchronization/notification.h"
16*9356374aSAndroid Build Coastguard Worker
17*9356374aSAndroid Build Coastguard Worker #include <thread> // NOLINT(build/c++11)
18*9356374aSAndroid Build Coastguard Worker #include <vector>
19*9356374aSAndroid Build Coastguard Worker
20*9356374aSAndroid Build Coastguard Worker #include "gtest/gtest.h"
21*9356374aSAndroid Build Coastguard Worker #include "absl/synchronization/mutex.h"
22*9356374aSAndroid Build Coastguard Worker
23*9356374aSAndroid Build Coastguard Worker namespace absl {
24*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
25*9356374aSAndroid Build Coastguard Worker
26*9356374aSAndroid Build Coastguard Worker // A thread-safe class that holds a counter.
27*9356374aSAndroid Build Coastguard Worker class ThreadSafeCounter {
28*9356374aSAndroid Build Coastguard Worker public:
ThreadSafeCounter()29*9356374aSAndroid Build Coastguard Worker ThreadSafeCounter() : count_(0) {}
30*9356374aSAndroid Build Coastguard Worker
Increment()31*9356374aSAndroid Build Coastguard Worker void Increment() {
32*9356374aSAndroid Build Coastguard Worker MutexLock lock(&mutex_);
33*9356374aSAndroid Build Coastguard Worker ++count_;
34*9356374aSAndroid Build Coastguard Worker }
35*9356374aSAndroid Build Coastguard Worker
Get() const36*9356374aSAndroid Build Coastguard Worker int Get() const {
37*9356374aSAndroid Build Coastguard Worker MutexLock lock(&mutex_);
38*9356374aSAndroid Build Coastguard Worker return count_;
39*9356374aSAndroid Build Coastguard Worker }
40*9356374aSAndroid Build Coastguard Worker
WaitUntilGreaterOrEqual(int n)41*9356374aSAndroid Build Coastguard Worker void WaitUntilGreaterOrEqual(int n) {
42*9356374aSAndroid Build Coastguard Worker MutexLock lock(&mutex_);
43*9356374aSAndroid Build Coastguard Worker auto cond = [this, n]() { return count_ >= n; };
44*9356374aSAndroid Build Coastguard Worker mutex_.Await(Condition(&cond));
45*9356374aSAndroid Build Coastguard Worker }
46*9356374aSAndroid Build Coastguard Worker
47*9356374aSAndroid Build Coastguard Worker private:
48*9356374aSAndroid Build Coastguard Worker mutable Mutex mutex_;
49*9356374aSAndroid Build Coastguard Worker int count_;
50*9356374aSAndroid Build Coastguard Worker };
51*9356374aSAndroid Build Coastguard Worker
52*9356374aSAndroid Build Coastguard Worker // Runs the |i|'th worker thread for the tests in BasicTests(). Increments the
53*9356374aSAndroid Build Coastguard Worker // |ready_counter|, waits on the |notification|, and then increments the
54*9356374aSAndroid Build Coastguard Worker // |done_counter|.
RunWorker(int i,ThreadSafeCounter * ready_counter,Notification * notification,ThreadSafeCounter * done_counter)55*9356374aSAndroid Build Coastguard Worker static void RunWorker(int i, ThreadSafeCounter* ready_counter,
56*9356374aSAndroid Build Coastguard Worker Notification* notification,
57*9356374aSAndroid Build Coastguard Worker ThreadSafeCounter* done_counter) {
58*9356374aSAndroid Build Coastguard Worker ready_counter->Increment();
59*9356374aSAndroid Build Coastguard Worker notification->WaitForNotification();
60*9356374aSAndroid Build Coastguard Worker done_counter->Increment();
61*9356374aSAndroid Build Coastguard Worker }
62*9356374aSAndroid Build Coastguard Worker
63*9356374aSAndroid Build Coastguard Worker // Tests that the |notification| properly blocks and awakens threads. Assumes
64*9356374aSAndroid Build Coastguard Worker // that the |notification| is not yet triggered. If |notify_before_waiting| is
65*9356374aSAndroid Build Coastguard Worker // true, the |notification| is triggered before any threads are created, so the
66*9356374aSAndroid Build Coastguard Worker // threads never block in WaitForNotification(). Otherwise, the |notification|
67*9356374aSAndroid Build Coastguard Worker // is triggered at a later point when most threads are likely to be blocking in
68*9356374aSAndroid Build Coastguard Worker // WaitForNotification().
BasicTests(bool notify_before_waiting,Notification * notification)69*9356374aSAndroid Build Coastguard Worker static void BasicTests(bool notify_before_waiting, Notification* notification) {
70*9356374aSAndroid Build Coastguard Worker EXPECT_FALSE(notification->HasBeenNotified());
71*9356374aSAndroid Build Coastguard Worker EXPECT_FALSE(
72*9356374aSAndroid Build Coastguard Worker notification->WaitForNotificationWithTimeout(absl::Milliseconds(0)));
73*9356374aSAndroid Build Coastguard Worker EXPECT_FALSE(notification->WaitForNotificationWithDeadline(absl::Now()));
74*9356374aSAndroid Build Coastguard Worker
75*9356374aSAndroid Build Coastguard Worker const absl::Duration delay = absl::Milliseconds(50);
76*9356374aSAndroid Build Coastguard Worker const absl::Time start = absl::Now();
77*9356374aSAndroid Build Coastguard Worker EXPECT_FALSE(notification->WaitForNotificationWithTimeout(delay));
78*9356374aSAndroid Build Coastguard Worker const absl::Duration elapsed = absl::Now() - start;
79*9356374aSAndroid Build Coastguard Worker
80*9356374aSAndroid Build Coastguard Worker // Allow for a slight early return, to account for quality of implementation
81*9356374aSAndroid Build Coastguard Worker // issues on various platforms.
82*9356374aSAndroid Build Coastguard Worker const absl::Duration slop = absl::Milliseconds(5);
83*9356374aSAndroid Build Coastguard Worker EXPECT_LE(delay - slop, elapsed)
84*9356374aSAndroid Build Coastguard Worker << "WaitForNotificationWithTimeout returned " << delay - elapsed
85*9356374aSAndroid Build Coastguard Worker << " early (with " << slop << " slop), start time was " << start;
86*9356374aSAndroid Build Coastguard Worker
87*9356374aSAndroid Build Coastguard Worker ThreadSafeCounter ready_counter;
88*9356374aSAndroid Build Coastguard Worker ThreadSafeCounter done_counter;
89*9356374aSAndroid Build Coastguard Worker
90*9356374aSAndroid Build Coastguard Worker if (notify_before_waiting) {
91*9356374aSAndroid Build Coastguard Worker notification->Notify();
92*9356374aSAndroid Build Coastguard Worker }
93*9356374aSAndroid Build Coastguard Worker
94*9356374aSAndroid Build Coastguard Worker // Create a bunch of threads that increment the |done_counter| after being
95*9356374aSAndroid Build Coastguard Worker // notified.
96*9356374aSAndroid Build Coastguard Worker const int kNumThreads = 10;
97*9356374aSAndroid Build Coastguard Worker std::vector<std::thread> workers;
98*9356374aSAndroid Build Coastguard Worker for (int i = 0; i < kNumThreads; ++i) {
99*9356374aSAndroid Build Coastguard Worker workers.push_back(std::thread(&RunWorker, i, &ready_counter, notification,
100*9356374aSAndroid Build Coastguard Worker &done_counter));
101*9356374aSAndroid Build Coastguard Worker }
102*9356374aSAndroid Build Coastguard Worker
103*9356374aSAndroid Build Coastguard Worker if (!notify_before_waiting) {
104*9356374aSAndroid Build Coastguard Worker ready_counter.WaitUntilGreaterOrEqual(kNumThreads);
105*9356374aSAndroid Build Coastguard Worker
106*9356374aSAndroid Build Coastguard Worker // Workers have not been notified yet, so the |done_counter| should be
107*9356374aSAndroid Build Coastguard Worker // unmodified.
108*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(0, done_counter.Get());
109*9356374aSAndroid Build Coastguard Worker
110*9356374aSAndroid Build Coastguard Worker notification->Notify();
111*9356374aSAndroid Build Coastguard Worker }
112*9356374aSAndroid Build Coastguard Worker
113*9356374aSAndroid Build Coastguard Worker // After notifying and then joining the workers, both counters should be
114*9356374aSAndroid Build Coastguard Worker // fully incremented.
115*9356374aSAndroid Build Coastguard Worker notification->WaitForNotification(); // should exit immediately
116*9356374aSAndroid Build Coastguard Worker EXPECT_TRUE(notification->HasBeenNotified());
117*9356374aSAndroid Build Coastguard Worker EXPECT_TRUE(notification->WaitForNotificationWithTimeout(absl::Seconds(0)));
118*9356374aSAndroid Build Coastguard Worker EXPECT_TRUE(notification->WaitForNotificationWithDeadline(absl::Now()));
119*9356374aSAndroid Build Coastguard Worker for (std::thread& worker : workers) {
120*9356374aSAndroid Build Coastguard Worker worker.join();
121*9356374aSAndroid Build Coastguard Worker }
122*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(kNumThreads, ready_counter.Get());
123*9356374aSAndroid Build Coastguard Worker EXPECT_EQ(kNumThreads, done_counter.Get());
124*9356374aSAndroid Build Coastguard Worker }
125*9356374aSAndroid Build Coastguard Worker
TEST(NotificationTest,SanityTest)126*9356374aSAndroid Build Coastguard Worker TEST(NotificationTest, SanityTest) {
127*9356374aSAndroid Build Coastguard Worker Notification local_notification1, local_notification2;
128*9356374aSAndroid Build Coastguard Worker BasicTests(false, &local_notification1);
129*9356374aSAndroid Build Coastguard Worker BasicTests(true, &local_notification2);
130*9356374aSAndroid Build Coastguard Worker }
131*9356374aSAndroid Build Coastguard Worker
132*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
133*9356374aSAndroid Build Coastguard Worker } // namespace absl
134