Bug 864035 - Add an atomic RefCounted and WeakPtr implementation. r=Waldo

This commit is contained in:
Mike Hommey 2013-05-18 09:52:53 +02:00
parent 5638e38904
commit d292a5f228
3 changed files with 75 additions and 16 deletions

View File

@ -9,6 +9,7 @@
#define mozilla_RefPtr_h_
#include "mozilla/Assertions.h"
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/TypeTraits.h"
@ -41,13 +42,19 @@ template<typename T> OutParamRef<T> byRef(RefPtr<T>&);
* state distinguishes use-before-ref (refcount==0) from
* use-after-destroy (refcount==0xffffdead).
*/
#ifdef DEBUG
namespace detail {
#ifdef DEBUG
static const int DEAD = 0xffffdead;
}
#endif
template<typename T>
// This is used WeakPtr.h as well as this file.
enum RefCountAtomicity
{
AtomicRefCount,
NonAtomicRefCount
};
template<typename T, RefCountAtomicity Atomicity>
class RefCounted
{
friend class RefPtr<T>;
@ -56,8 +63,6 @@ class RefCounted
RefCounted() : refCnt(0) { }
~RefCounted() {
MOZ_ASSERT(refCnt == detail::DEAD);
MOZ_STATIC_ASSERT((IsBaseOf<RefCounted<T>, T>::value),
"T must derive from RefCounted<T>");
}
public:
@ -87,7 +92,33 @@ class RefCounted
}
private:
int refCnt;
typename Conditional<Atomicity == AtomicRefCount, Atomic<int>, int>::Type refCnt;
};
}
template<typename T>
class RefCounted : public detail::RefCounted<T, detail::NonAtomicRefCount>
{
public:
~RefCounted() {
MOZ_STATIC_ASSERT((IsBaseOf<RefCounted, T>::value),
"T must derive from RefCounted<T>");
}
};
/**
* AtomicRefCounted<T> is like RefCounted<T>, with an atomically updated
* reference counter.
*/
template<typename T>
class AtomicRefCounted : public detail::RefCounted<T, detail::AtomicRefCount>
{
public:
~AtomicRefCounted() {
MOZ_STATIC_ASSERT((IsBaseOf<AtomicRefCounted, T>::value),
"T must derive from AtomicRefCounted<T>");
}
};
/**

View File

@ -13,6 +13,9 @@
* the WeakPtrs to it and allows the WeakReference to live beyond the lifetime
* of 'Foo'.
*
* AtomicSupportsWeakPtr can be used for a variant with an atomically updated
* reference counter.
*
* The overhead of WeakPtr is that accesses to 'Foo' becomes an additional
* dereference, and an additional heap allocated pointer sized object shared
* between all of the WeakPtrs.
@ -59,6 +62,7 @@
#define mozilla_WeakPtr_h_
#include "mozilla/Assertions.h"
#include "mozilla/Atomics.h"
#include "mozilla/NullPtr.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TypeTraits.h"
@ -71,8 +75,8 @@ template <typename T, class WeakReference> class SupportsWeakPtrBase;
namespace detail {
// This can live beyond the lifetime of the class derived from SupportsWeakPtrBase.
template<class T>
class WeakReference : public RefCounted<WeakReference<T> >
template<class T, RefCountAtomicity Atomicity>
class WeakReference : public RefCounted<WeakReference<T, Atomicity>, Atomicity>
{
public:
explicit WeakReference(T* p) : ptr(p) {}
@ -81,8 +85,8 @@ class WeakReference : public RefCounted<WeakReference<T> >
}
private:
friend class WeakPtrBase<T, WeakReference<T> >;
friend class SupportsWeakPtrBase<T, WeakReference<T> >;
friend class WeakPtrBase<T, WeakReference>;
friend class SupportsWeakPtrBase<T, WeakReference>;
void detach() {
ptr = nullptr;
}
@ -116,10 +120,30 @@ class SupportsWeakPtrBase
};
template <typename T>
class SupportsWeakPtr : public SupportsWeakPtrBase<T, detail::WeakReference<T> >
class SupportsWeakPtr
: public SupportsWeakPtrBase<T, detail::WeakReference<T, detail::NonAtomicRefCount> >
{
};
template <typename T>
class AtomicSupportsWeakPtr
: public SupportsWeakPtrBase<T, detail::WeakReference<T, detail::AtomicRefCount> >
{
};
namespace detail {
template <typename T>
struct WeakReferenceCount
{
static const RefCountAtomicity atomicity =
IsBaseOf<AtomicSupportsWeakPtr<T>, T>::value
? AtomicRefCount
: NonAtomicRefCount;
};
}
template <typename T, class WeakReference>
class WeakPtrBase
{
@ -152,9 +176,9 @@ class WeakPtrBase
};
template <typename T>
class WeakPtr : public WeakPtrBase<T, detail::WeakReference<T> >
class WeakPtr : public WeakPtrBase<T, detail::WeakReference<T, detail::WeakReferenceCount<T>::atomicity> >
{
typedef WeakPtrBase<T, detail::WeakReference<T> > Base;
typedef WeakPtrBase<T, detail::WeakReference<T, detail::WeakReferenceCount<T>::atomicity> > Base;
public:
WeakPtr(const WeakPtr<T>& o) : Base(o) {}
WeakPtr(const Base& o) : Base(o) {}

View File

@ -68,14 +68,16 @@ __dl_munmap(void *handle, void *addr, size_t length);
class LibHandle;
namespace mozilla {
namespace detail {
template <> inline void RefCounted<LibHandle>::Release();
template <> inline void RefCounted<LibHandle, NonAtomicRefCount>::Release();
template <> inline RefCounted<LibHandle>::~RefCounted()
template <> inline RefCounted<LibHandle, NonAtomicRefCount>::~RefCounted()
{
MOZ_ASSERT(refCnt == 0x7fffdead);
}
} /* namespace detail */
} /* namespace mozilla */
/* Forward declaration */
@ -213,8 +215,9 @@ private:
* would mean too many Releases from within the destructor.
*/
namespace mozilla {
namespace detail {
template <> inline void RefCounted<LibHandle>::Release() {
template <> inline void RefCounted<LibHandle, NonAtomicRefCount>::Release() {
#ifdef DEBUG
if (refCnt > 0x7fff0000)
MOZ_ASSERT(refCnt > 0x7fffdead);
@ -232,6 +235,7 @@ template <> inline void RefCounted<LibHandle>::Release() {
}
}
} /* namespace detail */
} /* namespace mozilla */
/**