1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef MOZILLA_ATOMICREFCOUNTEDWITHFINALIZE_H_
8 #define MOZILLA_ATOMICREFCOUNTEDWITHFINALIZE_H_
10 #include "mozilla/RefPtr.h"
11 #include "mozilla/Likely.h"
12 #include "MainThreadUtils.h"
13 #include "base/message_loop.h"
14 #include "base/task.h"
15 #include "mozilla/gfx/Logging.h"
17 #define ADDREF_MANUALLY(obj) \
18 (obj)->AddRefManually(__FUNCTION__, __FILE__, __LINE__)
19 #define RELEASE_MANUALLY(obj) \
20 (obj)->ReleaseManually(__FUNCTION__, __FILE__, __LINE__)
36 class AtomicRefCountedWithFinalize
{
38 explicit AtomicRefCountedWithFinalize(const char* aName
)
39 : mRecycleCallback(nullptr),
48 #ifdef NS_BUILD_REFCNT_LOGGING
55 ~AtomicRefCountedWithFinalize() {
57 gfxCriticalError() << "Deleting referenced object? " << mRefCount
;
62 // Mark user classes that are considered flawless.
64 friend class ::mozilla::StaticRefPtr
;
67 friend struct mozilla::RefPtrTraits
;
70 friend class ::mozilla::gl::RefSet
;
73 friend class ::mozilla::gl::RefQueue
;
75 // friend class mozilla::gl::SurfaceFactory;
77 void AddRefManually(const char* funcName
, const char* fileName
,
80 uint32_t count
= ++mManualAddRefs
;
82 printf_stderr("AddRefManually() #%u in %s at %s:%u\n", count
, funcName
,
93 void ReleaseManually(const char* funcName
, const char* fileName
,
96 uint32_t count
= ++mManualReleases
;
98 printf_stderr("ReleaseManually() #%u in %s at %s:%u\n", count
, funcName
,
111 MOZ_ASSERT(mRefCount
>= 0, "AddRef() during/after Finalize()/dtor.");
112 #ifdef NS_BUILD_REFCNT_LOGGING
113 int currCount
= ++mRefCount
;
114 NS_LOG_ADDREF(this, currCount
, mName
, sizeof(*this));
121 MOZ_ASSERT(mRefCount
> 0, "Release() during/after Finalize()/dtor.");
122 // Read mRecycleCallback early so that it does not get set to
123 // deleted memory, if the object is goes away. See bug 994903.
124 // This saves us in the case where there is no callback, so that
125 // we can do the "else if" below.
126 RecycleCallback recycleCallback
= mRecycleCallback
;
127 int currCount
= --mRefCount
;
129 gfxCriticalError() << "Invalid reference count release" << currCount
;
133 #ifdef NS_BUILD_REFCNT_LOGGING
134 NS_LOG_RELEASE(this, currCount
, mName
);
137 if (0 == currCount
) {
138 mRefCount
= detail::DEAD
;
139 MOZ_ASSERT(IsDead());
141 // Recycle listeners must call ClearRecycleCallback
142 // before releasing their strong reference.
143 if (mRecycleCallback
) {
144 gfxCriticalError() << "About to release with valid callback";
145 mRecycleCallback
= nullptr;
148 MOZ_ASSERT(mManualAddRefs
== mManualReleases
);
150 T
* derived
= static_cast<T
*>(this);
153 } else if (1 == currCount
&& recycleCallback
) {
154 // There is nothing enforcing this in the code, except how the callers
155 // are being careful to never let the reference count go down if there
157 MOZ_ASSERT(!IsDead());
158 T
* derived
= static_cast<T
*>(this);
159 recycleCallback(derived
, mClosure
);
164 typedef void (*RecycleCallback
)(T
* aObject
, void* aClosure
);
166 * Set a callback responsible for recycling this object
167 * before it is finalized.
169 void SetRecycleCallback(RecycleCallback aCallback
, void* aClosure
) {
170 MOZ_ASSERT(!IsDead());
171 mRecycleCallback
= aCallback
;
174 void ClearRecycleCallback() {
175 MOZ_ASSERT(!IsDead());
176 SetRecycleCallback(nullptr, nullptr);
179 bool HasRecycleCallback() const {
180 MOZ_ASSERT(!IsDead());
181 return !!mRecycleCallback
;
184 bool IsDead() const { return mRefCount
< 0; }
186 bool HasOneRef() const { return mRefCount
== 1; }
189 RecycleCallback mRecycleCallback
;
191 Atomic
<int> mRefCount
;
197 Atomic
<uint32_t> mManualAddRefs
;
198 Atomic
<uint32_t> mManualReleases
;
200 #ifdef NS_BUILD_REFCNT_LOGGING
205 } // namespace mozilla