Change return types of refcount methods.
AddRef() now returns void, and Release() returns an enum RefCountReleaseStatus, to indicate whether or not this Release call implied deletion. Bug: webrtc:8270 Change-Id: If2fb77f26118b61751b51c856af187c72112c630 Reviewed-on: https://webrtc-review.googlesource.com/3320 Commit-Queue: Niels Moller <nisse@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org> Cr-Commit-Position: refs/heads/master@{#20366}
This commit is contained in:
@ -60,17 +60,17 @@ bool AudioState::typing_noise_detected() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reference count; implementation copied from rtc::RefCountedObject.
|
// Reference count; implementation copied from rtc::RefCountedObject.
|
||||||
int AudioState::AddRef() const {
|
void AudioState::AddRef() const {
|
||||||
return rtc::AtomicOps::Increment(&ref_count_);
|
rtc::AtomicOps::Increment(&ref_count_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reference count; implementation copied from rtc::RefCountedObject.
|
// Reference count; implementation copied from rtc::RefCountedObject.
|
||||||
int AudioState::Release() const {
|
rtc::RefCountReleaseStatus AudioState::Release() const {
|
||||||
int count = rtc::AtomicOps::Decrement(&ref_count_);
|
if (rtc::AtomicOps::Decrement(&ref_count_) == 0) {
|
||||||
if (!count) {
|
|
||||||
delete this;
|
delete this;
|
||||||
|
return rtc::RefCountReleaseStatus::kDroppedLastRef;
|
||||||
}
|
}
|
||||||
return count;
|
return rtc::RefCountReleaseStatus::kOtherRefsRemained;
|
||||||
}
|
}
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
#include "call/audio_state.h"
|
#include "call/audio_state.h"
|
||||||
#include "rtc_base/constructormagic.h"
|
#include "rtc_base/constructormagic.h"
|
||||||
#include "rtc_base/criticalsection.h"
|
#include "rtc_base/criticalsection.h"
|
||||||
|
#include "rtc_base/refcount.h"
|
||||||
#include "rtc_base/thread_checker.h"
|
#include "rtc_base/thread_checker.h"
|
||||||
#include "voice_engine/include/voe_base.h"
|
#include "voice_engine/include/voe_base.h"
|
||||||
|
|
||||||
@ -38,8 +39,8 @@ class AudioState final : public webrtc::AudioState {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// rtc::RefCountInterface implementation.
|
// rtc::RefCountInterface implementation.
|
||||||
int AddRef() const override;
|
void AddRef() const override;
|
||||||
int Release() const override;
|
rtc::RefCountReleaseStatus Release() const override;
|
||||||
|
|
||||||
rtc::ThreadChecker thread_checker_;
|
rtc::ThreadChecker thread_checker_;
|
||||||
rtc::ThreadChecker process_thread_checker_;
|
rtc::ThreadChecker process_thread_checker_;
|
||||||
|
|||||||
@ -84,8 +84,9 @@ class MockTransmitMixer : public webrtc::voe::TransmitMixer {
|
|||||||
|
|
||||||
void AdmSetupExpectations(webrtc::test::MockAudioDeviceModule* adm) {
|
void AdmSetupExpectations(webrtc::test::MockAudioDeviceModule* adm) {
|
||||||
RTC_DCHECK(adm);
|
RTC_DCHECK(adm);
|
||||||
EXPECT_CALL(*adm, AddRef()).WillOnce(Return(0));
|
EXPECT_CALL(*adm, AddRef()).Times(1);
|
||||||
EXPECT_CALL(*adm, Release()).WillOnce(Return(0));
|
EXPECT_CALL(*adm, Release())
|
||||||
|
.WillOnce(Return(rtc::RefCountReleaseStatus::kDroppedLastRef));
|
||||||
#if !defined(WEBRTC_IOS)
|
#if !defined(WEBRTC_IOS)
|
||||||
EXPECT_CALL(*adm, Recording()).WillOnce(Return(false));
|
EXPECT_CALL(*adm, Recording()).WillOnce(Return(false));
|
||||||
EXPECT_CALL(*adm, SetRecordingChannel(webrtc::AudioDeviceModule::
|
EXPECT_CALL(*adm, SetRecordingChannel(webrtc::AudioDeviceModule::
|
||||||
@ -3340,8 +3341,10 @@ TEST(WebRtcVoiceEngineTest, StartupShutdown) {
|
|||||||
// Tests that reference counting on the external ADM is correct.
|
// Tests that reference counting on the external ADM is correct.
|
||||||
TEST(WebRtcVoiceEngineTest, StartupShutdownWithExternalADM) {
|
TEST(WebRtcVoiceEngineTest, StartupShutdownWithExternalADM) {
|
||||||
testing::NiceMock<webrtc::test::MockAudioDeviceModule> adm;
|
testing::NiceMock<webrtc::test::MockAudioDeviceModule> adm;
|
||||||
EXPECT_CALL(adm, AddRef()).Times(3).WillRepeatedly(Return(0));
|
EXPECT_CALL(adm, AddRef()).Times(3);
|
||||||
EXPECT_CALL(adm, Release()).Times(3).WillRepeatedly(Return(0));
|
EXPECT_CALL(adm, Release())
|
||||||
|
.Times(3)
|
||||||
|
.WillRepeatedly(Return(rtc::RefCountReleaseStatus::kDroppedLastRef));
|
||||||
{
|
{
|
||||||
rtc::scoped_refptr<webrtc::AudioProcessing> apm =
|
rtc::scoped_refptr<webrtc::AudioProcessing> apm =
|
||||||
webrtc::AudioProcessing::Create();
|
webrtc::AudioProcessing::Create();
|
||||||
|
|||||||
@ -19,8 +19,13 @@ class FakeAudioDeviceModule : public AudioDeviceModule {
|
|||||||
public:
|
public:
|
||||||
FakeAudioDeviceModule() {}
|
FakeAudioDeviceModule() {}
|
||||||
virtual ~FakeAudioDeviceModule() {}
|
virtual ~FakeAudioDeviceModule() {}
|
||||||
int32_t AddRef() const override { return 0; }
|
|
||||||
int32_t Release() const override { return 0; }
|
// TODO(nisse): Fix all users of this class to managed references using
|
||||||
|
// scoped_refptr. Current code doesn't always use refcounting for this class.
|
||||||
|
void AddRef() const override {}
|
||||||
|
rtc::RefCountReleaseStatus Release() const override {
|
||||||
|
return rtc::RefCountReleaseStatus::kDroppedLastRef;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int32_t RegisterAudioCallback(AudioTransport* audioCallback) override {
|
int32_t RegisterAudioCallback(AudioTransport* audioCallback) override {
|
||||||
|
|||||||
@ -22,8 +22,8 @@ namespace test {
|
|||||||
class MockAudioDeviceModule : public AudioDeviceModule {
|
class MockAudioDeviceModule : public AudioDeviceModule {
|
||||||
public:
|
public:
|
||||||
// RefCounted
|
// RefCounted
|
||||||
MOCK_CONST_METHOD0(AddRef, int32_t());
|
MOCK_CONST_METHOD0(AddRef, void());
|
||||||
MOCK_CONST_METHOD0(Release, int32_t());
|
MOCK_CONST_METHOD0(Release, rtc::RefCountReleaseStatus());
|
||||||
// AudioDeviceModule.
|
// AudioDeviceModule.
|
||||||
MOCK_CONST_METHOD1(ActiveAudioLayer, int32_t(AudioLayer* audioLayer));
|
MOCK_CONST_METHOD1(ActiveAudioLayer, int32_t(AudioLayer* audioLayer));
|
||||||
MOCK_CONST_METHOD0(LastError, ErrorCode());
|
MOCK_CONST_METHOD0(LastError, ErrorCode());
|
||||||
|
|||||||
@ -30,8 +30,8 @@ class MockInitialize : public AudioProcessingImpl {
|
|||||||
return AudioProcessingImpl::InitializeLocked();
|
return AudioProcessingImpl::InitializeLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
MOCK_CONST_METHOD0(AddRef, int());
|
MOCK_CONST_METHOD0(AddRef, void());
|
||||||
MOCK_CONST_METHOD0(Release, int());
|
MOCK_CONST_METHOD0(Release, rtc::RefCountReleaseStatus());
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -310,7 +310,10 @@ void TransportController::DestroyDtlsTransport_n(
|
|||||||
<< ", which doesn't exist.";
|
<< ", which doesn't exist.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((*it)->Release() > 0) {
|
// Release one reference to the RefCountedChannel, and do additional cleanup
|
||||||
|
// only if it was the last one. Matches the AddRef logic in
|
||||||
|
// CreateDtlsTransport_n.
|
||||||
|
if ((*it)->Release() == rtc::RefCountReleaseStatus::kOtherRefsRemained) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
channels_.erase(it);
|
channels_.erase(it);
|
||||||
@ -471,11 +474,14 @@ JsepTransport* TransportController::GetOrCreateJsepTransport(
|
|||||||
void TransportController::DestroyAllChannels_n() {
|
void TransportController::DestroyAllChannels_n() {
|
||||||
RTC_DCHECK(network_thread_->IsCurrent());
|
RTC_DCHECK(network_thread_->IsCurrent());
|
||||||
transports_.clear();
|
transports_.clear();
|
||||||
|
// TODO(nisse): If |channels_| were a vector of scoped_refptr, we
|
||||||
|
// wouldn't need this strange hack.
|
||||||
for (RefCountedChannel* channel : channels_) {
|
for (RefCountedChannel* channel : channels_) {
|
||||||
// Even though these objects are normally ref-counted, if
|
// Even though these objects are normally ref-counted, if
|
||||||
// TransportController is deleted while they still have references, just
|
// TransportController is deleted while they still have references, just
|
||||||
// remove all references.
|
// remove all references.
|
||||||
while (channel->Release() > 0) {
|
while (channel->Release() ==
|
||||||
|
rtc::RefCountReleaseStatus::kOtherRefsRemained) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
channels_.clear();
|
channels_.clear();
|
||||||
|
|||||||
@ -31,11 +31,11 @@ struct BindTester {
|
|||||||
class RefCountedBindTester : public RefCountInterface {
|
class RefCountedBindTester : public RefCountInterface {
|
||||||
public:
|
public:
|
||||||
RefCountedBindTester() : count_(0) {}
|
RefCountedBindTester() : count_(0) {}
|
||||||
int AddRef() const override {
|
void AddRef() const override { ++count_; }
|
||||||
return ++count_;
|
RefCountReleaseStatus Release() const override {
|
||||||
}
|
--count_;
|
||||||
int Release() const override {
|
return count_ == 0 ? RefCountReleaseStatus::kDroppedLastRef
|
||||||
return --count_;
|
: RefCountReleaseStatus::kOtherRefsRemained;
|
||||||
}
|
}
|
||||||
int RefCount() const { return count_; }
|
int RefCount() const { return count_; }
|
||||||
|
|
||||||
|
|||||||
@ -12,12 +12,52 @@
|
|||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
// Reference count interface.
|
// Refcounted objects should implement the following informal interface:
|
||||||
|
//
|
||||||
|
// void AddRef() const ;
|
||||||
|
// RefCountReleaseStatus Release() const;
|
||||||
|
//
|
||||||
|
// You may access members of a reference-counted object, including the AddRef()
|
||||||
|
// and Release() methods, only if you already own a reference to it, or if
|
||||||
|
// you're borrowing someone else's reference. (A newly created object is a
|
||||||
|
// special case: the reference count is zero on construction, and the code that
|
||||||
|
// creates the object should immediately call AddRef(), bringing the reference
|
||||||
|
// count from zero to one, e.g., by constructing an rtc::scoped_refptr).
|
||||||
|
//
|
||||||
|
// AddRef() creates a new reference to the object.
|
||||||
|
//
|
||||||
|
// Release() releases a reference to the object; the caller now has one less
|
||||||
|
// reference than before the call. Returns kDroppedLastRef if the number of
|
||||||
|
// references dropped to zero because of this (in which case the object destroys
|
||||||
|
// itself). Otherwise, returns kOtherRefsRemained, to signal that at the precise
|
||||||
|
// time the caller's reference was dropped, other references still remained (but
|
||||||
|
// if other threads own references, this may of course have changed by the time
|
||||||
|
// Release() returns).
|
||||||
|
//
|
||||||
|
// The caller of Release() must treat it in the same way as a delete operation:
|
||||||
|
// Regardless of the return value from Release(), the caller mustn't access the
|
||||||
|
// object. The object might still be alive, due to references held by other
|
||||||
|
// users of the object, but the object can go away at any time, e.g., as the
|
||||||
|
// result of another thread calling Release().
|
||||||
|
//
|
||||||
|
// Calling AddRef() and Release() manually is discouraged. It's recommended to
|
||||||
|
// use rtc::scoped_refptr to manage all pointers to reference counted objects.
|
||||||
|
// Note that rtc::scoped_refptr depends on compile-time duck-typing; formally
|
||||||
|
// implementing the below RefCountInterface is not required.
|
||||||
|
|
||||||
|
enum class RefCountReleaseStatus { kDroppedLastRef, kOtherRefsRemained };
|
||||||
|
|
||||||
|
// Interfaces where refcounting is part of the public api should
|
||||||
|
// inherit this abstract interface. The implementation of these
|
||||||
|
// methods is usually provided by the RefCountedObject template class,
|
||||||
|
// applied as a leaf in the inheritance tree.
|
||||||
class RefCountInterface {
|
class RefCountInterface {
|
||||||
public:
|
public:
|
||||||
virtual int AddRef() const = 0;
|
virtual void AddRef() const = 0;
|
||||||
virtual int Release() const = 0;
|
virtual RefCountReleaseStatus Release() const = 0;
|
||||||
|
|
||||||
|
// Non-public destructor, because Release() has exclusive responsibility for
|
||||||
|
// destroying the object.
|
||||||
protected:
|
protected:
|
||||||
virtual ~RefCountInterface() {}
|
virtual ~RefCountInterface() {}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "rtc_base/atomicops.h"
|
#include "rtc_base/atomicops.h"
|
||||||
|
#include "rtc_base/refcount.h"
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
@ -30,14 +31,14 @@ class RefCountedObject : public T {
|
|||||||
std::forward<P1>(p1),
|
std::forward<P1>(p1),
|
||||||
std::forward<Args>(args)...) {}
|
std::forward<Args>(args)...) {}
|
||||||
|
|
||||||
virtual int AddRef() const { return AtomicOps::Increment(&ref_count_); }
|
virtual void AddRef() const { AtomicOps::Increment(&ref_count_); }
|
||||||
|
|
||||||
virtual int Release() const {
|
virtual RefCountReleaseStatus Release() const {
|
||||||
int count = AtomicOps::Decrement(&ref_count_);
|
if (AtomicOps::Decrement(&ref_count_) == 0) {
|
||||||
if (!count) {
|
|
||||||
delete this;
|
delete this;
|
||||||
|
return RefCountReleaseStatus::kDroppedLastRef;
|
||||||
}
|
}
|
||||||
return count;
|
return RefCountReleaseStatus::kOtherRefsRemained;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return whether the reference count is one. If the reference count is used
|
// Return whether the reference count is one. If the reference count is used
|
||||||
|
|||||||
@ -61,12 +61,14 @@ class RefClassWithMixedValues : public RefCountInterface {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TEST(RefCountedObject, Basic) {
|
TEST(RefCountedObject, HasOneRef) {
|
||||||
scoped_refptr<RefCountedObject<RefClass>> aref(
|
scoped_refptr<RefCountedObject<RefClass>> aref(
|
||||||
new RefCountedObject<RefClass>());
|
new RefCountedObject<RefClass>());
|
||||||
EXPECT_TRUE(aref->HasOneRef());
|
EXPECT_TRUE(aref->HasOneRef());
|
||||||
EXPECT_EQ(2, aref->AddRef());
|
aref->AddRef();
|
||||||
EXPECT_EQ(1, aref->Release());
|
EXPECT_FALSE(aref->HasOneRef());
|
||||||
|
EXPECT_EQ(aref->Release(), RefCountReleaseStatus::kOtherRefsRemained);
|
||||||
|
EXPECT_TRUE(aref->HasOneRef());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RefCountedObject, SupportRValuesInCtor) {
|
TEST(RefCountedObject, SupportRValuesInCtor) {
|
||||||
|
|||||||
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
#include "rtc_base/constructormagic.h"
|
#include "rtc_base/constructormagic.h"
|
||||||
|
#include "rtc_base/refcount.h"
|
||||||
#include "rtc_base/thread_checker.h"
|
#include "rtc_base/thread_checker.h"
|
||||||
|
|
||||||
// Abort the process if |jni| has a Java exception pending.
|
// Abort the process if |jni| has a Java exception pending.
|
||||||
@ -34,7 +35,8 @@
|
|||||||
// Helper that calls ptr->Release() and aborts the process with a useful
|
// Helper that calls ptr->Release() and aborts the process with a useful
|
||||||
// message if that didn't actually delete *ptr because of extra refcounts.
|
// message if that didn't actually delete *ptr because of extra refcounts.
|
||||||
#define CHECK_RELEASE(ptr) \
|
#define CHECK_RELEASE(ptr) \
|
||||||
RTC_CHECK_EQ(0, (ptr)->Release()) << "Unexpected refcount."
|
RTC_CHECK((ptr)->Release() == rtc::RefCountReleaseStatus::kDroppedLastRef) \
|
||||||
|
<< "Unexpected refcount."
|
||||||
|
|
||||||
// Convenience macro defining JNI-accessible methods in the org.webrtc package.
|
// Convenience macro defining JNI-accessible methods in the org.webrtc package.
|
||||||
// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
|
// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
|
||||||
|
|||||||
@ -110,8 +110,7 @@ JNI_FUNCTION_DECLARATION(jobject,
|
|||||||
nativeChannelPtr);
|
nativeChannelPtr);
|
||||||
CHECK_EXCEPTION(jni) << "error during NewObject";
|
CHECK_EXCEPTION(jni) << "error during NewObject";
|
||||||
// Channel is now owned by Java object, and will be freed from there.
|
// Channel is now owned by Java object, and will be freed from there.
|
||||||
int bumped_count = channel->AddRef();
|
channel->AddRef();
|
||||||
RTC_CHECK(bumped_count == 2) << "Unexpected refcount";
|
|
||||||
return j_channel;
|
return j_channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -304,8 +304,7 @@ void PeerConnectionObserverJni::OnDataChannel(
|
|||||||
// DataChannel.dispose(). Important that this be done _after_ the
|
// DataChannel.dispose(). Important that this be done _after_ the
|
||||||
// CallVoidMethod above as Java code might call back into native code and be
|
// CallVoidMethod above as Java code might call back into native code and be
|
||||||
// surprised to see a refcount of 2.
|
// surprised to see a refcount of 2.
|
||||||
int bumped_count = channel->AddRef();
|
channel->AddRef();
|
||||||
RTC_CHECK(bumped_count == 2) << "Unexpected refcount OnDataChannel";
|
|
||||||
|
|
||||||
CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
|
CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user