summaryrefslogtreecommitdiff
path: root/absl/synchronization
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2021-05-12 17:01:06 -0700
committerGravatar vslashg <gfalcon@google.com>2021-05-12 20:28:41 -0400
commitce42de10fbea616379826e91c7c23c16bffe6e61 (patch)
tree84e546f054980b875f6be1a6eb3a9256a5b88ba5 /absl/synchronization
parent7ba826e50dff1878e6ecc6b9af44097c040c8968 (diff)
Export of internal Abseil changes
-- 9fc37c11b9e46287acef00ee06ed9adcba54dd13 by Greg Falcon <gfalcon@google.com>: Rename absl::hash_internal::HashState to absl::hash_internal::MixingHashState. Before this change, we had two classes named HashState: absl::HashState, the public API used for type erasure, and absl::hash_internal::HashState, the internal concrete implementation ordinarily used. The internal class used to be named `CityHashState`, but we renamed it to `HashState` it when we changed underlying hash implementation to wyhash. This inadvertent naming conflict made the code much harder to read, and this change intends to undo that. PiperOrigin-RevId: 373481959 -- 4aec55ffddebd085c239352a2e20721091f719a1 by Greg Falcon <gfalcon@google.com>: Introduce absl::HashOf(), a convenience wrapper around absl::Hash that calculates hashes from the values of its arguments. PiperOrigin-RevId: 373461406 -- 86b5fd8db50bbc8bd0aa9258523527381fe0445d by Abseil Team <absl-team@google.com>: Improve speed of BlockingCounter by making its most common path lock free. With the new implementation, the fast path of BlockingCounter::DecrementCount() is only a fetch_sub operation. This is most times much more efficient than the previous implementation (full mutex lock/unlock). As a matter of fact, in most actual usecases in practice, the waiter thread is already waiting on the Wait() call when DecrementCount() is called, which makes Mutex::Unlock() take the slow path as there's a waiter thread that it might need to wake up. PiperOrigin-RevId: 373394164 -- 65c876be5eac0cd32583ff8535ede4109d39cf3f by Martijn Vels <mvels@google.com>: Move the 'sample copied cord' logic into MaybeTrackCord(), This changes move the logic for selecting if a cord should remain being sampled from Cord to CordzInfo::MaybeTrackCord, and updates the documentation for the latter method. PiperOrigin-RevId: 373363168 -- e84410bd0aada293a81dfb82656c952e209e21fb by Martijn Vels <mvels@google.com>: Add check for the first call to cordz_should_profile() for each thread. This prevents the first cord of a newly created thread to be always sampled, which is a 'bad' kind of determinism for sampling. PiperOrigin-RevId: 373229768 -- bf09c589dc099ac8f4af780bf7e609c53c27574c by Samuel Benzaquen <sbenza@google.com>: Refactor the Flags structure into an enum. This gives us more control over the representation and allows for easier merging during parsing. PiperOrigin-RevId: 373163038 -- b947b0c51083b7b6508284b5d31819596c91729e by Derek Mauro <dmauro@google.com>: Fixes warnings about shadowed variables Fixes #956 PiperOrigin-RevId: 373158133 GitOrigin-RevId: 9fc37c11b9e46287acef00ee06ed9adcba54dd13 Change-Id: I91f35699f9bf439d1a870c6493946a310afe088c
Diffstat (limited to 'absl/synchronization')
-rw-r--r--absl/synchronization/blocking_counter.cc40
-rw-r--r--absl/synchronization/blocking_counter.h8
-rw-r--r--absl/synchronization/blocking_counter_test.cc12
3 files changed, 42 insertions, 18 deletions
diff --git a/absl/synchronization/blocking_counter.cc b/absl/synchronization/blocking_counter.cc
index 3cea7aed..d2f82da3 100644
--- a/absl/synchronization/blocking_counter.cc
+++ b/absl/synchronization/blocking_counter.cc
@@ -14,41 +14,51 @@
#include "absl/synchronization/blocking_counter.h"
+#include <atomic>
+
#include "absl/base/internal/raw_logging.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
-// Return whether int *arg is zero.
-static bool IsZero(void *arg) {
- return 0 == *reinterpret_cast<int *>(arg);
+namespace {
+
+// Return whether int *arg is true.
+bool IsDone(void *arg) { return *reinterpret_cast<bool *>(arg); }
+
+} // namespace
+
+BlockingCounter::BlockingCounter(int initial_count)
+ : count_(initial_count),
+ num_waiting_(0),
+ done_{initial_count == 0 ? true : false} {
+ ABSL_RAW_CHECK(initial_count >= 0, "BlockingCounter initial_count negative");
}
bool BlockingCounter::DecrementCount() {
- MutexLock l(&lock_);
- count_--;
- if (count_ < 0) {
- ABSL_RAW_LOG(
- FATAL,
- "BlockingCounter::DecrementCount() called too many times. count=%d",
- count_);
+ int count = count_.fetch_sub(1, std::memory_order_acq_rel) - 1;
+ ABSL_RAW_CHECK(count >= 0,
+ "BlockingCounter::DecrementCount() called too many times");
+ if (count == 0) {
+ MutexLock l(&lock_);
+ done_ = true;
+ return true;
}
- return count_ == 0;
+ return false;
}
void BlockingCounter::Wait() {
MutexLock l(&this->lock_);
- ABSL_RAW_CHECK(count_ >= 0, "BlockingCounter underflow");
// only one thread may call Wait(). To support more than one thread,
// implement a counter num_to_exit, like in the Barrier class.
ABSL_RAW_CHECK(num_waiting_ == 0, "multiple threads called Wait()");
num_waiting_++;
- this->lock_.Await(Condition(IsZero, &this->count_));
+ this->lock_.Await(Condition(IsDone, &this->done_));
- // At this point, We know that all threads executing DecrementCount have
- // released the lock, and so will not touch this object again.
+ // At this point, we know that all threads executing DecrementCount
+ // will not touch this object again.
// Therefore, the thread calling this method is free to delete the object
// after we return from this method.
}
diff --git a/absl/synchronization/blocking_counter.h b/absl/synchronization/blocking_counter.h
index 1f53f9f2..1908fdb1 100644
--- a/absl/synchronization/blocking_counter.h
+++ b/absl/synchronization/blocking_counter.h
@@ -20,6 +20,8 @@
#ifndef ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_
#define ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_
+#include <atomic>
+
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
@@ -60,8 +62,7 @@ ABSL_NAMESPACE_BEGIN
//
class BlockingCounter {
public:
- explicit BlockingCounter(int initial_count)
- : count_(initial_count), num_waiting_(0) {}
+ explicit BlockingCounter(int initial_count);
BlockingCounter(const BlockingCounter&) = delete;
BlockingCounter& operator=(const BlockingCounter&) = delete;
@@ -89,8 +90,9 @@ class BlockingCounter {
private:
Mutex lock_;
- int count_ ABSL_GUARDED_BY(lock_);
+ std::atomic<int> count_;
int num_waiting_ ABSL_GUARDED_BY(lock_);
+ bool done_ ABSL_GUARDED_BY(lock_);
};
ABSL_NAMESPACE_END
diff --git a/absl/synchronization/blocking_counter_test.cc b/absl/synchronization/blocking_counter_test.cc
index 2926224a..06885f57 100644
--- a/absl/synchronization/blocking_counter_test.cc
+++ b/absl/synchronization/blocking_counter_test.cc
@@ -63,6 +63,18 @@ TEST(BlockingCounterTest, BasicFunctionality) {
}
}
+TEST(BlockingCounterTest, WaitZeroInitialCount) {
+ BlockingCounter counter(0);
+ counter.Wait();
+}
+
+#if GTEST_HAS_DEATH_TEST
+TEST(BlockingCounterTest, WaitNegativeInitialCount) {
+ EXPECT_DEATH(BlockingCounter counter(-1),
+ "BlockingCounter initial_count negative");
+}
+#endif
+
} // namespace
ABSL_NAMESPACE_END
} // namespace absl