blob: 37ae6f0e93db7a035d4cadbd469da22ca0579eb8 [file] [log] [blame]
cfredrica0464ebf2021-07-24 01:26:391// Copyright 2021 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_BARRIER_CALLBACK_H_
6#define BASE_BARRIER_CALLBACK_H_
7
8#include <type_traits>
9#include <vector>
10
11#include "base/bind.h"
12#include "base/callback.h"
13#include "base/callback_helpers.h"
14#include "base/synchronization/lock.h"
15#include "base/thread_annotations.h"
16
17namespace base {
18
cfredric8c677a12021-08-03 21:48:3019namespace internal {
cfredrica0464ebf2021-07-24 01:26:3920
21template <typename T>
22class BarrierCallbackInfo {
23 public:
24 BarrierCallbackInfo(size_t num_callbacks,
25 OnceCallback<void(std::vector<T>)> done_callback)
26 : num_callbacks_left_(num_callbacks),
27 done_callback_(std::move(done_callback)) {
28 results_.reserve(num_callbacks);
29 }
30
31 void Run(T t) LOCKS_EXCLUDED(mutex_) {
32 base::ReleasableAutoLock lock(&mutex_);
33 DCHECK_NE(num_callbacks_left_, 0U);
34 results_.push_back(std::move(t));
35 --num_callbacks_left_;
36
37 if (num_callbacks_left_ == 0) {
38 std::vector<T> results = std::move(results_);
39 lock.Release();
40 std::move(done_callback_).Run(std::move(results));
41 }
42 }
43
44 private:
45 Lock mutex_;
46 size_t num_callbacks_left_ GUARDED_BY(mutex_);
47 std::vector<T> results_ GUARDED_BY(mutex_);
48 OnceCallback<void(std::vector<T>)> done_callback_;
49};
50
cfredriceaafc6b2021-07-27 21:12:0151template <typename T>
52void ShouldNeverRun(T t) {
53 CHECK(false);
54}
55
cfredric8c677a12021-08-03 21:48:3056} // namespace internal
cfredrica0464ebf2021-07-24 01:26:3957
58// BarrierCallback<T> is an analog of BarrierClosure for which each `Run()`
59// invocation takes a `T` as an argument. After `num_callbacks` such
60// invocations, BarrierCallback invokes `Run()` on its `done_callback`, passing
61// the vector of `T`s as an argument. (The ordering of the vector is
62// unspecified.)
63//
cfredriceaafc6b2021-07-27 21:12:0164// If `num_callbacks` is 0, `done_callback` is executed immediately.
cfredrica0464ebf2021-07-24 01:26:3965//
66// BarrierCallback is thread-safe - the internals are protected by a
67// `base::Lock`. `done_callback` will be run on the thread that calls the final
68// Run() on the returned callbacks, or the thread that constructed the
69// BarrierCallback (in the case where `num_callbacks` is 0).
70//
71// `done_callback` is also cleared on the thread that runs it (by virtue of
72// being a OnceCallback).
73template <typename T>
74RepeatingCallback<void(T)> BarrierCallback(
75 size_t num_callbacks,
76 OnceCallback<void(std::vector<T>)> done_callback) {
cfredriceaafc6b2021-07-27 21:12:0177 if (num_callbacks == 0) {
78 std::move(done_callback).Run({});
cfredric8c677a12021-08-03 21:48:3079 return BindRepeating(&internal::ShouldNeverRun<T>);
cfredriceaafc6b2021-07-27 21:12:0180 }
cfredrica0464ebf2021-07-24 01:26:3981
cfredric8c677a12021-08-03 21:48:3082 return BindRepeating(&internal::BarrierCallbackInfo<T>::Run,
83 std::make_unique<internal::BarrierCallbackInfo<T>>(
cfredrica0464ebf2021-07-24 01:26:3984 num_callbacks, std::move(done_callback)));
85}
86
87} // namespace base
88
89#endif // BASE_BARRIER_CALLBACK_H_