blob: 36d019b82a0422ec7e2da0a0805e97ad3468f058 [file] [log] [blame]
// Copyright 2019 The Fuchsia 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 REFCOUNT_BLOCKING_REFCOUNT_H_
#define REFCOUNT_BLOCKING_REFCOUNT_H_
#include <lib/sync/condition.h>
#include <lib/sync/mutex.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
namespace refcount {
// A BlockingRefCount provides a counter which can be incremented and
// decremented, with an additional operation allowing threads to wait
// for the count to become zero.
//
// This can be useful in scenarios where an object is waiting for
// in-flight callbacks to complete before cleaning up resources,
// for example:
//
// class MyClass {
// void PerformAsyncOperation() {
// // Increment the counter when we start the work, and decrement
// // it when finished.
// in_flight_ops_.Inc();
// DoWork(..., /*completion_callback=*/[this](){
// // ...
// in_flight_ops_.Dec();
// });
// }
//
// // Wait for all in-flight operations to terminate before
// // destructing.
// ~MyClass() {
// in_flight_ops_.WaitForZero();
// }
//
// BlockingRefCount in_flight_ops_;
// }
//
// BlockingRefCount must not be destructed while threads are waiting
// on it.
//
// Thread safe.
class BlockingRefCount {
public:
// Create a new BlockingRefCount with initial reference count of 0.
BlockingRefCount();
// Create a new BlockingRefCount with the given initial reference count.
explicit BlockingRefCount(int32_t initial_count);
// Increment the reference count.
void Inc();
// Decrement the reference count, potentially waking up threads waiting
// for the count to reach zero.
//
// Callers must ensure that calling this would not result in the counter
// dropping below zero.
void Dec();
// Wait for the counter to become zero.
//
// If the counter only briefly becomes zero, waiting threads may not
// see the zero and fail to wake up. If the counter hits zero and
// remains, however, threads are guaranteed to wake up.
void WaitForZero() const;
private:
// Number of references to this object.
mutable sync_mutex_t lock_;
mutable sync_condition_t condition_
__TA_GUARDED(lock_); // Threads waiting on the count to reach zero.
int32_t count_ __TA_GUARDED(lock_); // Number of references.
};
} // namespace refcount
#endif // REFCOUNT_BLOCKING_REFCOUNT_H_