diff options
author | groby@chromium.org <groby@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-24 15:00:33 +0000 |
---|---|---|
committer | groby@chromium.org <groby@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-24 15:00:33 +0000 |
commit | 285d06fced9e6778985c50778327d64f29300174 (patch) | |
tree | 62df99ebde4d3b082f5ade19a31249e55ac06ac9 | |
parent | 213fcfcf37c64ea18ebe2adc82a05c469a479d39 (diff) | |
download | chromium_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.cc | 52 | ||||
-rw-r--r-- | base/barrier_closure.h | 30 | ||||
-rw-r--r-- | base/barrier_closure_unittest.cc | 36 | ||||
-rw-r--r-- | base/base.gyp | 1 | ||||
-rw-r--r-- | base/base.gypi | 2 |
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', |