xref: /aosp_15_r20/external/libgav1/src/utils/blocking_counter.h (revision 095378508e87ed692bf8dfeb34008b65b3735891)
1*09537850SAkhilesh Sanikop /*
2*09537850SAkhilesh Sanikop  * Copyright 2019 The libgav1 Authors
3*09537850SAkhilesh Sanikop  *
4*09537850SAkhilesh Sanikop  * Licensed under the Apache License, Version 2.0 (the "License");
5*09537850SAkhilesh Sanikop  * you may not use this file except in compliance with the License.
6*09537850SAkhilesh Sanikop  * You may obtain a copy of the License at
7*09537850SAkhilesh Sanikop  *
8*09537850SAkhilesh Sanikop  *      http://www.apache.org/licenses/LICENSE-2.0
9*09537850SAkhilesh Sanikop  *
10*09537850SAkhilesh Sanikop  * Unless required by applicable law or agreed to in writing, software
11*09537850SAkhilesh Sanikop  * distributed under the License is distributed on an "AS IS" BASIS,
12*09537850SAkhilesh Sanikop  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*09537850SAkhilesh Sanikop  * See the License for the specific language governing permissions and
14*09537850SAkhilesh Sanikop  * limitations under the License.
15*09537850SAkhilesh Sanikop  */
16*09537850SAkhilesh Sanikop 
17*09537850SAkhilesh Sanikop #ifndef LIBGAV1_SRC_UTILS_BLOCKING_COUNTER_H_
18*09537850SAkhilesh Sanikop #define LIBGAV1_SRC_UTILS_BLOCKING_COUNTER_H_
19*09537850SAkhilesh Sanikop 
20*09537850SAkhilesh Sanikop #include <cassert>
21*09537850SAkhilesh Sanikop #include <condition_variable>  // NOLINT (unapproved c++11 header)
22*09537850SAkhilesh Sanikop #include <mutex>               // NOLINT (unapproved c++11 header)
23*09537850SAkhilesh Sanikop 
24*09537850SAkhilesh Sanikop #include "src/utils/compiler_attributes.h"
25*09537850SAkhilesh Sanikop 
26*09537850SAkhilesh Sanikop namespace libgav1 {
27*09537850SAkhilesh Sanikop 
28*09537850SAkhilesh Sanikop // Implementation of a Blocking Counter that is used for the "fork-join"
29*09537850SAkhilesh Sanikop // use case. Typical usage would be as follows:
30*09537850SAkhilesh Sanikop //   BlockingCounter counter(num_jobs);
31*09537850SAkhilesh Sanikop //     - spawn the jobs.
32*09537850SAkhilesh Sanikop //     - call counter.Wait() on the master thread.
33*09537850SAkhilesh Sanikop //     - worker threads will call counter.Decrement().
34*09537850SAkhilesh Sanikop //     - master thread will return from counter.Wait() when all workers are
35*09537850SAkhilesh Sanikop //     complete.
36*09537850SAkhilesh Sanikop template <bool has_failure_status>
37*09537850SAkhilesh Sanikop class BlockingCounterImpl {
38*09537850SAkhilesh Sanikop  public:
BlockingCounterImpl(int initial_count)39*09537850SAkhilesh Sanikop   explicit BlockingCounterImpl(int initial_count)
40*09537850SAkhilesh Sanikop       : count_(initial_count), job_failed_(false) {}
41*09537850SAkhilesh Sanikop 
42*09537850SAkhilesh Sanikop   // Increment the counter by |count|. This must be called before Wait() is
43*09537850SAkhilesh Sanikop   // called. This must be called from the same thread that will call Wait().
IncrementBy(int count)44*09537850SAkhilesh Sanikop   void IncrementBy(int count) {
45*09537850SAkhilesh Sanikop     assert(count >= 0);
46*09537850SAkhilesh Sanikop     std::unique_lock<std::mutex> lock(mutex_);
47*09537850SAkhilesh Sanikop     count_ += count;
48*09537850SAkhilesh Sanikop   }
49*09537850SAkhilesh Sanikop 
50*09537850SAkhilesh Sanikop   // Decrement the counter by 1. This function can be called only when
51*09537850SAkhilesh Sanikop   // |has_failure_status| is false (i.e.) when this class is being used with the
52*09537850SAkhilesh Sanikop   // |BlockingCounter| alias.
Decrement()53*09537850SAkhilesh Sanikop   void Decrement() {
54*09537850SAkhilesh Sanikop     static_assert(!has_failure_status, "");
55*09537850SAkhilesh Sanikop     std::unique_lock<std::mutex> lock(mutex_);
56*09537850SAkhilesh Sanikop     if (--count_ == 0) {
57*09537850SAkhilesh Sanikop       condition_.notify_one();
58*09537850SAkhilesh Sanikop     }
59*09537850SAkhilesh Sanikop   }
60*09537850SAkhilesh Sanikop 
61*09537850SAkhilesh Sanikop   // Decrement the counter by 1. This function can be called only when
62*09537850SAkhilesh Sanikop   // |has_failure_status| is true (i.e.) when this class is being used with the
63*09537850SAkhilesh Sanikop   // |BlockingCounterWithStatus| alias. |job_succeeded| is used to update the
64*09537850SAkhilesh Sanikop   // state of |job_failed_|.
Decrement(bool job_succeeded)65*09537850SAkhilesh Sanikop   void Decrement(bool job_succeeded) {
66*09537850SAkhilesh Sanikop     static_assert(has_failure_status, "");
67*09537850SAkhilesh Sanikop     std::unique_lock<std::mutex> lock(mutex_);
68*09537850SAkhilesh Sanikop     job_failed_ |= !job_succeeded;
69*09537850SAkhilesh Sanikop     if (--count_ == 0) {
70*09537850SAkhilesh Sanikop       condition_.notify_one();
71*09537850SAkhilesh Sanikop     }
72*09537850SAkhilesh Sanikop   }
73*09537850SAkhilesh Sanikop 
74*09537850SAkhilesh Sanikop   // Block until the counter becomes 0. This function can be called only once
75*09537850SAkhilesh Sanikop   // per object. If |has_failure_status| is true, true is returned if all the
76*09537850SAkhilesh Sanikop   // jobs succeeded and false is returned if any of the jobs failed. If
77*09537850SAkhilesh Sanikop   // |has_failure_status| is false, this function always returns true.
Wait()78*09537850SAkhilesh Sanikop   bool Wait() {
79*09537850SAkhilesh Sanikop     std::unique_lock<std::mutex> lock(mutex_);
80*09537850SAkhilesh Sanikop     condition_.wait(lock, [this]() { return count_ == 0; });
81*09537850SAkhilesh Sanikop     // If |has_failure_status| is false, we simply return true.
82*09537850SAkhilesh Sanikop     return has_failure_status ? !job_failed_ : true;
83*09537850SAkhilesh Sanikop   }
84*09537850SAkhilesh Sanikop 
85*09537850SAkhilesh Sanikop  private:
86*09537850SAkhilesh Sanikop   std::mutex mutex_;
87*09537850SAkhilesh Sanikop   std::condition_variable condition_;
88*09537850SAkhilesh Sanikop   int count_ LIBGAV1_GUARDED_BY(mutex_);
89*09537850SAkhilesh Sanikop   bool job_failed_ LIBGAV1_GUARDED_BY(mutex_);
90*09537850SAkhilesh Sanikop };
91*09537850SAkhilesh Sanikop 
92*09537850SAkhilesh Sanikop using BlockingCounterWithStatus = BlockingCounterImpl<true>;
93*09537850SAkhilesh Sanikop using BlockingCounter = BlockingCounterImpl<false>;
94*09537850SAkhilesh Sanikop 
95*09537850SAkhilesh Sanikop }  // namespace libgav1
96*09537850SAkhilesh Sanikop 
97*09537850SAkhilesh Sanikop #endif  // LIBGAV1_SRC_UTILS_BLOCKING_COUNTER_H_
98