2013-12-12 01:45:11 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#ifndef MOZILLA_ATOMICREFCOUNTEDWITHFINALIZE_H_
|
|
|
|
#define MOZILLA_ATOMICREFCOUNTEDWITHFINALIZE_H_
|
|
|
|
|
|
|
|
#include "mozilla/RefPtr.h"
|
2014-03-10 18:34:57 +00:00
|
|
|
#include "mozilla/NullPtr.h"
|
2014-07-04 18:04:12 +00:00
|
|
|
#include "mozilla/Likely.h"
|
|
|
|
#include "MainThreadUtils.h"
|
|
|
|
#include "base/message_loop.h"
|
|
|
|
#include "base/task.h"
|
2013-12-12 01:45:11 +00:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
class AtomicRefCountedWithFinalize
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
AtomicRefCountedWithFinalize()
|
2014-03-10 18:34:57 +00:00
|
|
|
: mRecycleCallback(nullptr)
|
|
|
|
, mRefCount(0)
|
2014-07-04 18:04:12 +00:00
|
|
|
, mMessageLoopToPostDestructionTo(nullptr)
|
2013-12-12 01:45:11 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
~AtomicRefCountedWithFinalize() {}
|
|
|
|
|
2014-07-04 18:04:12 +00:00
|
|
|
void SetMessageLoopToPostDestructionTo(MessageLoop* l) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
mMessageLoopToPostDestructionTo = l;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DestroyToBeCalledOnMainThread(T* ptr) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
delete ptr;
|
|
|
|
}
|
|
|
|
|
2013-12-12 01:45:11 +00:00
|
|
|
public:
|
|
|
|
void AddRef() {
|
|
|
|
MOZ_ASSERT(mRefCount >= 0);
|
|
|
|
++mRefCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Release() {
|
|
|
|
MOZ_ASSERT(mRefCount > 0);
|
2014-04-11 14:24:14 +00:00
|
|
|
// Read mRecycleCallback early so that it does not get set to
|
|
|
|
// deleted memory, if the object is goes away.
|
|
|
|
RecycleCallback recycleCallback = mRecycleCallback;
|
2014-03-10 18:34:57 +00:00
|
|
|
int currCount = --mRefCount;
|
|
|
|
if (0 == currCount) {
|
|
|
|
// Recycle listeners must call ClearRecycleCallback
|
|
|
|
// before releasing their strong reference.
|
|
|
|
MOZ_ASSERT(mRecycleCallback == nullptr);
|
2013-12-12 01:45:11 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
mRefCount = detail::DEAD;
|
|
|
|
#endif
|
|
|
|
T* derived = static_cast<T*>(this);
|
|
|
|
derived->Finalize();
|
2014-07-04 18:04:12 +00:00
|
|
|
if (MOZ_LIKELY(!mMessageLoopToPostDestructionTo)) {
|
|
|
|
delete derived;
|
|
|
|
} else {
|
|
|
|
if (MOZ_LIKELY(NS_IsMainThread())) {
|
|
|
|
delete derived;
|
|
|
|
} else {
|
|
|
|
mMessageLoopToPostDestructionTo->PostTask(
|
|
|
|
FROM_HERE,
|
|
|
|
NewRunnableFunction(&DestroyToBeCalledOnMainThread, derived));
|
|
|
|
}
|
|
|
|
}
|
2014-04-11 14:24:14 +00:00
|
|
|
} else if (1 == currCount && recycleCallback) {
|
2014-03-10 18:34:57 +00:00
|
|
|
T* derived = static_cast<T*>(this);
|
2014-04-11 14:24:14 +00:00
|
|
|
recycleCallback(derived, mClosure);
|
2013-12-12 01:45:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-10 18:34:57 +00:00
|
|
|
typedef void (*RecycleCallback)(T* aObject, void* aClosure);
|
|
|
|
/**
|
|
|
|
* Set a callback responsible for recycling this object
|
|
|
|
* before it is finalized.
|
|
|
|
*/
|
|
|
|
void SetRecycleCallback(RecycleCallback aCallback, void* aClosure)
|
|
|
|
{
|
|
|
|
mRecycleCallback = aCallback;
|
|
|
|
mClosure = aClosure;
|
|
|
|
}
|
|
|
|
void ClearRecycleCallback() { SetRecycleCallback(nullptr, nullptr); }
|
|
|
|
|
2014-05-12 14:39:25 +00:00
|
|
|
bool HasRecycleCallback() const
|
|
|
|
{
|
|
|
|
return !!mRecycleCallback;
|
|
|
|
}
|
|
|
|
|
2013-12-12 01:45:11 +00:00
|
|
|
private:
|
2014-03-10 18:34:57 +00:00
|
|
|
RecycleCallback mRecycleCallback;
|
|
|
|
void *mClosure;
|
2013-12-12 01:45:11 +00:00
|
|
|
Atomic<int> mRefCount;
|
2014-07-04 18:04:12 +00:00
|
|
|
MessageLoop *mMessageLoopToPostDestructionTo;
|
2013-12-12 01:45:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|