зеркало из https://github.com/mozilla/gecko-dev.git
Bug 675221 part A: replace XPCOM proxies with runanble for code in XPCOM itself, r=bz
This commit is contained in:
Родитель
4eeef6d0b6
Коммит
51e3a00405
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче