Bug 1186745 part 1 - Add LeakRefPtr for pointer leaking by default. r=froydnj

This class can be used instead of raw pointer for a sound leaking-by-default
behavior. Also it could take advantage of move semantic check in the future.

--HG--
extra : source : 47cd2c22bafc8d4bb1c7e1dce3b45517aaec199f
This commit is contained in:
Xidorn Quan 2015-10-03 00:18:24 +10:00
parent ee2cd3bbc3
commit 4dad63f727
7 changed files with 64 additions and 8 deletions

View File

@ -106,6 +106,7 @@ if CONFIG['_MSC_VER']:
LOCAL_INCLUDES += [
'../build',
'../threads',
]
if CONFIG['ENABLE_TESTS']:

View File

@ -7,6 +7,7 @@
#include "nsThreadUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/Likely.h"
#include "LeakRefPtr.h"
#ifdef MOZILLA_INTERNAL_API
# include "nsThreadManager.h"
@ -27,6 +28,8 @@ using mozilla::IsVistaOrLater;
#include <pratom.h>
#include <prthread.h>
using namespace mozilla;
#ifndef XPCOM_GLUE_AVOID_NSPR
NS_IMPL_ISUPPORTS(nsRunnable, nsIRunnable)
@ -164,17 +167,16 @@ NS_DispatchToCurrentThread(nsIRunnable* aEvent)
NS_METHOD
NS_DispatchToMainThread(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aDispatchFlags)
{
nsCOMPtr<nsIRunnable> event(aEvent);
LeakRefPtr<nsIRunnable> event(Move(aEvent));
nsCOMPtr<nsIThread> thread;
nsresult rv = NS_GetMainThread(getter_AddRefs(thread));
if (NS_WARN_IF(NS_FAILED(rv))) {
NS_ASSERTION(false, "Failed NS_DispatchToMainThread() in shutdown; leaking");
// NOTE: if you stop leaking here, adjust Promise::MaybeReportRejected(),
// which assumes a leak here, or split into leaks and no-leaks versions
nsIRunnable* temp = event.forget().take(); // leak without using "unused <<" due to Windows (boo)
return temp ? rv : rv; // to make compiler not bletch on us
return rv;
}
return thread->Dispatch(event.forget(), aDispatchFlags);
return thread->Dispatch(event.take(), aDispatchFlags);
}
// In the case of failure with a newly allocated runnable with a

View File

@ -38,6 +38,7 @@ DEFINES['XPCOM_GLUE'] = True
LOCAL_INCLUDES += [
'../../build',
'../../threads',
]
# Don't use STL wrappers here (i.e. wrapped <new>); they require mozalloc

View File

@ -30,6 +30,7 @@ DEFINES['XPCOM_GLUE'] = True
LOCAL_INCLUDES += [
'../../../build',
'../../../threads',
]
# Statically link to the CRT on Windows

View File

@ -28,6 +28,7 @@ if CONFIG['_MSC_VER']:
LOCAL_INCLUDES += [
'../../build',
'../../threads',
]
# Statically link to the CRT on Windows

View File

@ -0,0 +1,48 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
/* Smart pointer which leaks its owning refcounted object by default. */
#ifndef LeakRefPtr_h
#define LeakRefPtr_h
#include "mozilla/AlreadyAddRefed.h"
namespace mozilla {
/**
* Instance of this class behaves like a raw pointer which leaks the
* resource it's owning if not explicitly released.
*/
template<class T>
class LeakRefPtr
{
public:
explicit LeakRefPtr(already_AddRefed<T>&& aPtr)
: mRawPtr(aPtr.take()) { }
explicit operator bool() const { return !!mRawPtr; }
LeakRefPtr<T>& operator=(already_AddRefed<T>&& aPtr)
{
mRawPtr = aPtr.take();
return *this;
}
already_AddRefed<T> take()
{
T* rawPtr = mRawPtr;
mRawPtr = nullptr;
return already_AddRefed<T>(rawPtr);
}
private:
T* MOZ_OWNING_REF mRawPtr;
};
} // namespace mozilla
#endif // LeakRefPtr_h

View File

@ -36,6 +36,7 @@
#include "nsXPCOMPrivate.h"
#include "mozilla/ChaosMode.h"
#include "mozilla/TimeStamp.h"
#include "LeakRefPtr.h"
#ifdef MOZ_CRASHREPORTER
#include "nsServiceManagerUtils.h"
@ -541,6 +542,9 @@ nsThread::PutEvent(nsIRunnable* aEvent, nsNestedEventTarget* aTarget)
nsresult
nsThread::PutEvent(already_AddRefed<nsIRunnable>&& aEvent, nsNestedEventTarget* aTarget)
{
// We want to leak the reference when we fail to dispatch it, so that
// we won't release the event in a wrong thread.
LeakRefPtr<nsIRunnable> event(Move(aEvent));
nsCOMPtr<nsIThreadObserver> obs;
#ifdef MOZ_NUWA_PROCESS
@ -554,11 +558,9 @@ nsThread::PutEvent(already_AddRefed<nsIRunnable>&& aEvent, nsNestedEventTarget*
nsChainedEventQueue* queue = aTarget ? aTarget->mQueue : &mEventsRoot;
if (!queue || (queue == &mEventsRoot && mEventsAreDoomed)) {
NS_WARNING("An event was posted to a thread that will never run it (rejected)");
nsCOMPtr<nsIRunnable> temp(aEvent);
nsIRunnable* temp2 = temp.forget().take(); // can't use unused << aEvent here due to Windows (boo)
return temp2 ? NS_ERROR_UNEXPECTED : NS_ERROR_UNEXPECTED; // to make compiler not bletch on us
return NS_ERROR_UNEXPECTED;
}
queue->PutEvent(Move(aEvent), lock);
queue->PutEvent(event.take(), lock);
// Make sure to grab the observer before dropping the lock, otherwise the
// event that we just placed into the queue could run and eventually delete