f197d7c72a
-- 1a5fb4eb5bc6c0332962f659470a07908168aa5c by CJ Johnson <johnsoncj@google.com>: Move InlinedVector's AbslHashValue(...) definition to out of line PiperOrigin-RevId: 224389234 -- b7c5ccdfe17b9cb5f7124c8d591ce0989a15b9fb by Jon Cohen <cohenjon@google.com>: Add a shebang line and chmod +x generate_copts.py. Note that we use the "python" command as suggested in PEP 934 (https://www.python.org/dev/peps/pep-0394/) as this script should work in both Python 2 and Python 3. Also adds a gitignore for __pycache__ for when using python3 PiperOrigin-RevId: 224375405 -- c57a148a1106b21dbcd750541f10b058bf55a2bf by CJ Johnson <johnsoncj@google.com>: Adds comment to InlinedVector intended to help the g4 diffing algo to better identify the substantive change PiperOrigin-RevId: 224362807 -- b635ab981a07dc2434be7b0d164030a42cc67923 by Greg Falcon <gfalcon@google.com>: internal change PiperOrigin-RevId: 224362442 -- 217021f7dcec31141a89b91930c241af062c2133 by CJ Johnson <johnsoncj@google.com>: Distinguishes the source of InlinedVector::at(...)'s bounds checking exception PiperOrigin-RevId: 224341645 -- 01a5943560ce9216a9d8ccb1279b5c5c2f6e1019 by CJ Johnson <johnsoncj@google.com>: Relocates out of line member function definitions to their respective declarations in InlinedVector PiperOrigin-RevId: 224320130 -- b3d57fcddcd737e91aab812d69b82fef2ca43d7e by Abseil Team <absl-team@google.com>: On 32-bit systems, the alignment of int64 can be 4 bytes. Created a custom Int64 type (to go with the custom Int128 type) just for the purpose of testing layouts and alignments; it doesn't need to support actual arithmetic. PiperOrigin-RevId: 224209785 GitOrigin-RevId: 1a5fb4eb5bc6c0332962f659470a07908168aa5c Change-Id: I9d6b1c441cd712709ebd6c0a8911d0755cab506f
103 lines
3 KiB
C++
103 lines
3 KiB
C++
// Copyright 2017 The Abseil Authors.
|
|
//
|
|
// 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 "absl/base/call_once.h"
|
|
|
|
#include <thread>
|
|
#include <vector>
|
|
|
|
#include "gtest/gtest.h"
|
|
#include "absl/base/attributes.h"
|
|
#include "absl/base/thread_annotations.h"
|
|
#include "absl/synchronization/mutex.h"
|
|
|
|
namespace absl {
|
|
namespace {
|
|
|
|
absl::once_flag once;
|
|
Mutex counters_mu;
|
|
|
|
int running_thread_count GUARDED_BY(counters_mu) = 0;
|
|
int call_once_invoke_count GUARDED_BY(counters_mu) = 0;
|
|
int call_once_finished_count GUARDED_BY(counters_mu) = 0;
|
|
int call_once_return_count GUARDED_BY(counters_mu) = 0;
|
|
bool done_blocking GUARDED_BY(counters_mu) = false;
|
|
|
|
// Function to be called from absl::call_once. Waits for a notification.
|
|
void WaitAndIncrement() {
|
|
counters_mu.Lock();
|
|
++call_once_invoke_count;
|
|
counters_mu.Unlock();
|
|
|
|
counters_mu.LockWhen(Condition(&done_blocking));
|
|
++call_once_finished_count;
|
|
counters_mu.Unlock();
|
|
}
|
|
|
|
void ThreadBody() {
|
|
counters_mu.Lock();
|
|
++running_thread_count;
|
|
counters_mu.Unlock();
|
|
|
|
absl::call_once(once, WaitAndIncrement);
|
|
|
|
counters_mu.Lock();
|
|
++call_once_return_count;
|
|
counters_mu.Unlock();
|
|
}
|
|
|
|
// Returns true if all threads are set up for the test.
|
|
bool ThreadsAreSetup(void*) EXCLUSIVE_LOCKS_REQUIRED(counters_mu) {
|
|
// All ten threads must be running, and WaitAndIncrement should be blocked.
|
|
return running_thread_count == 10 && call_once_invoke_count == 1;
|
|
}
|
|
|
|
TEST(CallOnceTest, ExecutionCount) {
|
|
std::vector<std::thread> threads;
|
|
|
|
// Start 10 threads all calling call_once on the same once_flag.
|
|
for (int i = 0; i < 10; ++i) {
|
|
threads.emplace_back(ThreadBody);
|
|
}
|
|
|
|
|
|
// Wait until all ten threads have started, and WaitAndIncrement has been
|
|
// invoked.
|
|
counters_mu.LockWhen(Condition(ThreadsAreSetup, nullptr));
|
|
|
|
// WaitAndIncrement should have been invoked by exactly one call_once()
|
|
// instance. That thread should be blocking on a notification, and all other
|
|
// call_once instances should be blocking as well.
|
|
EXPECT_EQ(call_once_invoke_count, 1);
|
|
EXPECT_EQ(call_once_finished_count, 0);
|
|
EXPECT_EQ(call_once_return_count, 0);
|
|
|
|
// Allow WaitAndIncrement to finish executing. Once it does, the other
|
|
// call_once waiters will be unblocked.
|
|
done_blocking = true;
|
|
counters_mu.Unlock();
|
|
|
|
for (std::thread& thread : threads) {
|
|
thread.join();
|
|
}
|
|
|
|
counters_mu.Lock();
|
|
EXPECT_EQ(call_once_invoke_count, 1);
|
|
EXPECT_EQ(call_once_finished_count, 1);
|
|
EXPECT_EQ(call_once_return_count, 10);
|
|
counters_mu.Unlock();
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace absl
|