summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgroby@chromium.org <groby@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-24 15:00:33 +0000
committergroby@chromium.org <groby@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-24 15:00:33 +0000
commit285d06fced9e6778985c50778327d64f29300174 (patch)
tree62df99ebde4d3b082f5ade19a31249e55ac06ac9
parent213fcfcf37c64ea18ebe2adc82a05c469a479d39 (diff)
downloadchromium_src-285d06fced9e6778985c50778327d64f29300174.zip
chromium_src-285d06fced9e6778985c50778327d64f29300174.tar.gz
chromium_src-285d06fced9e6778985c50778327d64f29300174.tar.bz2
Add a BarrierClosure.
Chromium frequently needs to execute a "final" closure once a given number of other callbacks have run. BarrierClosure encapsulates that logic while staying as light-weight as possible. TBR=gbillock@chromium.org, willchan@chromium.org BUG=none Review URL: https://chromiumcodereview.appspot.com/22859056 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@219446 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/barrier_closure.cc52
-rw-r--r--base/barrier_closure.h30
-rw-r--r--base/barrier_closure_unittest.cc36
-rw-r--r--base/base.gyp1
-rw-r--r--base/base.gypi2
5 files changed, 121 insertions, 0 deletions
diff --git a/base/barrier_closure.cc b/base/barrier_closure.cc
new file mode 100644
index 0000000..65e9c086
--- /dev/null
+++ b/base/barrier_closure.cc
@@ -0,0 +1,52 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/barrier_closure.h"
+
+#include "base/atomic_ref_count.h"
+#include "base/bind.h"
+
+namespace {
+
+// Maintains state for a BarrierClosure.
+class BarrierInfo {
+ public:
+ BarrierInfo(int num_callbacks_left, const base::Closure& done_closure);
+ void Run();
+
+ private:
+ base::AtomicRefCount num_callbacks_left_;
+ base::Closure done_closure_;
+};
+
+BarrierInfo::BarrierInfo(int num_callbacks, const base::Closure& done_closure)
+ : num_callbacks_left_(num_callbacks),
+ done_closure_(done_closure) {
+}
+
+void BarrierInfo::Run() {
+ DCHECK(!base::AtomicRefCountIsZero(&num_callbacks_left_));
+ if (!base::AtomicRefCountDec(&num_callbacks_left_)) {
+ done_closure_.Run();
+ done_closure_.Reset();
+ }
+}
+
+} // namespace
+
+namespace base {
+
+base::Closure BarrierClosure(int num_callbacks_left,
+ const base::Closure& done_closure) {
+ DCHECK(num_callbacks_left >= 0);
+
+ if (num_callbacks_left == 0)
+ done_closure.Run();
+
+ return base::Bind(&BarrierInfo::Run,
+ base::Owned(
+ new BarrierInfo(num_callbacks_left, done_closure)));
+}
+
+} // namespace base \ No newline at end of file
diff --git a/base/barrier_closure.h b/base/barrier_closure.h
new file mode 100644
index 0000000..2fb870f
--- /dev/null
+++ b/base/barrier_closure.h
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BARRIER_CLOSURE_H_
+#define BASE_BARRIER_CLOSURE_H_
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+
+namespace base {
+
+// BarrierClosure executes |done_closure| after it has been invoked
+// |num_closures| times.
+//
+// If |num_closures| is 0, |done_closure| is executed immediately.
+//
+// BarrierClosure is thread-safe - the count of remaining closures is
+// maintained as a base::AtomicRefCount. |done_closure| will be run on
+// the thread that calls the final Run() on the returned closures.
+//
+// |done_closure| is also Reset() on the final calling thread but due to the
+// refcounted nature of callbacks, it is hard to know what thread resources
+// will be released on.
+BASE_EXPORT base::Closure BarrierClosure(int num_closures,
+ const base::Closure& done_closure);
+
+} // namespace base
+
+#endif // BASE_BARRIER_CLOSURE_H_ \ No newline at end of file
diff --git a/base/barrier_closure_unittest.cc b/base/barrier_closure_unittest.cc
new file mode 100644
index 0000000..ab05cb8
--- /dev/null
+++ b/base/barrier_closure_unittest.cc
@@ -0,0 +1,36 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/barrier_closure.h"
+
+#include "base/bind.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void Increment(int* count) { (*count)++; }
+
+TEST(BarrierClosureTest, RunImmediatelyForZeroClosures) {
+ int count = 0;
+ base::Closure doneClosure(base::Bind(&Increment, base::Unretained(&count)));
+
+ base::Closure barrierClosure = base::BarrierClosure(0, doneClosure);
+ EXPECT_EQ(1, count);
+}
+
+TEST(BarrierClosureTest, RunAfterNumClosures) {
+ int count = 0;
+ base::Closure doneClosure(base::Bind(&Increment, base::Unretained(&count)));
+
+ base::Closure barrierClosure = base::BarrierClosure(2, doneClosure);
+ EXPECT_EQ(0, count);
+
+ barrierClosure.Run();
+ EXPECT_EQ(0, count);
+
+ barrierClosure.Run();
+ EXPECT_EQ(1, count);
+}
+
+} // namespace
diff --git a/base/base.gyp b/base/base.gyp
index 2600754..39e9f33 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -453,6 +453,7 @@
'async_socket_io_handler_unittest.cc',
'at_exit_unittest.cc',
'atomicops_unittest.cc',
+ 'barrier_closure_unittest.cc',
'base64_unittest.cc',
'bind_helpers_unittest.cc',
'bind_unittest.cc',
diff --git a/base/base.gypi b/base/base.gypi
index e22aa2e..fce37f6 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -78,6 +78,8 @@
'atomicops_internals_x86_gcc.cc',
'atomicops_internals_x86_gcc.h',
'atomicops_internals_x86_msvc.h',
+ 'barrier_closure.cc',
+ 'barrier_closure.h',
'base_export.h',
'base_paths.cc',
'base_paths.h',