Bug 675221 part A: replace XPCOM proxies with runanble for code in XPCOM itself, r=bz

This commit is contained in:
Benjamin Smedberg 2012-01-11 11:28:21 -05:00
Родитель 4eeef6d0b6
Коммит 51e3a00405
8 изменённых файлов: 159 добавлений и 155 удалений

Просмотреть файл

@ -45,7 +45,6 @@
#include "nsMemory.h"
#include "nsIServiceManager.h"
#include "nsIProxyObjectManager.h"
#include "nsCOMArray.h"
#include "nsThreadUtils.h"
@ -66,7 +65,10 @@ NS_IMPL_QUERY_INTERFACE1_CI(nsConsoleService, nsIConsoleService)
NS_IMPL_CI_INTERFACE_GETTER1(nsConsoleService, nsIConsoleService)
nsConsoleService::nsConsoleService()
: mMessages(nsnull), mCurrent(0), mFull(false), mListening(false), mLock("nsConsoleService.mLock")
: mMessages(nsnull)
, mCurrent(0)
, mFull(false)
, mLock("nsConsoleService.mLock")
{
// XXX grab this from a pref!
// hm, but worry about circularity, bc we want to be able to report
@ -82,16 +84,6 @@ nsConsoleService::~nsConsoleService()
i++;
}
#ifdef DEBUG_mccabe
if (mListeners.Count() != 0) {
fprintf(stderr,
"WARNING - %d console error listeners still registered!\n"
"More calls to nsIConsoleService::UnregisterListener needed.\n",
mListeners.Count());
}
#endif
if (mMessages)
nsMemory::Free(mMessages);
}
@ -107,19 +99,51 @@ nsConsoleService::Init()
// Array elements should be 0 initially for circular buffer algorithm.
memset(mMessages, 0, mBufferSize * sizeof(nsIConsoleMessage *));
mListeners.Init();
return NS_OK;
}
static bool snapshot_enum_func(nsHashKey *key, void *data, void* closure)
{
nsCOMArray<nsIConsoleListener> *array =
reinterpret_cast<nsCOMArray<nsIConsoleListener> *>(closure);
namespace {
// Copy each element into the temporary nsCOMArray...
array->AppendObject((nsIConsoleListener*)data);
return true;
class LogMessageRunnable : public nsRunnable
{
public:
LogMessageRunnable(nsIConsoleMessage* message) :
mMessage(message)
{ }
void AddListener(nsIConsoleListener* listener) {
mListeners.AppendObject(listener);
}
NS_DECL_NSIRUNNABLE
private:
nsCOMPtr<nsIConsoleMessage> mMessage;
nsCOMArray<nsIConsoleListener> mListeners;
};
NS_IMETHODIMP
LogMessageRunnable::Run()
{
for (PRInt32 i = 0; i < mListeners.Count(); ++i)
mListeners[i]->Observe(mMessage);
return NS_OK;
}
PLDHashOperator
CollectCurrentListeners(nsISupports* aKey, nsIConsoleListener* aValue,
void* closure)
{
LogMessageRunnable* r = static_cast<LogMessageRunnable*>(closure);
r->AddListener(aValue);
return PL_DHASH_NEXT;
}
} // anonymous namespace
// nsIConsoleService methods
NS_IMETHODIMP
nsConsoleService::LogMessage(nsIConsoleMessage *message)
@ -127,7 +151,7 @@ nsConsoleService::LogMessage(nsIConsoleMessage *message)
if (message == nsnull)
return NS_ERROR_INVALID_ARG;
nsCOMArray<nsIConsoleListener> listenersSnapshot;
nsRefPtr<LogMessageRunnable> r = new LogMessageRunnable(message);
nsIConsoleMessage *retiredMessage;
NS_ADDREF(message); // early, in case it's same as replaced below.
@ -166,36 +190,12 @@ nsConsoleService::LogMessage(nsIConsoleMessage *message)
* Copy the listeners into the snapshot array - in case a listener
* is removed during an Observe(...) notification...
*/
mListeners.Enumerate(snapshot_enum_func, &listenersSnapshot);
mListeners.EnumerateRead(CollectCurrentListeners, r);
}
if (retiredMessage != nsnull)
NS_RELEASE(retiredMessage);
/*
* Iterate through any registered listeners and tell them about
* the message. We use the mListening flag to guard against
* recursive message logs. This could sometimes result in
* listeners being skipped because of activity on other threads,
* when we only care about the recursive case.
*/
nsCOMPtr<nsIConsoleListener> listener;
PRInt32 snapshotCount = listenersSnapshot.Count();
{
MutexAutoLock lock(mLock);
if (mListening)
return NS_OK;
mListening = true;
}
for (PRInt32 i = 0; i < snapshotCount; i++) {
listenersSnapshot[i]->Observe(message);
}
{
MutexAutoLock lock(mLock);
mListening = false;
}
NS_DispatchToMainThread(r);
return NS_OK;
}
@ -265,63 +265,44 @@ nsConsoleService::GetMessageArray(nsIConsoleMessage ***messages, PRUint32 *count
}
NS_IMETHODIMP
nsConsoleService::RegisterListener(nsIConsoleListener *listener) {
nsresult rv;
/*
* Store a threadsafe proxy to the listener rather than the
* listener itself; we want the console service to be callable
* from any thread, but listeners can be implemented in
* thread-specific ways, and we always want to call them on their
* originating thread. JavaScript is the motivating example.
*/
nsCOMPtr<nsIConsoleListener> proxiedListener;
rv = GetProxyForListener(listener, getter_AddRefs(proxiedListener));
if (NS_FAILED(rv))
return rv;
{
MutexAutoLock lock(mLock);
nsISupportsKey key(listener);
/*
* Put the proxy event listener into a hashtable using the *real*
* listener as the key.
*
* This is necessary because proxy objects do *not* maintain
* nsISupports identity. Therefore, since GetProxyForListener(...)
* can return different proxies for the same object (see bug #85831)
* we need to use the real object as the unique key...
*/
mListeners.Put(&key, proxiedListener);
nsConsoleService::RegisterListener(nsIConsoleListener *listener)
{
if (!NS_IsMainThread()) {
NS_ERROR("nsConsoleService::RegisterListener is main thread only.");
return NS_ERROR_NOT_SAME_THREAD;
}
nsCOMPtr<nsISupports> canonical = do_QueryInterface(listener);
MutexAutoLock lock(mLock);
if (mListeners.GetWeak(canonical)) {
// Reregistering a listener isn't good
return NS_ERROR_FAILURE;
}
mListeners.Put(canonical, listener);
return NS_OK;
}
NS_IMETHODIMP
nsConsoleService::UnregisterListener(nsIConsoleListener *listener) {
nsConsoleService::UnregisterListener(nsIConsoleListener *listener)
{
if (!NS_IsMainThread()) {
NS_ERROR("nsConsoleService::UnregisterListener is main thread only.");
return NS_ERROR_NOT_SAME_THREAD;
}
nsCOMPtr<nsISupports> canonical = do_QueryInterface(listener);
MutexAutoLock lock(mLock);
nsISupportsKey key(listener);
mListeners.Remove(&key);
if (!mListeners.GetWeak(canonical)) {
// Unregistering a listener that was never registered?
return NS_ERROR_FAILURE;
}
mListeners.Remove(canonical);
return NS_OK;
}
nsresult
nsConsoleService::GetProxyForListener(nsIConsoleListener* aListener,
nsIConsoleListener** aProxy)
{
/*
* Would it be better to catch that case and leave the listener unproxied?
*/
return NS_GetProxyForObject(NS_PROXY_TO_CURRENT_THREAD,
NS_GET_IID(nsIConsoleListener),
aListener,
NS_PROXY_ASYNC | NS_PROXY_ALWAYS,
(void**) aProxy);
}
NS_IMETHODIMP
nsConsoleService::Reset()
{

Просмотреть файл

@ -46,7 +46,8 @@
#include "mozilla/Mutex.h"
#include "nsCOMPtr.h"
#include "nsHashtable.h"
#include "nsInterfaceHashtable.h"
#include "nsHashKeys.h"
#include "nsIConsoleService.h"
@ -62,10 +63,6 @@ public:
private:
~nsConsoleService();
// build (or find) a proxy for the listener
nsresult GetProxyForListener(nsIConsoleListener* aListener,
nsIConsoleListener** aProxy);
// Circular buffer of saved messages
nsIConsoleMessage **mMessages;
@ -79,11 +76,7 @@ private:
bool mFull;
// Listeners to notify whenever a new message is logged.
nsSupportsHashtable mListeners;
// Current listener being notified of a logged error - to prevent
// stack overflows.
bool mListening;
nsInterfaceHashtable<nsISupportsHashKey, nsIConsoleListener> mListeners;
// To serialize interesting methods.
mozilla::Mutex mLock;

Просмотреть файл

@ -59,7 +59,6 @@
#include "nsCRT.h"
#include "nsQuickSort.h"
#include "nsEnumeratorUtils.h"
#include "nsIProxyObjectManager.h"
#include "nsThreadUtils.h"
#include "mozilla/Services.h"
@ -497,6 +496,41 @@ nsCategoryManager::get_category(const char* aName) {
return node;
}
namespace {
class CategoryNotificationRunnable : public nsRunnable
{
public:
CategoryNotificationRunnable(nsISupports* aSubject,
const char* aTopic,
const char* aData)
: mSubject(aSubject)
, mTopic(aTopic)
, mData(aData)
{ }
NS_DECL_NSIRUNNABLE
private:
nsCOMPtr<nsISupports> mSubject;
const char* mTopic;
NS_ConvertUTF8toUTF16 mData;
};
NS_IMETHODIMP
CategoryNotificationRunnable::Run()
{
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService)
observerService->NotifyObservers(mSubject, mTopic, mData.get());
return NS_OK;
}
} // anonymous namespace
void
nsCategoryManager::NotifyObservers( const char *aTopic,
const char *aCategoryName,
@ -505,19 +539,7 @@ nsCategoryManager::NotifyObservers( const char *aTopic,
if (mSuppressNotifications)
return;
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (!observerService)
return;
nsCOMPtr<nsIObserverService> obsProxy;
NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
NS_GET_IID(nsIObserverService),
observerService,
NS_PROXY_ASYNC,
getter_AddRefs(obsProxy));
if (!obsProxy)
return;
nsRefPtr<CategoryNotificationRunnable> r;
if (aEntryName) {
nsCOMPtr<nsISupportsCString> entry
@ -529,11 +551,16 @@ nsCategoryManager::NotifyObservers( const char *aTopic,
if (NS_FAILED(rv))
return;
obsProxy->NotifyObservers(entry, aTopic,
NS_ConvertUTF8toUTF16(aCategoryName).get());
r = new CategoryNotificationRunnable(entry, aTopic, aCategoryName);
} else {
obsProxy->NotifyObservers(this, aTopic,
NS_ConvertUTF8toUTF16(aCategoryName).get());
r = new CategoryNotificationRunnable(this, aTopic, aCategoryName);
}
if (NS_IsMainThread()) {
r->Run();
}
else {
NS_DispatchToMainThread(r);
}
}

Просмотреть файл

@ -157,7 +157,7 @@ private:
CategoryNode* get_category(const char* aName);
void NotifyObservers(const char* aTopic,
const char* aCategoryName,
const char* aCategoryName, // must be a static string
const char* aEntryName);
PLArenaPool mArena;

Просмотреть файл

@ -64,7 +64,6 @@
#include "nsTraceRefcntImpl.h"
#include "nsILocalFile.h"
#include "nsIProxyObjectManager.h"
#ifdef XP_WIN
#include <windows.h>

Просмотреть файл

@ -37,7 +37,6 @@
#include "TestHarness.h"
#include "nsIProxyObjectManager.h"
#include "nsIThread.h"
#include "nsIThreadPool.h"
@ -178,13 +177,6 @@ int main(int argc, char** argv)
nsresult rv;
// Grab the proxy service before messing with the thread pool. This is a
// workaround for bug 449822 where the thread pool shutdown can create two
// instances of the proxy service and hang.
nsCOMPtr<nsIProxyObjectManager> proxyObjMgr =
do_GetService(NS_XPCOMPROXY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIThreadPool> pool =
do_CreateInstance(NS_THREADPOOL_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, 1);

Просмотреть файл

@ -46,7 +46,6 @@
#include "nsIObserverService.h"
#include "nsIServiceManager.h"
#include "nsIProxyObjectManager.h"
#include "mozilla/Services.h"
#include <math.h>
@ -80,6 +79,35 @@ TimerThread::InitLocks()
return NS_OK;
}
namespace {
class TimerObserverRunnable : public nsRunnable
{
public:
TimerObserverRunnable(nsIObserver* observer)
: mObserver(observer)
{ }
NS_DECL_NSIRUNNABLE
private:
nsCOMPtr<nsIObserver> mObserver;
};
NS_IMETHODIMP
TimerObserverRunnable::Run()
{
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService) {
observerService->AddObserver(mObserver, "sleep_notification", PR_FALSE);
observerService->AddObserver(mObserver, "wake_notification", PR_FALSE);
}
return NS_OK;
}
} // anonymous namespace
nsresult TimerThread::Init()
{
PR_LOG(gTimerLog, PR_LOG_DEBUG, ("TimerThread::Init [%d]\n", mInitialized));
@ -98,21 +126,12 @@ nsresult TimerThread::Init()
mThread = nsnull;
}
else {
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
// We must not use the observer service from a background thread!
if (observerService && !NS_IsMainThread()) {
nsCOMPtr<nsIObserverService> result = nsnull;
NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
NS_GET_IID(nsIObserverService),
observerService, NS_PROXY_ASYNC,
getter_AddRefs(result));
observerService.swap(result);
nsRefPtr<TimerObserverRunnable> r = new TimerObserverRunnable(this);
if (NS_IsMainThread()) {
r->Run();
}
// We'll be released at xpcom shutdown
if (observerService) {
observerService->AddObserver(this, "sleep_notification", false);
observerService->AddObserver(this, "wake_notification", false);
else {
NS_DispatchToMainThread(r);
}
}

Просмотреть файл

@ -36,7 +36,6 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsIProxyObjectManager.h"
#include "nsIClassInfoImpl.h"
#include "nsThreadPool.h"
#include "nsThreadManager.h"
@ -144,14 +143,8 @@ nsThreadPool::ShutdownThread(nsIThread *thread)
NS_ASSERTION(!NS_IsMainThread(), "wrong thread");
nsCOMPtr<nsIThread> doomed;
NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD, NS_GET_IID(nsIThread), thread,
NS_PROXY_ASYNC, getter_AddRefs(doomed));
if (doomed) {
doomed->Shutdown();
} else {
NS_WARNING("failed to construct proxy to main thread");
}
nsRefPtr<nsIRunnable> r = NS_NewRunnableMethod(thread, &nsIThread::Shutdown);
NS_DispatchToMainThread(r);
}
NS_IMETHODIMP