initial checkin of xpcom changes
git-svn-id: svn://10.0.0.236/branches/THREADS_20060213_BRANCH@189905 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -46,6 +46,7 @@
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "nsSupportsArray.h"
|
||||
#include "nsThreadManager.h"
|
||||
|
||||
#include "nsConsoleService.h"
|
||||
#include "nsConsoleMessage.h"
|
||||
@@ -322,7 +323,11 @@ nsConsoleService::GetProxyForListener(nsIConsoleListener* aListener,
|
||||
*
|
||||
* Would it be better to catch that case and leave the listener unproxied?
|
||||
*/
|
||||
rv = proxyManager->GetProxyForObject(NS_CURRENT_EVENTQ,
|
||||
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsThreadManager::get()->GetCurrentThread(getter_AddRefs(thread));
|
||||
|
||||
rv = proxyManager->GetProxyForObject(thread,
|
||||
NS_GET_IID(nsIConsoleListener),
|
||||
aListener,
|
||||
PROXY_ASYNC | PROXY_ALWAYS,
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsMemoryImpl.h"
|
||||
#include "nsThreadManager.h"
|
||||
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsIServiceManager.h"
|
||||
@@ -46,7 +46,7 @@
|
||||
#include "nsIThread.h"
|
||||
|
||||
#include "prmem.h"
|
||||
#include "plevent.h"
|
||||
#include "prcvar.h"
|
||||
|
||||
#include "nsAlgorithm.h"
|
||||
#include "nsAutoLock.h"
|
||||
@@ -237,20 +237,7 @@ nsMemoryImpl::FlushMemory(const PRUnichar* aReason, PRBool aImmediate)
|
||||
// They've asked us to run the flusher *immediately*. We've
|
||||
// got to be on the UI main thread for us to be able to do
|
||||
// that...are we?
|
||||
PRBool isOnUIThread = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIThread> main;
|
||||
rv = nsIThread::GetMainThread(getter_AddRefs(main));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsIThread> current;
|
||||
rv = nsIThread::GetCurrent(getter_AddRefs(current));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (current == main)
|
||||
isOnUIThread = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (! isOnUIThread) {
|
||||
if (!nsThreadManager::IsMainThread()) {
|
||||
NS_ERROR("can't synchronously flush memory: not on UI thread");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@@ -272,16 +259,11 @@ nsMemoryImpl::FlushMemory(const PRUnichar* aReason, PRBool aImmediate)
|
||||
rv = RunFlushers(aReason);
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIEventQueueService> eqs = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
|
||||
if (eqs) {
|
||||
nsCOMPtr<nsIEventQueue> eq;
|
||||
rv = eqs->GetThreadEventQueue(NS_UI_THREAD, getter_AddRefs(eq));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
PL_InitEvent(&sFlushEvent.mEvent, this, HandleFlushEvent, DestroyFlushEvent);
|
||||
sFlushEvent.mReason = aReason;
|
||||
|
||||
rv = eq->PostEvent(NS_REINTERPRET_CAST(PLEvent*, &sFlushEvent));
|
||||
}
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsThreadManager::get()->GetMainThread(getter_AddRefs(thread));
|
||||
if (thread) {
|
||||
sFlushEvent.mReason = aReason;
|
||||
rv = thread->Dispatch(&sFlushEvent, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,19 +287,16 @@ nsMemoryImpl::RunFlushers(const PRUnichar* aReason)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void*
|
||||
nsMemoryImpl::HandleFlushEvent(PLEvent* aEvent)
|
||||
{
|
||||
FlushEvent* event = NS_REINTERPRET_CAST(FlushEvent*, aEvent);
|
||||
// XXX need NS_IMPL_STATIC_ADDREF/RELEASE
|
||||
NS_IMETHODIMP_(nsrefcnt) nsMemoryImpl::FlushEvent::AddRef() { return 2; }
|
||||
NS_IMETHODIMP_(nsrefcnt) nsMemoryImpl::FlushEvent::Release() { return 1; }
|
||||
NS_IMPL_QUERY_INTERFACE1(nsMemoryImpl::FlushEvent, nsIRunnable)
|
||||
|
||||
sGlobalMemory.RunFlushers(event->mReason);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nsMemoryImpl::DestroyFlushEvent(PLEvent* aEvent)
|
||||
NS_IMETHODIMP
|
||||
nsMemoryImpl::FlushEvent::Run()
|
||||
{
|
||||
// no-op, since mEvent is a member of nsMemoryImpl
|
||||
sGlobalMemory.RunFlushers(mReason);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRLock*
|
||||
@@ -421,10 +400,8 @@ MemoryFlusher::Init()
|
||||
sCVar = PR_NewCondVar(sLock);
|
||||
if (!sCVar) return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_NewThread(&sThread,
|
||||
this,
|
||||
0, /* XXX use default stack size? */
|
||||
PR_JOINABLE_THREAD);
|
||||
return nsThreadManager::NewThread(NS_LITERAL_CSTRING("xpcom.memoryflusher"),
|
||||
this, &sThread);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -438,7 +415,7 @@ MemoryFlusher::StopAndJoin()
|
||||
}
|
||||
|
||||
if (sThread)
|
||||
sThread->Join();
|
||||
sThread->Shutdown();
|
||||
}
|
||||
|
||||
NS_IF_RELEASE(sThread);
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
#define nsMemoryImpl_h__
|
||||
|
||||
#include "nsIMemory.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "prlock.h"
|
||||
#include "plevent.h"
|
||||
|
||||
// nsMemoryImpl is a static object. We can do this because it doesn't have
|
||||
// a constructor/destructor or any instance members. Please don't add
|
||||
@@ -64,14 +64,13 @@ public:
|
||||
NS_HIDDEN_(nsresult) FlushMemory(const PRUnichar* aReason, PRBool aImmediate);
|
||||
|
||||
protected:
|
||||
struct FlushEvent {
|
||||
PLEvent mEvent;
|
||||
struct FlushEvent : public nsIRunnable {
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIRUNNABLE
|
||||
const PRUnichar* mReason;
|
||||
};
|
||||
|
||||
NS_HIDDEN_(nsresult) RunFlushers(const PRUnichar* aReason);
|
||||
static NS_HIDDEN_(void*) PR_CALLBACK HandleFlushEvent(PLEvent* aEvent);
|
||||
static NS_HIDDEN_(void) PR_CALLBACK DestroyFlushEvent(PLEvent* aEvent);
|
||||
|
||||
static PRLock* sFlushLock;
|
||||
static PRBool sIsFlushing;
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
#include "nsIAtom.h"
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsRecyclingAllocator.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsDeque.h"
|
||||
#include "nsTraceRefcnt.h"
|
||||
#include "nsTraceRefcntImpl.h"
|
||||
@@ -138,7 +137,6 @@ void XXXNeverCalled()
|
||||
a.Init(0, 0, 0, 0, 0);
|
||||
a.Alloc(0);
|
||||
a.Free(0, 0);
|
||||
nsIThread::GetCurrent(nsnull);
|
||||
nsDeque d(nsnull);
|
||||
nsDequeIterator di(d);
|
||||
nsTraceRefcnt::LogAddCOMPtr(nsnull, nsnull);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim:set ts=4 sw=4 sts=4 ci et: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@@ -70,9 +71,7 @@
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsGenericFactory.h"
|
||||
|
||||
#include "nsEventQueueService.h"
|
||||
#include "nsEventQueue.h"
|
||||
#include "nsEventQueueUtils.h"
|
||||
#include "nsThreadManager.h"
|
||||
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "nsProxyEventPrivate.h" // access to the impl of nsProxyObjectManager for the generic factory registration.
|
||||
@@ -149,7 +148,6 @@ static NS_DEFINE_CID(kMemoryCID, NS_MEMORY_CID);
|
||||
static NS_DEFINE_CID(kINIParserFactoryCID, NS_INIPARSERFACTORY_CID);
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsProcess)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsEventQueueServiceImpl, Init)
|
||||
|
||||
#define NS_ENVIRONMENT_CLASSNAME "Environment Service"
|
||||
|
||||
@@ -217,6 +215,19 @@ NS_GENERIC_AGGREGATED_CONSTRUCTOR_INIT(nsProperties, Init)
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsUUIDGenerator)
|
||||
|
||||
static NS_METHOD
|
||||
nsThreadManagerGetSingleton(nsISupports* outer,
|
||||
const nsIID& aIID,
|
||||
void* *aInstancePtr)
|
||||
{
|
||||
NS_ASSERTION(aInstancePtr, "null outptr");
|
||||
NS_ENSURE_TRUE(!outer, NS_ERROR_NO_AGGREGATION);
|
||||
|
||||
return nsThreadManager::get()->QueryInterface(aIID, aInstancePtr);
|
||||
}
|
||||
NS_DECL_CLASSINFO(nsThreadManager)
|
||||
NS_DECL_CLASSINFO(nsThread)
|
||||
|
||||
static NS_METHOD
|
||||
nsXPTIInterfaceInfoManagerGetSingleton(nsISupports* outer,
|
||||
const nsIID& aIID,
|
||||
@@ -349,9 +360,6 @@ static const nsModuleComponentInfo components[] = {
|
||||
#endif
|
||||
COMPONENT(OBSERVERSERVICE, nsObserverService::Create),
|
||||
COMPONENT(GENERICFACTORY, nsGenericFactory::Create),
|
||||
COMPONENT(EVENTQUEUESERVICE, nsEventQueueServiceImplConstructor),
|
||||
COMPONENT(EVENTQUEUE, nsEventQueueImpl::Create),
|
||||
COMPONENT(THREAD, nsThread::Create),
|
||||
|
||||
#define NS_XPCOMPROXY_CID NS_PROXYEVENT_MANAGER_CID
|
||||
COMPONENT(XPCOMPROXY, nsProxyObjectManager::Create),
|
||||
@@ -388,6 +396,10 @@ static const nsModuleComponentInfo components[] = {
|
||||
COMPONENT(PROCESS, nsProcessConstructor),
|
||||
COMPONENT(ENVIRONMENT, nsEnvironment::Create),
|
||||
|
||||
COMPONENT_CI_FLAGS(THREADMANAGER, nsThreadManagerGetSingleton,
|
||||
nsThreadManager,
|
||||
nsIClassInfo::THREADSAFE | nsIClassInfo::SINGLETON),
|
||||
|
||||
COMPONENT_CI_FLAGS(STRINGINPUTSTREAM, nsStringInputStreamConstructor,
|
||||
nsStringInputStream, nsIClassInfo::THREADSAFE),
|
||||
COMPONENT(MULTIPLEXINPUTSTREAM, nsMultiplexInputStreamConstructor),
|
||||
@@ -471,7 +483,7 @@ NS_InitXPCOM3(nsIServiceManager* *result,
|
||||
NS_LogInit();
|
||||
|
||||
// Establish the main thread here.
|
||||
rv = nsIThread::SetMainThread();
|
||||
rv = nsThreadManager::get()->Init();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Set up the timer globals/timer thread
|
||||
@@ -659,14 +671,8 @@ NS_ShutdownXPCOM(nsIServiceManager* servMgr)
|
||||
// Block it so that the COMPtr will get deleted before we hit
|
||||
// servicemanager shutdown
|
||||
|
||||
// grab the event queue service so that we can process events and
|
||||
// manage event queues
|
||||
nsRefPtr<nsEventQueueServiceImpl> eqs;
|
||||
CallGetService(NS_EVENTQUEUESERVICE_CONTRACTID,
|
||||
(nsEventQueueServiceImpl**) getter_AddRefs(eqs));
|
||||
|
||||
nsCOMPtr <nsIEventQueue> currentQ;
|
||||
NS_GetCurrentEventQ(getter_AddRefs(currentQ), eqs);
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsThreadManager::get()->GetCurrentThread(getter_AddRefs(thread));
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
do_GetService("@mozilla.org/observer-service;1");
|
||||
@@ -683,22 +689,21 @@ NS_ShutdownXPCOM(nsIServiceManager* servMgr)
|
||||
}
|
||||
}
|
||||
|
||||
if (currentQ)
|
||||
currentQ->ProcessPendingEvents();
|
||||
if (thread)
|
||||
NS_RunPendingTasks(thread);
|
||||
|
||||
if (observerService)
|
||||
(void) observerService->
|
||||
NotifyObservers(nsnull, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID,
|
||||
nsnull);
|
||||
|
||||
if (currentQ)
|
||||
currentQ->ProcessPendingEvents();
|
||||
if (thread)
|
||||
NS_RunPendingTasks(thread);
|
||||
|
||||
if (eqs)
|
||||
eqs->Shutdown();
|
||||
nsThreadManager::get()->Shutdown();
|
||||
|
||||
if (currentQ)
|
||||
currentQ->ProcessPendingEvents();
|
||||
if (thread)
|
||||
NS_RunPendingTasks(thread);
|
||||
|
||||
// We save the "xpcom-shutdown-loaders" observers to notify after
|
||||
// the observerservice is gone.
|
||||
@@ -793,7 +798,6 @@ NS_ShutdownXPCOM(nsIServiceManager* servMgr)
|
||||
EmptyEnumeratorImpl::Shutdown();
|
||||
nsMemoryImpl::Shutdown();
|
||||
|
||||
nsThread::Shutdown();
|
||||
NS_PurgeAtomTable();
|
||||
|
||||
NS_IF_RELEASE(gDebug);
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
#include "nsQuickSort.h"
|
||||
#include "nsEnumeratorUtils.h"
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "nsThreadManager.h"
|
||||
|
||||
class nsIComponentLoaderManager;
|
||||
|
||||
@@ -544,13 +545,17 @@ nsCategoryManager::NotifyObservers( const char *aTopic,
|
||||
if (!observerService)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIThread> mainThread;
|
||||
nsThreadManager::get()->GetMainThread(getter_AddRefs(mainThread));
|
||||
|
||||
nsCOMPtr<nsIObserverService> obsProxy;
|
||||
NS_GetProxyForObject(NS_UI_THREAD_EVENTQ,
|
||||
NS_GetProxyForObject(mainThread,
|
||||
NS_GET_IID(nsIObserverService),
|
||||
observerService,
|
||||
PROXY_ASYNC,
|
||||
getter_AddRefs(obsProxy));
|
||||
if (!obsProxy) return;
|
||||
if (!obsProxy)
|
||||
return;
|
||||
|
||||
if (aEntryName) {
|
||||
nsCOMPtr<nsISupportsCString> entry
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#include "nsIInputStream.idl"
|
||||
|
||||
interface nsIInputStreamCallback;
|
||||
interface nsIEventTarget;
|
||||
interface nsIDispatchTarget;
|
||||
|
||||
/**
|
||||
* If an input stream is non-blocking, it may return NS_BASE_STREAM_WOULD_BLOCK
|
||||
@@ -52,7 +52,7 @@ interface nsIEventTarget;
|
||||
* necessary that a non-blocking nsIInputStream implementation also implement
|
||||
* nsIAsyncInputStream.
|
||||
*/
|
||||
[scriptable, uuid(15a15329-00de-44e8-ab06-0d0b0d43dc5b)]
|
||||
[scriptable, uuid(a5f255ab-4801-4161-8816-277ac92f6ad1)]
|
||||
interface nsIAsyncInputStream : nsIInputStream
|
||||
{
|
||||
/**
|
||||
@@ -108,7 +108,7 @@ interface nsIAsyncInputStream : nsIInputStream
|
||||
void asyncWait(in nsIInputStreamCallback aCallback,
|
||||
in unsigned long aFlags,
|
||||
in unsigned long aRequestedCount,
|
||||
in nsIEventTarget aEventTarget);
|
||||
in nsIDispatchTarget aDispatchTarget);
|
||||
|
||||
/**
|
||||
* If passed to asyncWait, this flag overrides the default behavior,
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#include "nsIOutputStream.idl"
|
||||
|
||||
interface nsIOutputStreamCallback;
|
||||
interface nsIEventTarget;
|
||||
interface nsIDispatchTarget;
|
||||
|
||||
/**
|
||||
* If an output stream is non-blocking, it may return NS_BASE_STREAM_WOULD_BLOCK
|
||||
@@ -52,7 +52,7 @@ interface nsIEventTarget;
|
||||
* necessary that a non-blocking nsIOutputStream implementation also implement
|
||||
* nsIAsyncOutputStream.
|
||||
*/
|
||||
[scriptable, uuid(10dc9c94-8aff-49c6-8af9-d7fdb7339dae)]
|
||||
[scriptable, uuid(beb632d3-d77a-4e90-9134-f9ece69e8200)]
|
||||
interface nsIAsyncOutputStream : nsIOutputStream
|
||||
{
|
||||
/**
|
||||
@@ -99,7 +99,7 @@ interface nsIAsyncOutputStream : nsIOutputStream
|
||||
* Wait until at least this many bytes can be written. This is only
|
||||
* a suggestion to the underlying stream; it may be ignored. The
|
||||
* caller may pass zero to indicate no preference.
|
||||
* @param aEventTarget
|
||||
* @param aDispatchTarget
|
||||
* Specify NULL to receive notification on ANY thread (possibly even
|
||||
* recursively on the calling thread -- i.e., synchronously), or
|
||||
* specify that the notification be delivered to a specific event
|
||||
@@ -108,7 +108,7 @@ interface nsIAsyncOutputStream : nsIOutputStream
|
||||
void asyncWait(in nsIOutputStreamCallback aCallback,
|
||||
in unsigned long aFlags,
|
||||
in unsigned long aRequestedCount,
|
||||
in nsIEventTarget aEventTarget);
|
||||
in nsIDispatchTarget aDispatchTarget);
|
||||
|
||||
/**
|
||||
* If passed to asyncWait, this flag overrides the default behavior,
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsIPipe.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsIDispatchTarget.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "nsSegmentedBuffer.h"
|
||||
#include "nsStreamUtils.h"
|
||||
@@ -801,7 +801,7 @@ NS_IMETHODIMP
|
||||
nsPipeInputStream::AsyncWait(nsIInputStreamCallback *callback,
|
||||
PRUint32 flags,
|
||||
PRUint32 requestedCount,
|
||||
nsIEventTarget *target)
|
||||
nsIDispatchTarget *target)
|
||||
{
|
||||
LOG(("III AsyncWait [this=%x]\n", this));
|
||||
|
||||
@@ -1172,7 +1172,7 @@ NS_IMETHODIMP
|
||||
nsPipeOutputStream::AsyncWait(nsIOutputStreamCallback *callback,
|
||||
PRUint32 flags,
|
||||
PRUint32 requestedCount,
|
||||
nsIEventTarget *target)
|
||||
nsIDispatchTarget *target)
|
||||
{
|
||||
LOG(("OOO AsyncWait [this=%x]\n", this));
|
||||
|
||||
|
||||
@@ -39,20 +39,21 @@
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIPipe.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsIDispatchTarget.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsString.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsInputStreamReadyEvent : public PLEvent
|
||||
class nsInputStreamReadyEvent : public nsIRunnable
|
||||
, public nsIInputStreamCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsInputStreamReadyEvent(nsIInputStreamCallback *callback,
|
||||
nsIEventTarget *target)
|
||||
nsIDispatchTarget *target)
|
||||
: mCallback(callback)
|
||||
, mTarget(target)
|
||||
{
|
||||
@@ -61,28 +62,28 @@ public:
|
||||
private:
|
||||
~nsInputStreamReadyEvent()
|
||||
{
|
||||
if (mCallback) {
|
||||
nsresult rv;
|
||||
//
|
||||
// whoa!! looks like we never posted this event. take care to
|
||||
// release mCallback on the correct thread. if mTarget lives on the
|
||||
// calling thread, then we are ok. otherwise, we have to try to
|
||||
// proxy the Release over the right thread. if that thread is dead,
|
||||
// then there's nothing we can do... better to leak than crash.
|
||||
//
|
||||
PRBool val;
|
||||
rv = mTarget->IsOnCurrentThread(&val);
|
||||
if (NS_FAILED(rv) || !val) {
|
||||
nsCOMPtr<nsIInputStreamCallback> event;
|
||||
NS_NewInputStreamReadyEvent(getter_AddRefs(event), mCallback, mTarget);
|
||||
mCallback = 0;
|
||||
if (event) {
|
||||
rv = event->OnInputStreamReady(nsnull);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_NOTREACHED("leaking stream event");
|
||||
nsISupports *sup = event;
|
||||
NS_ADDREF(sup);
|
||||
}
|
||||
if (!mCallback)
|
||||
return;
|
||||
//
|
||||
// whoa!! looks like we never posted this event. take care to
|
||||
// release mCallback on the correct thread. if mTarget lives on the
|
||||
// calling thread, then we are ok. otherwise, we have to try to
|
||||
// proxy the Release over the right thread. if that thread is dead,
|
||||
// then there's nothing we can do... better to leak than crash.
|
||||
//
|
||||
PRBool val;
|
||||
nsresult rv = mTarget->IsOnCurrentThread(&val);
|
||||
if (NS_FAILED(rv) || !val) {
|
||||
nsCOMPtr<nsIInputStreamCallback> event;
|
||||
NS_NewInputStreamReadyEvent(getter_AddRefs(event), mCallback,
|
||||
mTarget);
|
||||
mCallback = 0;
|
||||
if (event) {
|
||||
rv = event->OnInputStreamReady(nsnull);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_NOTREACHED("leaking stream event");
|
||||
nsISupports *sup = event;
|
||||
NS_ADDREF(sup);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,55 +94,44 @@ public:
|
||||
{
|
||||
mStream = stream;
|
||||
|
||||
// will be released when event is handled
|
||||
NS_ADDREF_THIS();
|
||||
|
||||
PL_InitEvent(this, nsnull, EventHandler, EventCleanup);
|
||||
|
||||
if (NS_FAILED(mTarget->PostEvent(this))) {
|
||||
NS_WARNING("PostEvent failed");
|
||||
NS_RELEASE_THIS();
|
||||
nsresult rv =
|
||||
mTarget->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Dispatch failed");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (mCallback) {
|
||||
mCallback->OnInputStreamReady(mStream);
|
||||
mCallback = nsnull;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIAsyncInputStream> mStream;
|
||||
nsCOMPtr<nsIInputStreamCallback> mCallback;
|
||||
nsCOMPtr<nsIEventTarget> mTarget;
|
||||
|
||||
PR_STATIC_CALLBACK(void *) EventHandler(PLEvent *plevent)
|
||||
{
|
||||
nsInputStreamReadyEvent *ev = (nsInputStreamReadyEvent *) plevent;
|
||||
// bypass event delivery if this is a cleanup event...
|
||||
if (ev->mCallback)
|
||||
ev->mCallback->OnInputStreamReady(ev->mStream);
|
||||
ev->mCallback = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(void) EventCleanup(PLEvent *plevent)
|
||||
{
|
||||
nsInputStreamReadyEvent *ev = (nsInputStreamReadyEvent *) plevent;
|
||||
NS_RELEASE(ev);
|
||||
}
|
||||
nsCOMPtr<nsIDispatchTarget> mTarget;
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsInputStreamReadyEvent,
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(nsInputStreamReadyEvent, nsIRunnable,
|
||||
nsIInputStreamCallback)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsOutputStreamReadyEvent : public PLEvent
|
||||
class nsOutputStreamReadyEvent : public nsIRunnable
|
||||
, public nsIOutputStreamCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsOutputStreamReadyEvent(nsIOutputStreamCallback *callback,
|
||||
nsIEventTarget *target)
|
||||
nsIDispatchTarget *target)
|
||||
: mCallback(callback)
|
||||
, mTarget(target)
|
||||
{
|
||||
@@ -150,82 +140,64 @@ public:
|
||||
private:
|
||||
~nsOutputStreamReadyEvent()
|
||||
{
|
||||
if (mCallback) {
|
||||
nsresult rv;
|
||||
//
|
||||
// whoa!! looks like we never posted this event. take care to
|
||||
// release mCallback on the correct thread. if mTarget lives on the
|
||||
// calling thread, then we are ok. otherwise, we have to try to
|
||||
// proxy the Release over the right thread. if that thread is dead,
|
||||
// then there's nothing we can do... better to leak than crash.
|
||||
//
|
||||
PRBool val;
|
||||
rv = mTarget->IsOnCurrentThread(&val);
|
||||
if (NS_FAILED(rv) || !val) {
|
||||
nsCOMPtr<nsIOutputStreamCallback> event;
|
||||
NS_NewOutputStreamReadyEvent(getter_AddRefs(event), mCallback, mTarget);
|
||||
mCallback = 0;
|
||||
if (event) {
|
||||
rv = event->OnOutputStreamReady(nsnull);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_NOTREACHED("leaking stream event");
|
||||
nsISupports *sup = event;
|
||||
NS_ADDREF(sup);
|
||||
}
|
||||
if (!mCallback)
|
||||
return;
|
||||
//
|
||||
// whoa!! looks like we never posted this event. take care to
|
||||
// release mCallback on the correct thread. if mTarget lives on the
|
||||
// calling thread, then we are ok. otherwise, we have to try to
|
||||
// proxy the Release over the right thread. if that thread is dead,
|
||||
// then there's nothing we can do... better to leak than crash.
|
||||
//
|
||||
PRBool val;
|
||||
nsresult rv = mTarget->IsOnCurrentThread(&val);
|
||||
if (NS_FAILED(rv) || !val) {
|
||||
nsCOMPtr<nsIOutputStreamCallback> event;
|
||||
NS_NewOutputStreamReadyEvent(getter_AddRefs(event), mCallback,
|
||||
mTarget);
|
||||
mCallback = 0;
|
||||
if (event) {
|
||||
rv = event->OnOutputStreamReady(nsnull);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_NOTREACHED("leaking stream event");
|
||||
nsISupports *sup = event;
|
||||
NS_ADDREF(sup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void Init(nsIOutputStreamCallback *callback, nsIEventTarget *target)
|
||||
{
|
||||
mCallback = callback;
|
||||
mTarget = target;
|
||||
|
||||
PL_InitEvent(this, nsnull, EventHandler, EventCleanup);
|
||||
}
|
||||
|
||||
NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *stream)
|
||||
{
|
||||
mStream = stream;
|
||||
|
||||
// this will be released when the event is handled
|
||||
NS_ADDREF_THIS();
|
||||
|
||||
PL_InitEvent(this, nsnull, EventHandler, EventCleanup);
|
||||
|
||||
if (NS_FAILED(mTarget->PostEvent(this))) {
|
||||
nsresult rv =
|
||||
mTarget->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("PostEvent failed");
|
||||
NS_RELEASE_THIS();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (mCallback) {
|
||||
mCallback->OnOutputStreamReady(mStream);
|
||||
mCallback = nsnull;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIAsyncOutputStream> mStream;
|
||||
nsCOMPtr<nsIOutputStreamCallback> mCallback;
|
||||
nsCOMPtr<nsIEventTarget> mTarget;
|
||||
|
||||
PR_STATIC_CALLBACK(void *) EventHandler(PLEvent *plevent)
|
||||
{
|
||||
nsOutputStreamReadyEvent *ev = (nsOutputStreamReadyEvent *) plevent;
|
||||
if (ev->mCallback)
|
||||
ev->mCallback->OnOutputStreamReady(ev->mStream);
|
||||
ev->mCallback = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(void) EventCleanup(PLEvent *ev)
|
||||
{
|
||||
nsOutputStreamReadyEvent *event = (nsOutputStreamReadyEvent *) ev;
|
||||
NS_RELEASE(event);
|
||||
}
|
||||
nsCOMPtr<nsIDispatchTarget> mTarget;
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsOutputStreamReadyEvent,
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(nsOutputStreamReadyEvent, nsIRunnable,
|
||||
nsIOutputStreamCallback)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -233,7 +205,7 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(nsOutputStreamReadyEvent,
|
||||
NS_COM nsresult
|
||||
NS_NewInputStreamReadyEvent(nsIInputStreamCallback **event,
|
||||
nsIInputStreamCallback *callback,
|
||||
nsIEventTarget *target)
|
||||
nsIDispatchTarget *target)
|
||||
{
|
||||
nsInputStreamReadyEvent *ev = new nsInputStreamReadyEvent(callback, target);
|
||||
if (!ev)
|
||||
@@ -245,7 +217,7 @@ NS_NewInputStreamReadyEvent(nsIInputStreamCallback **event,
|
||||
NS_COM nsresult
|
||||
NS_NewOutputStreamReadyEvent(nsIOutputStreamCallback **event,
|
||||
nsIOutputStreamCallback *callback,
|
||||
nsIEventTarget *target)
|
||||
nsIDispatchTarget *target)
|
||||
{
|
||||
nsOutputStreamReadyEvent *ev = new nsOutputStreamReadyEvent(callback, target);
|
||||
if (!ev)
|
||||
@@ -260,6 +232,7 @@ NS_NewOutputStreamReadyEvent(nsIOutputStreamCallback **event,
|
||||
// abstract stream copier...
|
||||
class nsAStreamCopier : public nsIInputStreamCallback
|
||||
, public nsIOutputStreamCallback
|
||||
, public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
@@ -284,7 +257,7 @@ public:
|
||||
// kick off the async copy...
|
||||
nsresult Start(nsIInputStream *source,
|
||||
nsIOutputStream *sink,
|
||||
nsIEventTarget *target,
|
||||
nsIDispatchTarget *target,
|
||||
nsAsyncCopyCallbackFun callback,
|
||||
void *closure,
|
||||
PRUint32 chunksize)
|
||||
@@ -386,26 +359,20 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(void*) HandleContinuationEvent(PLEvent *event)
|
||||
// continuation event handler
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsAStreamCopier *self = (nsAStreamCopier *) event->owner;
|
||||
self->Process();
|
||||
Process();
|
||||
|
||||
// clear "in process" flag and post any pending continuation event
|
||||
nsAutoLock lock(self->mLock);
|
||||
self->mEventInProcess = PR_FALSE;
|
||||
if (self->mEventIsPending) {
|
||||
self->mEventIsPending = PR_FALSE;
|
||||
self->PostContinuationEvent_Locked();
|
||||
nsAutoLock lock(mLock);
|
||||
mEventInProcess = PR_FALSE;
|
||||
if (mEventIsPending) {
|
||||
mEventIsPending = PR_FALSE;
|
||||
PostContinuationEvent_Locked();
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(void) DestroyContinuationEvent(PLEvent *event)
|
||||
{
|
||||
nsAStreamCopier *self = (nsAStreamCopier *) event->owner;
|
||||
NS_RELEASE(self);
|
||||
delete event;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult PostContinuationEvent()
|
||||
@@ -427,23 +394,11 @@ public:
|
||||
if (mEventInProcess)
|
||||
mEventIsPending = PR_TRUE;
|
||||
else {
|
||||
PLEvent *event = new PLEvent;
|
||||
if (!event)
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
else {
|
||||
NS_ADDREF_THIS();
|
||||
PL_InitEvent(event, this,
|
||||
HandleContinuationEvent,
|
||||
DestroyContinuationEvent);
|
||||
|
||||
rv = mTarget->PostEvent(event);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mEventInProcess = PR_TRUE;
|
||||
else {
|
||||
NS_ERROR("unable to post continuation event");
|
||||
PL_DestroyEvent(event);
|
||||
}
|
||||
}
|
||||
rv = mTarget->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mEventInProcess = PR_TRUE;
|
||||
else
|
||||
NS_WARNING("unable to post continuation event");
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@@ -453,7 +408,7 @@ protected:
|
||||
nsCOMPtr<nsIOutputStream> mSink;
|
||||
nsCOMPtr<nsIAsyncInputStream> mAsyncSource;
|
||||
nsCOMPtr<nsIAsyncOutputStream> mAsyncSink;
|
||||
nsCOMPtr<nsIEventTarget> mTarget;
|
||||
nsCOMPtr<nsIDispatchTarget> mTarget;
|
||||
PRLock *mLock;
|
||||
nsAsyncCopyCallbackFun mCallback;
|
||||
void *mClosure;
|
||||
@@ -462,9 +417,10 @@ protected:
|
||||
PRPackedBool mEventIsPending;
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(nsAStreamCopier,
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS3(nsAStreamCopier,
|
||||
nsIInputStreamCallback,
|
||||
nsIOutputStreamCallback)
|
||||
nsIOutputStreamCallback,
|
||||
nsIRunnable)
|
||||
|
||||
class nsStreamCopierIB : public nsAStreamCopier
|
||||
{
|
||||
@@ -557,7 +513,7 @@ public:
|
||||
NS_COM nsresult
|
||||
NS_AsyncCopy(nsIInputStream *source,
|
||||
nsIOutputStream *sink,
|
||||
nsIEventTarget *target,
|
||||
nsIDispatchTarget *target,
|
||||
nsAsyncCopyMode mode,
|
||||
PRUint32 chunkSize,
|
||||
nsAsyncCopyCallbackFun callback,
|
||||
|
||||
@@ -44,7 +44,7 @@ class nsIInputStream;
|
||||
class nsIOutputStream;
|
||||
class nsIInputStreamCallback;
|
||||
class nsIOutputStreamCallback;
|
||||
class nsIEventTarget;
|
||||
class nsIDispatchTarget;
|
||||
|
||||
/**
|
||||
* A "one-shot" proxy of the OnInputStreamReady callback. The resulting
|
||||
@@ -59,7 +59,7 @@ class nsIEventTarget;
|
||||
extern NS_COM nsresult
|
||||
NS_NewInputStreamReadyEvent(nsIInputStreamCallback **aEvent,
|
||||
nsIInputStreamCallback *aNotify,
|
||||
nsIEventTarget *aEventTarget);
|
||||
nsIDispatchTarget *aEventTarget);
|
||||
|
||||
/**
|
||||
* A "one-shot" proxy of the OnOutputStreamReady callback. The resulting
|
||||
@@ -74,7 +74,7 @@ NS_NewInputStreamReadyEvent(nsIInputStreamCallback **aEvent,
|
||||
extern NS_COM nsresult
|
||||
NS_NewOutputStreamReadyEvent(nsIOutputStreamCallback **aEvent,
|
||||
nsIOutputStreamCallback *aNotify,
|
||||
nsIEventTarget *aEventTarget);
|
||||
nsIDispatchTarget *aEventTarget);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
@@ -102,7 +102,7 @@ typedef void (* nsAsyncCopyCallbackFun)(void *closure, nsresult status);
|
||||
extern NS_COM nsresult
|
||||
NS_AsyncCopy(nsIInputStream *aSource,
|
||||
nsIOutputStream *aSink,
|
||||
nsIEventTarget *aEventTarget,
|
||||
nsIDispatchTarget *aEventTarget,
|
||||
nsAsyncCopyMode aMode = NS_ASYNCCOPY_VIA_READSEGMENTS,
|
||||
PRUint32 aChunkSize = 4096,
|
||||
nsAsyncCopyCallbackFun aCallbackFun = nsnull,
|
||||
|
||||
@@ -55,9 +55,9 @@ EXPORTS = \
|
||||
nsProxiedService.h \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = nsIProxyCreateInstance.idl \
|
||||
nsIProxyObjectManager.idl \
|
||||
$(NULL)
|
||||
XPIDLSRCS = \
|
||||
nsIProxyObjectManager.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
||||
@@ -36,23 +36,27 @@
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
interface nsIEventQueue;
|
||||
|
||||
interface nsIDispatchTarget;
|
||||
|
||||
/**
|
||||
* See http://www.mozilla.org/projects/xpcom/Proxies.html
|
||||
*/
|
||||
|
||||
[scriptable, uuid(eea90d43-b059-11d2-915e-c12b696c9333)]
|
||||
[scriptable, uuid(ee8ce1e3-0319-4bd9-8f70-7258b21c7733)]
|
||||
interface nsIProxyObjectManager : nsISupports
|
||||
{
|
||||
/**
|
||||
* Constants for proxyType
|
||||
*/
|
||||
|
||||
/**
|
||||
* Synchronous: Block until result available, like function call.
|
||||
*/
|
||||
const long INVOKE_SYNC = 0x0001;
|
||||
|
||||
/**
|
||||
* Asynchronous: Return without waiting for result.
|
||||
* (Warning: do not pass &pointers into stack when using this flag.)
|
||||
@@ -64,20 +68,11 @@ interface nsIProxyObjectManager : nsISupports
|
||||
*/
|
||||
const long FORCE_PROXY_CREATION = 0x0004;
|
||||
|
||||
|
||||
void getProxyForObject(in nsIEventQueue destQueue,
|
||||
void getProxyForObject(in nsIDispatchTarget target,
|
||||
in nsIIDRef iid,
|
||||
in nsISupports object,
|
||||
in PRInt32 proxyType,
|
||||
[iid_is(iid),retval] out nsQIResult result);
|
||||
|
||||
void getProxy(in nsIEventQueue destQueue,
|
||||
in nsIIDRef cid,
|
||||
in nsISupports aOuter,
|
||||
in nsIIDRef iid,
|
||||
in PRInt32 proxyType,
|
||||
[iid_is(iid),retval] out nsQIResult result);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -102,7 +97,7 @@ interface nsIProxyObjectManager : nsISupports
|
||||
* readable.
|
||||
*/
|
||||
extern NS_COM nsresult
|
||||
NS_GetProxyForObject(nsIEventQueue *destQueue,
|
||||
NS_GetProxyForObject(nsIDispatchTarget *target,
|
||||
REFNSIID aIID,
|
||||
nsISupports* aObj,
|
||||
PRInt32 proxyType,
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsProxiedService_h_
|
||||
#define nsProxiedService_h_
|
||||
#ifndef nsProxiedService_h__
|
||||
#define nsProxiedService_h__
|
||||
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIProxyObjectManager.h"
|
||||
@@ -57,10 +57,10 @@
|
||||
// if(NS_FAILED(rv))
|
||||
// return;
|
||||
// nsIMyService pIProxiedObject = NULL;
|
||||
// rv = pIProxyObjectManager->GetProxyForObject(pIProxyQueue,
|
||||
// NS_GET_IID(nsIMyService),
|
||||
// pIMyService, PROXY_SYNC,
|
||||
// (void**)&pIProxiedObject);
|
||||
// rv = pIProxyObjectManager->GetProxyForObject(pIDispatchTarget,
|
||||
// NS_GET_IID(nsIMyService),
|
||||
// pIMyService, PROXY_SYNC,
|
||||
// (void**)&pIProxiedObject);
|
||||
// pIProxiedObject->DoIt(...); // Executed on same thread as pIProxyQueue
|
||||
// ...
|
||||
// pIProxiedObject->Release(); // Must be done as not managed for you.
|
||||
@@ -69,7 +69,7 @@
|
||||
// {
|
||||
// nsresult rv;
|
||||
// NS_WITH_PROXIED_SERVICE(nsIMyService, pIMyService, kMyServiceCID,
|
||||
// pIProxyQueue, &rv);
|
||||
// pIDispatchTarget, &rv);
|
||||
// if(NS_FAILED(rv))
|
||||
// return;
|
||||
// pIMyService->DoIt(...); // Executed on the same thread as pIProxyQueue
|
||||
@@ -96,19 +96,19 @@ class nsProxiedService
|
||||
{
|
||||
public:
|
||||
nsProxiedService(const nsCID &aClass, const nsIID &aIID,
|
||||
nsIEventQueue* aEventQ, PRBool always, nsresult* rv)
|
||||
nsIDispatchTarget* aTarget, PRBool always, nsresult* rv)
|
||||
{
|
||||
nsCOMPtr<nsISupports> svc = do_GetService(aClass, rv);
|
||||
if (NS_SUCCEEDED(*rv))
|
||||
InitProxy(svc, aIID, aEventQ, always, rv);
|
||||
InitProxy(svc, aIID, aTarget, always, rv);
|
||||
}
|
||||
|
||||
nsProxiedService(const char* aContractID, const nsIID &aIID,
|
||||
nsIEventQueue* aEventQ, PRBool always, nsresult* rv)
|
||||
nsIDispatchTarget* aTarget, PRBool always, nsresult* rv)
|
||||
{
|
||||
nsCOMPtr<nsISupports> svc = do_GetService(aContractID, rv);
|
||||
if (NS_SUCCEEDED(*rv))
|
||||
InitProxy(svc, aIID, aEventQ, always, rv);
|
||||
InitProxy(svc, aIID, aTarget, always, rv);
|
||||
}
|
||||
|
||||
operator nsISupports*() const
|
||||
@@ -119,13 +119,13 @@ public:
|
||||
private:
|
||||
|
||||
void InitProxy(nsISupports *aObj, const nsIID &aIID,
|
||||
nsIEventQueue* aEventQ, PRBool always, nsresult*rv)
|
||||
nsIDispatchTarget* aTarget, PRBool always, nsresult*rv)
|
||||
{
|
||||
PRInt32 proxyType = PROXY_SYNC;
|
||||
if (always)
|
||||
proxyType |= PROXY_ALWAYS;
|
||||
|
||||
*rv = NS_GetProxyForObject(aEventQ,
|
||||
*rv = NS_GetProxyForObject(aTarget,
|
||||
aIID,
|
||||
aObj,
|
||||
proxyType,
|
||||
@@ -135,4 +135,4 @@ private:
|
||||
nsCOMPtr<nsISupports> mProxiedService;
|
||||
};
|
||||
|
||||
#endif // nsProxiedService_h_
|
||||
#endif // nsProxiedService_h__
|
||||
|
||||
@@ -35,23 +35,22 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef __nsProxyEvent_h_
|
||||
#define __nsProxyEvent_h_
|
||||
#ifndef nsProxyEvent_h__
|
||||
#define nsProxyEvent_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nscore.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsIFactory.h"
|
||||
#include "nsIDispatchTarget.h"
|
||||
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIEventQueue.h"
|
||||
#include "plevent.h"
|
||||
#include "prtypes.h"
|
||||
#include "xptcall.h"
|
||||
#include "xptinfo.h"
|
||||
|
||||
class nsProxyObjectCallInfo;
|
||||
class nsIRunnable;
|
||||
|
||||
#define PROXY_SYNC 0x0001 // acts just like a function call.
|
||||
#define PROXY_ASYNC 0x0002 // fire and forget. This will return immediately and you will lose all return information.
|
||||
@@ -85,15 +84,16 @@ class nsProxyObjectCallInfo;
|
||||
// change your interface, or contact me about this feature request.
|
||||
|
||||
|
||||
|
||||
|
||||
class nsProxyObject
|
||||
{
|
||||
public:
|
||||
nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, nsISupports *realObject,
|
||||
nsIEventQueueService* eventQService);
|
||||
nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, const nsCID &aClass,
|
||||
nsISupports *aDelegate, const nsIID &aIID, nsIEventQueueService* eventQService);
|
||||
nsProxyObject(nsIDispatchTarget *destQueue, PRInt32 proxyType,
|
||||
nsISupports *realObject);
|
||||
/* XXX
|
||||
nsProxyObject(nsIDispatchTarget *destQueue, PRInt32 proxyType,
|
||||
const nsCID &aClass, nsISupports *aDelegate,
|
||||
const nsIID &aIID);
|
||||
*/
|
||||
|
||||
void AddRef();
|
||||
void Release();
|
||||
@@ -107,7 +107,7 @@ public:
|
||||
|
||||
nsresult PostAndWait(nsProxyObjectCallInfo *proxyInfo);
|
||||
nsISupports* GetRealObject() const { return mRealObject; }
|
||||
nsIEventQueue* GetQueue() const { return mDestQueue; }
|
||||
nsIDispatchTarget* GetTarget() const { return mTarget; }
|
||||
PRInt32 GetProxyType() const { return mProxyType; }
|
||||
|
||||
friend class nsProxyEventObject;
|
||||
@@ -117,17 +117,15 @@ private:
|
||||
|
||||
PRInt32 mProxyType;
|
||||
|
||||
nsCOMPtr<nsIEventQueue> mDestQueue; /* destination queue */
|
||||
nsCOMPtr<nsIDispatchTarget> mTarget; /* dispatch target */
|
||||
|
||||
nsCOMPtr<nsISupports> mRealObject; /* the non-proxy object that this event is referring to.
|
||||
This is a strong ref. */
|
||||
nsCOMPtr<nsIEventQueueService> mEventQService;
|
||||
|
||||
nsresult convertMiniVariantToVariant(nsXPTMethodInfo * methodInfo,
|
||||
nsXPTCMiniVariant * params,
|
||||
nsXPTCVariant **fullParam,
|
||||
uint8 *paramCount);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -140,14 +138,14 @@ public:
|
||||
PRUint32 methodIndex,
|
||||
nsXPTCVariant* parameterList,
|
||||
PRUint32 parameterCount,
|
||||
PLEvent *event);
|
||||
nsIRunnable *event);
|
||||
|
||||
~nsProxyObjectCallInfo();
|
||||
|
||||
PRUint32 GetMethodIndex() const { return mMethodIndex; }
|
||||
nsXPTCVariant* GetParameterList() const { return mParameterList; }
|
||||
PRUint32 GetParameterCount() const { return mParameterCount; }
|
||||
PLEvent* GetPLEvent() const { return mEvent; }
|
||||
nsIRunnable* GetEvent() const { return mEvent; }
|
||||
nsresult GetResult() const { return mResult; }
|
||||
nsProxyObject* GetProxyObject() const { return mOwner; }
|
||||
|
||||
@@ -155,10 +153,10 @@ public:
|
||||
void SetCompleted();
|
||||
void PostCompleted();
|
||||
|
||||
void SetResult(nsresult rv) {mResult = rv; }
|
||||
void SetResult(nsresult rv) { mResult = rv; }
|
||||
|
||||
nsIEventQueue* GetCallersQueue();
|
||||
void SetCallersQueue(nsIEventQueue* queue);
|
||||
nsIDispatchTarget* GetCallersTarget();
|
||||
void SetCallersTarget(nsIDispatchTarget* target);
|
||||
|
||||
private:
|
||||
|
||||
@@ -167,19 +165,16 @@ private:
|
||||
PRUint32 mMethodIndex; /* which method to be called? */
|
||||
nsXPTCVariant *mParameterList; /* marshalled in parameter buffer */
|
||||
PRUint32 mParameterCount; /* number of params */
|
||||
PLEvent *mEvent; /* the current plevent */
|
||||
nsIRunnable *mEvent; /* the current runnable */
|
||||
PRInt32 mCompleted; /* is true when the method has been called. */
|
||||
|
||||
nsCOMPtr<nsIEventQueue> mCallersEventQ; /* this is the eventQ that we must post a message back to
|
||||
when we are done invoking the method (only PROXY_SYNC).
|
||||
*/
|
||||
nsCOMPtr<nsIDispatchTarget> mCallersTarget; /* this is the dispatch target that we must post a message back to
|
||||
when we are done invoking the method (only PROXY_SYNC). */
|
||||
|
||||
nsRefPtr<nsProxyObject> mOwner; /* this is the strong referenced nsProxyObject */
|
||||
|
||||
void RefCountInInterfacePointers(PRBool addRef);
|
||||
void CopyStrings(PRBool copy);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
#endif // nsProxyEvent_h__
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#ifndef nsProxyRelease_h_
|
||||
#define nsProxyRelease_h__
|
||||
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIDispatchTarget.h"
|
||||
#include "pratom.h"
|
||||
#include "prmem.h"
|
||||
|
||||
@@ -56,57 +56,6 @@
|
||||
* the release will happen when that PLEvent is handled.
|
||||
*/
|
||||
NS_COM nsresult NS_ProxyRelease
|
||||
(nsIEventTarget *target, nsISupports *doomed, PRBool alwaysProxy=PR_FALSE);
|
||||
(nsIDispatchTarget *target, nsISupports *doomed, PRBool alwaysProxy=PR_FALSE);
|
||||
|
||||
|
||||
#define NS_IMPL_PROXY_RELEASE(_class) \
|
||||
NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \
|
||||
{ \
|
||||
NS_PRECONDITION(0 != mRefCnt, "dup release"); \
|
||||
nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); \
|
||||
NS_LOG_RELEASE(this, count, #_class); \
|
||||
\
|
||||
if (count == 0) \
|
||||
{ \
|
||||
mRefCnt = 1; /* stabilize */ \
|
||||
PRBool callDirectly = PR_TRUE; \
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); \
|
||||
nsCOMPtr<nsIEventQueueService> eventQService \
|
||||
= do_GetService(kEventQueueServiceCID); \
|
||||
NS_ASSERTION(eventQService, "event queue service is unavailable"); \
|
||||
\
|
||||
nsCOMPtr<nsIEventQueue> eventQ; \
|
||||
if (eventQService) { \
|
||||
eventQService->GetThreadEventQueue(NS_UI_THREAD, getter_AddRefs(eventQ)); \
|
||||
if (eventQ) \
|
||||
eventQ->IsOnCurrentThread(&callDirectly); \
|
||||
} \
|
||||
\
|
||||
if (callDirectly) \
|
||||
{ \
|
||||
NS_RELEASE(this); \
|
||||
return 0; \
|
||||
} \
|
||||
PLEvent *event = new PLEvent; \
|
||||
if (event == nsnull) \
|
||||
{ \
|
||||
NS_ASSERTION(0, "Could not create a plevent. Deleting on wrong thread!"); \
|
||||
NS_DELETEXPCOM(this); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
PL_InitEvent(event, \
|
||||
NS_STATIC_CAST(nsISupports*, this), \
|
||||
ReleaseDestructorEventHandler, \
|
||||
ReleaseDestructorDestroyHandler); \
|
||||
\
|
||||
eventQ->PostEvent(event); \
|
||||
return 0; \
|
||||
} \
|
||||
return count; \
|
||||
} \
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim:set ts=4 sw=4 sts=4 ci et: */
|
||||
/*
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
@@ -51,6 +53,7 @@
|
||||
#include "nsProxyEvent.h"
|
||||
#include "nsProxyEventPrivate.h"
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "nsRunnable.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
#include "pratom.h"
|
||||
@@ -59,8 +62,7 @@
|
||||
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsMemory.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsThreadManager.h"
|
||||
|
||||
#include "nsIAtom.h" //hack! Need a way to define a component as threadsafe (ie. sta).
|
||||
|
||||
@@ -72,19 +74,108 @@
|
||||
#define nsAUTF8String nsACString
|
||||
#define nsUTF8String nsCString
|
||||
|
||||
/*
|
||||
static void* PR_CALLBACK EventHandler(PLEvent *self);
|
||||
static void PR_CALLBACK DestroyHandler(PLEvent *self);
|
||||
static void* PR_CALLBACK CompletedEventHandler(PLEvent *self);
|
||||
static void PR_CALLBACK CompletedDestroyHandler(PLEvent *self) ;
|
||||
static void* PR_CALLBACK ProxyDestructorEventHandler(PLEvent *self);
|
||||
static void PR_CALLBACK ProxyDestructorDestroyHandler(PLEvent *self) ;
|
||||
*/
|
||||
|
||||
nsProxyObjectCallInfo::nsProxyObjectCallInfo( nsProxyObject* owner,
|
||||
nsXPTMethodInfo *methodInfo,
|
||||
PRUint32 methodIndex,
|
||||
nsXPTCVariant* parameterList,
|
||||
PRUint32 parameterCount,
|
||||
PLEvent *event)
|
||||
class nsProxyCallEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsProxyCallEvent()
|
||||
: mInfo(nsnull)
|
||||
{}
|
||||
|
||||
void SetInfo(nsProxyObjectCallInfo *info)
|
||||
{
|
||||
mInfo = info;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
Invoke();
|
||||
|
||||
nsProxyObject *proxyObject = mInfo->GetProxyObject();
|
||||
if (proxyObject == nsnull)
|
||||
return NS_OK;
|
||||
|
||||
if (proxyObject->GetProxyType() & PROXY_ASYNC)
|
||||
{
|
||||
delete mInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
mInfo->PostCompleted();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Invoke()
|
||||
{
|
||||
nsProxyObject *proxyObject = mInfo->GetProxyObject();
|
||||
if (proxyObject)
|
||||
{
|
||||
// invoke the magic of xptc...
|
||||
nsresult rv = XPTC_InvokeByIndex(proxyObject->GetRealObject(),
|
||||
mInfo->GetMethodIndex(),
|
||||
mInfo->GetParameterCount(),
|
||||
mInfo->GetParameterList());
|
||||
mInfo->SetResult(rv);
|
||||
}
|
||||
else
|
||||
{
|
||||
mInfo->SetResult(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsProxyObjectCallInfo *mInfo;
|
||||
};
|
||||
|
||||
class nsProxyCallCompletedEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsProxyCallCompletedEvent(nsProxyObjectCallInfo *info)
|
||||
: mInfo(info)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mInfo->SetCompleted();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsProxyObjectCallInfo *mInfo;
|
||||
};
|
||||
|
||||
class nsProxyDestructorEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsProxyDestructorEvent(nsProxyObject *doomed)
|
||||
: mDoomed(doomed)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
delete mDoomed;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsProxyObject *mDoomed;
|
||||
};
|
||||
|
||||
nsProxyObjectCallInfo::nsProxyObjectCallInfo(nsProxyObject* owner,
|
||||
nsXPTMethodInfo *methodInfo,
|
||||
PRUint32 methodIndex,
|
||||
nsXPTCVariant* parameterList,
|
||||
PRUint32 parameterCount,
|
||||
nsIRunnable *event)
|
||||
{
|
||||
NS_ASSERTION(owner, "No nsProxyObject!");
|
||||
NS_ASSERTION(methodInfo, "No nsXPTMethodInfo!");
|
||||
@@ -94,9 +185,9 @@ nsProxyObjectCallInfo::nsProxyObjectCallInfo( nsProxyObject* owner,
|
||||
mMethodIndex = methodIndex;
|
||||
mParameterList = parameterList;
|
||||
mParameterCount = parameterCount;
|
||||
mEvent = event;
|
||||
mEvent = event; // XXX strong or weak ref?
|
||||
mMethodInfo = methodInfo;
|
||||
mCallersEventQ = nsnull;
|
||||
mCallersTarget = nsnull;
|
||||
|
||||
mOwner = owner;
|
||||
|
||||
@@ -117,7 +208,7 @@ nsProxyObjectCallInfo::~nsProxyObjectCallInfo()
|
||||
PR_FREEIF(mEvent);
|
||||
|
||||
if (mParameterList)
|
||||
free( (void*) mParameterList);
|
||||
free((void*) mParameterList);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -137,7 +228,7 @@ nsProxyObjectCallInfo::RefCountInInterfacePointers(PRBool addRef)
|
||||
|
||||
if (anInterface)
|
||||
{
|
||||
if(addRef)
|
||||
if (addRef)
|
||||
anInterface->AddRef();
|
||||
else
|
||||
anInterface->Release();
|
||||
@@ -155,7 +246,7 @@ nsProxyObjectCallInfo::CopyStrings(PRBool copy)
|
||||
{
|
||||
const nsXPTParamInfo paramInfo = mMethodInfo->GetParam(i);
|
||||
|
||||
if(paramInfo.IsIn())
|
||||
if (paramInfo.IsIn())
|
||||
{
|
||||
const nsXPTType& type = paramInfo.GetType();
|
||||
uint8 type_tag = type.TagPart();
|
||||
@@ -236,53 +327,46 @@ nsProxyObjectCallInfo::SetCompleted()
|
||||
void
|
||||
nsProxyObjectCallInfo::PostCompleted()
|
||||
{
|
||||
if (mCallersEventQ)
|
||||
if (mCallersTarget)
|
||||
{
|
||||
PLEvent *event = PR_NEW(PLEvent);
|
||||
|
||||
PL_InitEvent(event,
|
||||
this,
|
||||
CompletedEventHandler,
|
||||
CompletedDestroyHandler);
|
||||
|
||||
mCallersEventQ->PostSynchronousEvent(event, nsnull);
|
||||
PR_FREEIF(event);
|
||||
nsCOMPtr<nsIRunnable> event = new nsProxyCallCompletedEvent(this);
|
||||
// XXX check for out-of-memory!
|
||||
// XXX dispatch sync will spin the current thread's event queue, which
|
||||
// may not be what we want!
|
||||
mCallersTarget->Dispatch(event, NS_DISPATCH_SYNC);
|
||||
}
|
||||
else
|
||||
{
|
||||
// caller does not have an eventQ? This is an error!
|
||||
// caller does not have a target? This is an error!
|
||||
SetCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
nsIEventQueue*
|
||||
nsProxyObjectCallInfo::GetCallersQueue()
|
||||
nsIDispatchTarget*
|
||||
nsProxyObjectCallInfo::GetCallersTarget()
|
||||
{
|
||||
return mCallersEventQ;
|
||||
}
|
||||
return mCallersTarget;
|
||||
}
|
||||
|
||||
void
|
||||
nsProxyObjectCallInfo::SetCallersQueue(nsIEventQueue* queue)
|
||||
nsProxyObjectCallInfo::SetCallersTarget(nsIDispatchTarget* target)
|
||||
{
|
||||
mCallersEventQ = queue;
|
||||
mCallersTarget = target;
|
||||
}
|
||||
|
||||
|
||||
nsProxyObject::nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, nsISupports *realObject,
|
||||
nsIEventQueueService* eventQService)
|
||||
nsProxyObject::nsProxyObject(nsIDispatchTarget *target, PRInt32 proxyType,
|
||||
nsISupports *realObject)
|
||||
{
|
||||
mEventQService = eventQService;
|
||||
|
||||
mRealObject = realObject;
|
||||
mDestQueue = do_QueryInterface(destQueue);
|
||||
mTarget = target;
|
||||
mProxyType = proxyType;
|
||||
}
|
||||
|
||||
|
||||
nsProxyObject::nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, const nsCID &aClass,
|
||||
nsISupports *aDelegate, const nsIID &aIID, nsIEventQueueService* eventQService)
|
||||
#if 0
|
||||
nsProxyObject::nsProxyObject(nsIDispatchTarget *target, PRInt32 proxyType,
|
||||
const nsCID &aClass, nsISupports *aDelegate,
|
||||
const nsIID &aIID)
|
||||
{
|
||||
mEventQService = eventQService;
|
||||
|
||||
nsCOMPtr<nsIComponentManager> compMgr;
|
||||
NS_GetComponentManager(getter_AddRefs(compMgr));
|
||||
compMgr->CreateInstance(aClass,
|
||||
@@ -290,9 +374,10 @@ nsProxyObject::nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, const
|
||||
aIID,
|
||||
getter_AddRefs(mRealObject));
|
||||
|
||||
mDestQueue = do_QueryInterface(destQueue);
|
||||
mTarget = do_QueryInterface(destQueue);
|
||||
mProxyType = proxyType;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsProxyObject::~nsProxyObject()
|
||||
{
|
||||
@@ -300,7 +385,7 @@ nsProxyObject::~nsProxyObject()
|
||||
// do not remove assignments.
|
||||
|
||||
mRealObject = 0;
|
||||
mDestQueue = 0;
|
||||
mTarget = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -314,91 +399,108 @@ nsProxyObject::AddRef()
|
||||
void
|
||||
nsProxyObject::Release(void)
|
||||
{
|
||||
NS_PRECONDITION(0 != mRefCnt, "dup release");
|
||||
NS_PRECONDITION(0 != mRefCnt, "dup release");
|
||||
|
||||
nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mRefCnt);
|
||||
NS_LOG_RELEASE(this, count, "nsProxyObject");
|
||||
nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mRefCnt);
|
||||
NS_LOG_RELEASE(this, count, "nsProxyObject");
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
mRefCnt = 1; /* stabilize */
|
||||
if (count == 0)
|
||||
{
|
||||
mRefCnt = 1; /* stabilize */
|
||||
|
||||
PRBool callDirectly;
|
||||
mDestQueue->IsOnCurrentThread(&callDirectly);
|
||||
PRBool callDirectly;
|
||||
mTarget->IsOnCurrentThread(&callDirectly);
|
||||
|
||||
if (callDirectly)
|
||||
{
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
if (callDirectly)
|
||||
{
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
// need to do something special here so that
|
||||
// the real object will always be deleted on
|
||||
// the correct thread..
|
||||
// need to do something special here so that
|
||||
// the real object will always be deleted on
|
||||
// the correct thread..
|
||||
|
||||
PLEvent *event = PR_NEW(PLEvent);
|
||||
if (event == nsnull)
|
||||
{
|
||||
NS_ASSERTION(0, "Could not create a plevent. Leaking nsProxyObject!");
|
||||
return; // if this happens we are going to leak.
|
||||
}
|
||||
|
||||
PL_InitEvent(event,
|
||||
this,
|
||||
ProxyDestructorEventHandler,
|
||||
ProxyDestructorDestroyHandler);
|
||||
/*
|
||||
PLEvent *event = PR_NEW(PLEvent);
|
||||
if (event == nsnull)
|
||||
{
|
||||
NS_ASSERTION(0, "Could not create a plevent. Leaking nsProxyObject!");
|
||||
return; // if this happens we are going to leak.
|
||||
}
|
||||
|
||||
mDestQueue->PostEvent(event);
|
||||
}
|
||||
}
|
||||
PL_InitEvent(event,
|
||||
this,
|
||||
ProxyDestructorEventHandler,
|
||||
ProxyDestructorDestroyHandler);
|
||||
*/
|
||||
|
||||
nsCOMPtr<nsIRunnable> event = new nsProxyDestructorEvent(this);
|
||||
if (event == nsnull)
|
||||
{
|
||||
NS_NOTREACHED("Leaking nsProxyObject!");
|
||||
return; // if this happens we are going to leak.
|
||||
}
|
||||
|
||||
mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsProxyObject::PostAndWait(nsProxyObjectCallInfo *proxyInfo)
|
||||
{
|
||||
if (proxyInfo == nsnull || mEventQService == nsnull)
|
||||
if (proxyInfo == nsnull)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
PRBool eventLoopCreated = PR_FALSE;
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIEventQueue> eventQ;
|
||||
rv = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(eventQ));
|
||||
if (NS_FAILED(rv))
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsThreadManager::get()->GetCurrentThread(getter_AddRefs(thread));
|
||||
if (!thread)
|
||||
{
|
||||
rv = mEventQService->CreateMonitoredThreadEventQueue();
|
||||
eventLoopCreated = PR_TRUE;
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
// XXX create a nsIThread wrapper for this thread.
|
||||
|
||||
/*
|
||||
static int sWrapperCount = 0;
|
||||
nsCString name;
|
||||
name.AssignLiteral("xpcom.proxy-");
|
||||
name.AppendInt(sDummyCount++);
|
||||
|
||||
nsThread *dummy = new nsThread(name);
|
||||
if (!dummy)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
dummy->InitCurrentThread();
|
||||
|
||||
rv = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(eventQ));
|
||||
thread = dummy;
|
||||
*/
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
proxyInfo->SetCallersQueue(eventQ);
|
||||
proxyInfo->SetCallersTarget(thread);
|
||||
|
||||
PLEvent* event = proxyInfo->GetPLEvent();
|
||||
nsIRunnable* event = proxyInfo->GetEvent();
|
||||
if (!event)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
mDestQueue->PostEvent(event);
|
||||
mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
|
||||
while (! proxyInfo->GetCompleted())
|
||||
while (!proxyInfo->GetCompleted())
|
||||
{
|
||||
PLEvent *nextEvent;
|
||||
rv = eventQ->WaitForEvent(&nextEvent);
|
||||
rv = thread->RunNextTask(nsIThread::RUN_NORMAL);
|
||||
if (NS_FAILED(rv)) break;
|
||||
|
||||
eventQ->HandleEvent(nextEvent);
|
||||
}
|
||||
|
||||
/*
|
||||
if (eventLoopCreated)
|
||||
{
|
||||
mEventQService->DestroyThreadEventQueue();
|
||||
eventQ = 0;
|
||||
}
|
||||
*/
|
||||
|
||||
return rv;
|
||||
}
|
||||
@@ -444,7 +546,7 @@ nsProxyObject::Post( PRUint32 methodIndex,
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (! mDestQueue || ! mRealObject)
|
||||
if (! mTarget || ! mRealObject)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (methodInfo->IsNotXPCOM())
|
||||
@@ -461,10 +563,10 @@ nsProxyObject::Post( PRUint32 methodIndex,
|
||||
|
||||
// see if we should call into the method directly. Either it is a QI function call
|
||||
// (methodIndex == 0), or it is a sync proxy and this code is running on the same thread
|
||||
// as the destination event queue.
|
||||
// as the destination dispatch target.
|
||||
if ( (methodIndex == 0) ||
|
||||
(mProxyType & PROXY_SYNC &&
|
||||
NS_SUCCEEDED(mDestQueue->IsOnCurrentThread(&callDirectly)) &&
|
||||
NS_SUCCEEDED(mTarget->IsOnCurrentThread(&callDirectly)) &&
|
||||
callDirectly))
|
||||
{
|
||||
|
||||
@@ -479,6 +581,7 @@ nsProxyObject::Post( PRUint32 methodIndex,
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
PLEvent *event = PR_NEW(PLEvent);
|
||||
|
||||
if (event == nsnull) {
|
||||
@@ -486,26 +589,30 @@ nsProxyObject::Post( PRUint32 methodIndex,
|
||||
free(fullParam);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsProxyObjectCallInfo *proxyInfo = new nsProxyObjectCallInfo(this,
|
||||
methodInfo,
|
||||
methodIndex,
|
||||
fullParam, // will be deleted by ~()
|
||||
paramCount,
|
||||
event); // will be deleted by ~()
|
||||
*/
|
||||
nsRefPtr<nsProxyCallEvent> event = new nsProxyCallEvent();
|
||||
if (!event) {
|
||||
if (fullParam)
|
||||
free(fullParam);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (proxyInfo == nsnull) {
|
||||
PR_DELETE(event);
|
||||
nsProxyObjectCallInfo *proxyInfo =
|
||||
new nsProxyObjectCallInfo(this,
|
||||
methodInfo,
|
||||
methodIndex,
|
||||
fullParam, // will be deleted by ~()
|
||||
paramCount,
|
||||
event); // will be deleted by ~()
|
||||
|
||||
if (!proxyInfo) {
|
||||
if (fullParam)
|
||||
free(fullParam);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
PL_InitEvent(event,
|
||||
proxyInfo,
|
||||
EventHandler,
|
||||
DestroyHandler);
|
||||
|
||||
event->SetInfo(proxyInfo);
|
||||
|
||||
if (mProxyType & PROXY_SYNC)
|
||||
{
|
||||
rv = PostAndWait(proxyInfo);
|
||||
@@ -518,76 +625,8 @@ nsProxyObject::Post( PRUint32 methodIndex,
|
||||
|
||||
if (mProxyType & PROXY_ASYNC)
|
||||
{
|
||||
mDestQueue->PostEvent(event);
|
||||
mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void DestroyHandler(PLEvent *self)
|
||||
{
|
||||
nsProxyObjectCallInfo* owner = (nsProxyObjectCallInfo*)PL_GetEventOwner(self);
|
||||
nsProxyObject* proxyObject = owner->GetProxyObject();
|
||||
|
||||
if (proxyObject == nsnull)
|
||||
return;
|
||||
|
||||
if (proxyObject->GetProxyType() & PROXY_ASYNC)
|
||||
{
|
||||
delete owner;
|
||||
}
|
||||
else
|
||||
{
|
||||
owner->PostCompleted();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void* EventHandler(PLEvent *self)
|
||||
{
|
||||
nsProxyObjectCallInfo *info = (nsProxyObjectCallInfo*)PL_GetEventOwner(self);
|
||||
NS_ASSERTION(info, "No nsProxyObjectCallInfo!");
|
||||
|
||||
nsProxyObject *proxyObject = info->GetProxyObject();
|
||||
|
||||
if (proxyObject)
|
||||
{
|
||||
// invoke the magic of xptc...
|
||||
nsresult rv = XPTC_InvokeByIndex( proxyObject->GetRealObject(),
|
||||
info->GetMethodIndex(),
|
||||
info->GetParameterCount(),
|
||||
info->GetParameterList());
|
||||
info->SetResult(rv);
|
||||
}
|
||||
else
|
||||
{
|
||||
info->SetResult(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void CompletedDestroyHandler(PLEvent *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void* CompletedEventHandler(PLEvent *self)
|
||||
{
|
||||
nsProxyObjectCallInfo* owner = (nsProxyObjectCallInfo*)PL_GetEventOwner(self);
|
||||
owner->SetCompleted();
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
static void* ProxyDestructorEventHandler(PLEvent *self)
|
||||
{
|
||||
nsProxyObject* owner = (nsProxyObject*) PL_GetEventOwner(self);
|
||||
NS_DELETEXPCOM(owner);
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
static void ProxyDestructorDestroyHandler(PLEvent *self)
|
||||
{
|
||||
PR_DELETE(self);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim:set ts=4 sw=4 sts=4 ci et: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@@ -76,12 +77,13 @@ nsProxyEventClass::GetNewOrUsedClass(REFNSIID aIID)
|
||||
/* find in our hash table */
|
||||
|
||||
nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance();
|
||||
if (manager == nsnull) return nsnull;
|
||||
if (manager == nsnull)
|
||||
return nsnull;
|
||||
|
||||
// don't need to lock the map, because this is only called
|
||||
// by nsProxyEventClass::GetNewOrUsed which locks it for us.
|
||||
// don't need to lock the map, because this is only called by
|
||||
// nsProxyEventClass::GetNewOrUsed which locks it for us.
|
||||
|
||||
nsHashtable *iidToClassMap = manager->GetIIDToProxyClassMap();
|
||||
nsHashtable *iidToClassMap = manager->GetIIDToProxyClassMap();
|
||||
|
||||
if (iidToClassMap == nsnull)
|
||||
{
|
||||
@@ -94,7 +96,7 @@ nsProxyEventClass::GetNewOrUsedClass(REFNSIID aIID)
|
||||
#ifdef PROXYEVENTCLASS_DEBUG
|
||||
char* iidStr = aIID.ToString();
|
||||
printf("GetNewOrUsedClass %s\n", iidStr);
|
||||
nsCRT::free(iidStr);
|
||||
PR_Free(iidStr);
|
||||
#endif
|
||||
|
||||
clazz = (nsProxyEventClass*) iidToClassMap->Get(&key);
|
||||
@@ -104,7 +106,7 @@ nsProxyEventClass::GetNewOrUsedClass(REFNSIID aIID)
|
||||
#ifdef PROXYEVENTCLASS_DEBUG
|
||||
char* iidStr = aIID.ToString();
|
||||
printf("GetNewOrUsedClass %s hit\n", iidStr);
|
||||
nsCRT::free(iidStr);
|
||||
PR_Free(iidStr);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@@ -142,7 +144,7 @@ nsProxyEventClass::GetNewOrUsedClass(REFNSIID aIID)
|
||||
if (isISupportsDescendent)
|
||||
{
|
||||
clazz = new nsProxyEventClass(aIID, info);
|
||||
if(!clazz->mDescriptors)
|
||||
if (!clazz->mDescriptors)
|
||||
NS_RELEASE(clazz); // sets clazz to NULL
|
||||
}
|
||||
}
|
||||
@@ -153,12 +155,12 @@ nsProxyEventClass::GetNewOrUsedClass(REFNSIID aIID)
|
||||
|
||||
nsProxyEventClass::nsProxyEventClass()
|
||||
{
|
||||
NS_WARNING("This constructor should never be called");
|
||||
NS_NOTREACHED("This constructor should never be called");
|
||||
}
|
||||
|
||||
nsProxyEventClass::nsProxyEventClass(REFNSIID aIID, nsIInterfaceInfo* aInfo)
|
||||
: mIID(aIID),
|
||||
mDescriptors(NULL)
|
||||
: mIID(aIID),
|
||||
mDescriptors(NULL)
|
||||
{
|
||||
NS_ADDREF_THIS();
|
||||
|
||||
@@ -168,7 +170,8 @@ nsProxyEventClass::nsProxyEventClass(REFNSIID aIID, nsIInterfaceInfo* aInfo)
|
||||
nsIDKey key(aIID);
|
||||
|
||||
nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance();
|
||||
if (manager == nsnull) return;
|
||||
if (manager == nsnull)
|
||||
return;
|
||||
// don't need to lock the map, because this is only called
|
||||
// by GetNewOrUsed which locks it for us.
|
||||
|
||||
@@ -184,7 +187,7 @@ nsProxyEventClass::nsProxyEventClass(REFNSIID aIID, nsIInterfaceInfo* aInfo)
|
||||
#ifdef PROXYEVENTCLASS_DEBUG
|
||||
char* iidStr = aIID.ToString();
|
||||
printf("GetNewOrUsedClass %s put\n", iidStr);
|
||||
nsCRT::free(iidStr);
|
||||
PR_Free(iidStr);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -208,7 +211,7 @@ nsProxyEventClass::nsProxyEventClass(REFNSIID aIID, nsIInterfaceInfo* aInfo)
|
||||
|
||||
nsProxyEventClass::~nsProxyEventClass()
|
||||
{
|
||||
if(mDescriptors && mDescriptors != &zero_methods_descriptor)
|
||||
if (mDescriptors && mDescriptors != &zero_methods_descriptor)
|
||||
delete [] mDescriptors;
|
||||
|
||||
if (nsProxyObjectManager::IsManagerShutdown())
|
||||
@@ -227,7 +230,7 @@ nsProxyEventClass::~nsProxyEventClass()
|
||||
#ifdef PROXYEVENTCLASS_DEBUG
|
||||
char* iidStr = mIID.ToString();
|
||||
printf("GetNewOrUsedClass %s remove\n", iidStr);
|
||||
nsCRT::free(iidStr);
|
||||
PR_Free(iidStr);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -242,7 +245,6 @@ nsProxyEventClass::CallQueryInterfaceOnProxy(nsProxyEventObject* self, REFNSIID
|
||||
|
||||
*aInstancePtr = nsnull; // in case of error.
|
||||
|
||||
|
||||
// The functions we will call: QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||
|
||||
nsXPTCMiniVariant var[2];
|
||||
@@ -278,7 +280,7 @@ nsProxyEventClass::CallQueryInterfaceOnProxy(nsProxyEventObject* self, REFNSIID
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = manager->GetProxyForObject(self->GetQueue(),
|
||||
rv = manager->GetProxyForObject(self->GetTarget(),
|
||||
aIID,
|
||||
self->GetRealObject(),
|
||||
self->GetProxyType(),
|
||||
@@ -311,7 +313,7 @@ public:
|
||||
static ProxyEventClassIdentity* singleton = NULL;
|
||||
if(!singleton)
|
||||
singleton = new ProxyEventClassIdentity();
|
||||
return (void*) singleton;
|
||||
return singleton;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -333,41 +335,41 @@ nsProxyEventClass::DelegatedQueryInterface(nsProxyEventObject* self,
|
||||
|
||||
nsProxyEventObject* sibling;
|
||||
{
|
||||
nsProxyObjectManager* manager = nsProxyObjectManager::GetInstance();
|
||||
nsAutoMonitor mon(manager->GetMonitor());
|
||||
nsProxyObjectManager* manager = nsProxyObjectManager::GetInstance();
|
||||
nsAutoMonitor mon(manager->GetMonitor());
|
||||
|
||||
// This includes checking for nsISupports and the iid of self.
|
||||
// And it also checks for other wrappers that have been constructed
|
||||
// for this object.
|
||||
if(nsnull != (sibling = self->LockedFind(aIID)))
|
||||
{
|
||||
NS_ADDREF(sibling);
|
||||
*aInstancePtr = (void*) sibling;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// check if asking for an interface that we inherit from
|
||||
nsCOMPtr<nsIInterfaceInfo> current = GetInterfaceInfo();
|
||||
nsCOMPtr<nsIInterfaceInfo> parent;
|
||||
|
||||
while(NS_SUCCEEDED(current->GetParent(getter_AddRefs(parent))) && parent)
|
||||
{
|
||||
current = parent;
|
||||
|
||||
nsIID* iid;
|
||||
if(NS_SUCCEEDED(current->GetInterfaceIID(&iid)) && iid)
|
||||
// This includes checking for nsISupports and the iid of self.
|
||||
// And it also checks for other wrappers that have been constructed
|
||||
// for this object.
|
||||
if (nsnull != (sibling = self->LockedFind(aIID)))
|
||||
{
|
||||
PRBool found = aIID.Equals(*iid);
|
||||
nsMemory::Free(iid);
|
||||
if(found)
|
||||
NS_ADDREF(sibling);
|
||||
*aInstancePtr = (void*) sibling;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// check if asking for an interface that we inherit from
|
||||
nsCOMPtr<nsIInterfaceInfo> current = GetInterfaceInfo();
|
||||
nsCOMPtr<nsIInterfaceInfo> parent;
|
||||
|
||||
while (NS_SUCCEEDED(current->GetParent(getter_AddRefs(parent))) && parent)
|
||||
{
|
||||
current = parent;
|
||||
|
||||
nsIID* iid;
|
||||
if (NS_SUCCEEDED(current->GetInterfaceIID(&iid)) && iid)
|
||||
{
|
||||
*aInstancePtr = (void*) self;
|
||||
NS_ADDREF(self);
|
||||
return NS_OK;
|
||||
PRBool found = aIID.Equals(*iid);
|
||||
nsMemory::Free(iid);
|
||||
if (found)
|
||||
{
|
||||
*aInstancePtr = (void*) self;
|
||||
NS_ADDREF(self);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CallQueryInterfaceOnProxy(self, aIID, (nsProxyEventObject**)aInstancePtr);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "nsProxyEventPrivate.h"
|
||||
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
#include "nsHashtable.h"
|
||||
@@ -55,36 +54,35 @@
|
||||
#include "nsAutoLock.h"
|
||||
|
||||
static NS_DEFINE_IID(kProxyObject_Identity_Class_IID, NS_PROXYEVENT_IDENTITY_CLASS_IID);
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsProxyEventKey : public nsHashKey
|
||||
{
|
||||
public:
|
||||
nsProxyEventKey(void* rootObjectKey, void* destQueueKey, PRInt32 proxyType)
|
||||
: mRootObjectKey(rootObjectKey), mDestQueueKey(destQueueKey), mProxyType(proxyType) {
|
||||
nsProxyEventKey(void* rootObjectKey, void* targetKey, PRInt32 proxyType)
|
||||
: mRootObjectKey(rootObjectKey), mTargetKey(targetKey), mProxyType(proxyType) {
|
||||
}
|
||||
|
||||
PRUint32 HashCode(void) const {
|
||||
return NS_PTR_TO_INT32(mRootObjectKey) ^
|
||||
NS_PTR_TO_INT32(mDestQueueKey) ^ mProxyType;
|
||||
NS_PTR_TO_INT32(mTargetKey) ^ mProxyType;
|
||||
}
|
||||
|
||||
PRBool Equals(const nsHashKey *aKey) const {
|
||||
const nsProxyEventKey* other = (const nsProxyEventKey*)aKey;
|
||||
return mRootObjectKey == other->mRootObjectKey
|
||||
&& mDestQueueKey == other->mDestQueueKey
|
||||
&& mTargetKey == other->mTargetKey
|
||||
&& mProxyType == other->mProxyType;
|
||||
}
|
||||
|
||||
nsHashKey *Clone() const {
|
||||
return new nsProxyEventKey(mRootObjectKey, mDestQueueKey, mProxyType);
|
||||
return new nsProxyEventKey(mRootObjectKey, mTargetKey, mProxyType);
|
||||
}
|
||||
|
||||
protected:
|
||||
void* mRootObjectKey;
|
||||
void* mDestQueueKey;
|
||||
void* mTargetKey;
|
||||
PRInt32 mProxyType;
|
||||
};
|
||||
|
||||
@@ -127,7 +125,7 @@ nsProxyEventObject::DebugDump(const char * message, PRUint32 hashKey)
|
||||
printf("%s wrapper around @ %x\n", isRoot ? "ROOT":"non-root\n", GetRealObject());
|
||||
|
||||
nsCOMPtr<nsISupports> rootObject = do_QueryInterface(mProxyObject->mRealObject);
|
||||
nsCOMPtr<nsISupports> rootQueue = do_QueryInterface(mProxyObject->mDestQueue);
|
||||
nsCOMPtr<nsISupports> rootQueue = do_QueryInterface(mProxyObject->mTarget);
|
||||
nsProxyEventKey key(rootObject, rootQueue, mProxyObject->mProxyType);
|
||||
printf("Hashkey: %d\n", key.HashCode());
|
||||
|
||||
@@ -167,7 +165,7 @@ nsProxyEventObject::DebugDump(const char * message, PRUint32 hashKey)
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
nsProxyEventObject*
|
||||
nsProxyEventObject::GetNewOrUsedProxy(nsIEventQueue *destQueue,
|
||||
nsProxyEventObject::GetNewOrUsedProxy(nsIDispatchTarget *target,
|
||||
PRInt32 proxyType,
|
||||
nsISupports *aObj,
|
||||
REFNSIID aIID)
|
||||
@@ -199,7 +197,7 @@ nsProxyEventObject::GetNewOrUsedProxy(nsIEventQueue *destQueue,
|
||||
// if you hit this assertion, you might want to check out how
|
||||
// you are using proxies. You shouldn't need to be creating
|
||||
// a proxy from a proxy. -- dougt@netscape.com
|
||||
NS_ASSERTION(0, "Someone is building a proxy from a proxy");
|
||||
NS_WARNING("Someone is building a proxy from a proxy");
|
||||
|
||||
NS_ASSERTION(identificationObject, "where did my identification object go!");
|
||||
if (!identificationObject) {
|
||||
@@ -229,7 +227,7 @@ nsProxyEventObject::GetNewOrUsedProxy(nsIEventQueue *destQueue,
|
||||
|
||||
// Get the root nsISupports of the event queue... This is used later,
|
||||
// as part of the hashtable key...
|
||||
nsCOMPtr<nsISupports> destQRoot = do_QueryInterface(destQueue, &rv);
|
||||
nsCOMPtr<nsISupports> destQRoot = do_QueryInterface(target, &rv);
|
||||
if (NS_FAILED(rv) || !destQRoot) {
|
||||
return nsnull;
|
||||
}
|
||||
@@ -247,10 +245,6 @@ nsProxyEventObject::GetNewOrUsedProxy(nsIEventQueue *destQueue,
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEventQueueService> eventQService(do_GetService(kEventQueueServiceCID, &rv));
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
nsAutoMonitor mon(manager->GetMonitor());
|
||||
|
||||
// Get the hash table containing root proxy objects...
|
||||
@@ -299,12 +293,11 @@ nsProxyEventObject::GetNewOrUsedProxy(nsIEventQueue *destQueue,
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
peo = new nsProxyEventObject(destQueue,
|
||||
peo = new nsProxyEventObject(target,
|
||||
proxyType,
|
||||
rootObject,
|
||||
rootClazz,
|
||||
nsnull,
|
||||
eventQService);
|
||||
nsnull);
|
||||
if(!peo) {
|
||||
// Ouch... Out of memory!
|
||||
return nsnull;
|
||||
@@ -352,12 +345,11 @@ nsProxyEventObject::GetNewOrUsedProxy(nsIEventQueue *destQueue,
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
peo = new nsProxyEventObject(destQueue,
|
||||
peo = new nsProxyEventObject(target,
|
||||
proxyType,
|
||||
rawInterface,
|
||||
proxyClazz,
|
||||
rootProxy,
|
||||
eventQService);
|
||||
rootProxy);
|
||||
if (!peo) {
|
||||
// Ouch... Out of memory!
|
||||
return nsnull;
|
||||
@@ -402,19 +394,18 @@ nsProxyEventObject::nsProxyEventObject()
|
||||
NS_WARNING("This constructor should never be called");
|
||||
}
|
||||
|
||||
nsProxyEventObject::nsProxyEventObject(nsIEventQueue *destQueue,
|
||||
nsProxyEventObject::nsProxyEventObject(nsIDispatchTarget *target,
|
||||
PRInt32 proxyType,
|
||||
nsISupports* aObj,
|
||||
nsProxyEventClass* aClass,
|
||||
nsProxyEventObject* root,
|
||||
nsIEventQueueService* eventQService)
|
||||
nsProxyEventObject* root)
|
||||
: mClass(aClass),
|
||||
mRoot(root),
|
||||
mNext(nsnull)
|
||||
{
|
||||
NS_IF_ADDREF(mRoot);
|
||||
|
||||
mProxyObject = new nsProxyObject(destQueue, proxyType, aObj, eventQService);
|
||||
mProxyObject = new nsProxyObject(target, proxyType, aObj);
|
||||
|
||||
#ifdef DEBUG_xpcom_proxy
|
||||
DebugDump("Create", 0);
|
||||
@@ -456,7 +447,7 @@ nsProxyEventObject::~nsProxyEventObject()
|
||||
|
||||
if (realToProxyMap != nsnull) {
|
||||
nsCOMPtr<nsISupports> rootObject = do_QueryInterface(mProxyObject->mRealObject);
|
||||
nsCOMPtr<nsISupports> rootQueue = do_QueryInterface(mProxyObject->mDestQueue);
|
||||
nsCOMPtr<nsISupports> rootQueue = do_QueryInterface(mProxyObject->mTarget);
|
||||
nsProxyEventKey key(rootObject, rootQueue, mProxyObject->mProxyType);
|
||||
#ifdef DEBUG_dougt
|
||||
void* value =
|
||||
|
||||
@@ -36,20 +36,19 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef __nsProxyEventPrivate_h_
|
||||
#define __nsProxyEventPrivate_h_
|
||||
#ifndef nsProxyEventPrivate_h__
|
||||
#define nsProxyEventPrivate_h__
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsIFactory.h"
|
||||
#include "nsHashtable.h"
|
||||
|
||||
#include "plevent.h"
|
||||
#include "xptcall.h" // defines nsXPTCVariant
|
||||
#include "nsIEventQueue.h"
|
||||
|
||||
#include "nsProxyEvent.h"
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "prmon.h"
|
||||
|
||||
class nsProxyEventObject;
|
||||
class nsProxyEventClass;
|
||||
@@ -113,7 +112,7 @@ public:
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_OBJECT_IID)
|
||||
|
||||
static nsProxyEventObject* GetNewOrUsedProxy(nsIEventQueue *destQueue,
|
||||
static nsProxyEventObject* GetNewOrUsedProxy(nsIDispatchTarget *target,
|
||||
PRInt32 proxyType,
|
||||
nsISupports *aObj,
|
||||
REFNSIID aIID);
|
||||
@@ -126,17 +125,16 @@ public:
|
||||
|
||||
|
||||
nsProxyEventClass* GetClass() const { return mClass; }
|
||||
nsIEventQueue* GetQueue() const { return (mProxyObject ? mProxyObject->GetQueue() : nsnull);}
|
||||
nsIDispatchTarget* GetTarget() const { return (mProxyObject ? mProxyObject->GetTarget() : nsnull);}
|
||||
nsISupports* GetRealObject() const { return (mProxyObject ? mProxyObject->GetRealObject(): nsnull);}
|
||||
PRInt32 GetProxyType() const { return (mProxyObject ? mProxyObject->GetProxyType() : nsnull);}
|
||||
|
||||
nsProxyEventObject();
|
||||
nsProxyEventObject(nsIEventQueue *destQueue,
|
||||
nsProxyEventObject(nsIDispatchTarget *target,
|
||||
PRInt32 proxyType,
|
||||
nsISupports* aObj,
|
||||
nsProxyEventClass* aClass,
|
||||
nsProxyEventObject* root,
|
||||
nsIEventQueueService* eventQService);
|
||||
nsProxyEventObject* root);
|
||||
|
||||
nsProxyEventObject* LockedFind(REFNSIID aIID);
|
||||
|
||||
@@ -199,4 +197,4 @@ private:
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
#endif // nsProxyEventPrivate_h__
|
||||
|
||||
@@ -57,10 +57,10 @@
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIThread.h"
|
||||
|
||||
|
||||
#if 0
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
|
||||
/***************************************************************************/
|
||||
@@ -102,6 +102,7 @@ NS_IMETHODIMP nsProxyCreateInstance::CreateInstanceByContractID(const char *aCon
|
||||
iid,
|
||||
result);
|
||||
}
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// nsProxyObjectManager
|
||||
@@ -118,20 +119,20 @@ nsProxyObjectManager::nsProxyObjectManager()
|
||||
mProxyCreationMonitor = PR_NewMonitor();
|
||||
}
|
||||
|
||||
static PRBool PurgeProxyClasses(nsHashKey *aKey, void *aData, void* closure)
|
||||
static PRIntn
|
||||
PurgeProxyClasses(nsHashKey *aKey, void *aData, void* closure)
|
||||
{
|
||||
nsProxyEventClass* ptr = NS_REINTERPRET_CAST(nsProxyEventClass*, aData);
|
||||
nsProxyEventClass* ptr = NS_STATIC_CAST(nsProxyEventClass*, aData);
|
||||
NS_RELEASE(ptr);
|
||||
return PR_TRUE;
|
||||
return kHashEnumerateNext;
|
||||
}
|
||||
|
||||
nsProxyObjectManager::~nsProxyObjectManager()
|
||||
{
|
||||
mProxyClassMap.Reset((nsHashtableEnumFunc)PurgeProxyClasses, nsnull);
|
||||
mProxyClassMap.Reset(PurgeProxyClasses, nsnull);
|
||||
|
||||
if (mProxyCreationMonitor) {
|
||||
if (mProxyCreationMonitor)
|
||||
PR_DestroyMonitor(mProxyCreationMonitor);
|
||||
}
|
||||
|
||||
nsProxyObjectManager::mInstance = nsnull;
|
||||
}
|
||||
@@ -139,92 +140,71 @@ nsProxyObjectManager::~nsProxyObjectManager()
|
||||
PRBool
|
||||
nsProxyObjectManager::IsManagerShutdown()
|
||||
{
|
||||
if (mInstance)
|
||||
return PR_FALSE;
|
||||
return PR_TRUE;
|
||||
return mInstance == nsnull;
|
||||
}
|
||||
|
||||
nsProxyObjectManager *
|
||||
nsProxyObjectManager::GetInstance()
|
||||
{
|
||||
if (! mInstance)
|
||||
{
|
||||
if (!mInstance)
|
||||
mInstance = new nsProxyObjectManager();
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsProxyObjectManager::Shutdown()
|
||||
{
|
||||
mInstance = nsnull;
|
||||
}
|
||||
|
||||
|
||||
// Helpers
|
||||
NS_IMETHODIMP
|
||||
nsProxyObjectManager::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
|
||||
nsProxyObjectManager::Create(nsISupports* outer, const nsIID& aIID,
|
||||
void* *aInstancePtr)
|
||||
{
|
||||
nsProxyObjectManager *proxyObjectManager = GetInstance();
|
||||
|
||||
if (proxyObjectManager == nsnull)
|
||||
if (!proxyObjectManager)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return proxyObjectManager->QueryInterface(aIID, aInstancePtr);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProxyObjectManager::GetProxyForObject(nsIEventQueue *destQueue,
|
||||
nsProxyObjectManager::GetProxyForObject(nsIDispatchTarget* aTarget,
|
||||
REFNSIID aIID,
|
||||
nsISupports* aObj,
|
||||
PRInt32 proxyType,
|
||||
void** aProxyObject)
|
||||
{
|
||||
if (!aObj) return NS_ERROR_NULL_POINTER;
|
||||
if (!aProxyObject) return NS_ERROR_NULL_POINTER;
|
||||
NS_ENSURE_ARG_POINTER(aTarget);
|
||||
NS_ENSURE_ARG_POINTER(aObj);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIEventQueue> postQ;
|
||||
|
||||
|
||||
*aProxyObject = nsnull;
|
||||
|
||||
// check to see if the destination Q is a special case.
|
||||
// check to see if the target is on our thread. If so, just return the
|
||||
// real object.
|
||||
|
||||
nsCOMPtr<nsIEventQueueService> eventQService =
|
||||
do_GetService(kEventQueueServiceCID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = eventQService->ResolveEventQueue(destQueue, getter_AddRefs(postQ));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// check to see if the eventQ is on our thread. If so, just return the real object.
|
||||
|
||||
if (postQ && !(proxyType & PROXY_ASYNC) && !(proxyType & PROXY_ALWAYS))
|
||||
if (!(proxyType & PROXY_ASYNC) && !(proxyType & PROXY_ALWAYS))
|
||||
{
|
||||
PRBool aResult;
|
||||
postQ->IsOnCurrentThread(&aResult);
|
||||
PRBool result;
|
||||
aTarget->IsOnCurrentThread(&result);
|
||||
|
||||
if (aResult)
|
||||
{
|
||||
if (result)
|
||||
return aObj->QueryInterface(aIID, aProxyObject);
|
||||
}
|
||||
}
|
||||
|
||||
// check to see if proxy is there or not.
|
||||
*aProxyObject = nsProxyEventObject::GetNewOrUsedProxy(postQ, proxyType, aObj, aIID);
|
||||
|
||||
if (*aProxyObject == nsnull)
|
||||
return NS_ERROR_NO_INTERFACE; //fix error code?
|
||||
*aProxyObject = nsProxyEventObject::GetNewOrUsedProxy(aTarget, proxyType,
|
||||
aObj, aIID);
|
||||
if (!*aProxyObject)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
NS_IMETHODIMP
|
||||
nsProxyObjectManager::GetProxy( nsIEventQueue *destQueue,
|
||||
const nsCID &aClass,
|
||||
@@ -292,6 +272,7 @@ nsProxyObjectManager::GetProxy( nsIEventQueue *destQueue,
|
||||
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Helper function for code that already has a link-time dependency on
|
||||
@@ -301,7 +282,7 @@ nsProxyObjectManager::GetProxy( nsIEventQueue *destQueue,
|
||||
* readable.
|
||||
*/
|
||||
NS_COM nsresult
|
||||
NS_GetProxyForObject(nsIEventQueue *destQueue,
|
||||
NS_GetProxyForObject(nsIDispatchTarget *target,
|
||||
REFNSIID aIID,
|
||||
nsISupports* aObj,
|
||||
PRInt32 proxyType,
|
||||
@@ -309,18 +290,17 @@ NS_GetProxyForObject(nsIEventQueue *destQueue,
|
||||
{
|
||||
static NS_DEFINE_CID(proxyObjMgrCID, NS_PROXYEVENT_MANAGER_CID);
|
||||
|
||||
nsresult rv; // temp for return value
|
||||
nsresult rv;
|
||||
|
||||
// get the proxy object manager
|
||||
//
|
||||
nsCOMPtr<nsIProxyObjectManager> proxyObjMgr =
|
||||
do_GetService(proxyObjMgrCID, &rv);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE;
|
||||
return rv;
|
||||
|
||||
// and try to get the proxy object
|
||||
//
|
||||
return proxyObjMgr->GetProxyForObject(destQueue, aIID, aObj,
|
||||
return proxyObjMgr->GetProxyForObject(target, aIID, aObj,
|
||||
proxyType, aProxyObject);
|
||||
}
|
||||
|
||||
@@ -1,21 +1,65 @@
|
||||
/* vim:set ts=4 sw=4 sts=4 et cin: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2003
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsRunnable.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
PR_STATIC_CALLBACK(void*)
|
||||
HandleProxyReleaseEvent(PLEvent *self)
|
||||
{
|
||||
nsISupports* owner = (nsISupports*) self->owner;
|
||||
NS_RELEASE(owner);
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(void)
|
||||
DestroyProxyReleaseEvent(PLEvent *self)
|
||||
class nsProxyReleaseEvent : public nsRunnable
|
||||
{
|
||||
delete self;
|
||||
}
|
||||
public:
|
||||
nsProxyReleaseEvent(nsISupports *doomed)
|
||||
: mDoomed(doomed) {
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mDoomed->Release();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsISupports *mDoomed;
|
||||
};
|
||||
|
||||
NS_COM nsresult
|
||||
NS_ProxyRelease(nsIEventTarget *target, nsISupports *doomed, PRBool alwaysProxy)
|
||||
NS_ProxyRelease(nsIDispatchTarget *target, nsISupports *doomed,
|
||||
PRBool alwaysProxy)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
@@ -33,21 +77,16 @@ NS_ProxyRelease(nsIEventTarget *target, nsISupports *doomed, PRBool alwaysProxy)
|
||||
}
|
||||
}
|
||||
|
||||
PLEvent *ev = new PLEvent;
|
||||
nsRefPtr<nsIRunnable> ev = new nsProxyReleaseEvent(doomed);
|
||||
if (!ev) {
|
||||
// we do not release doomed here since it may cause a delete on the
|
||||
// wrong thread. better to leak than crash.
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
PL_InitEvent(ev, doomed,
|
||||
HandleProxyReleaseEvent,
|
||||
DestroyProxyReleaseEvent);
|
||||
|
||||
rv = target->PostEvent(ev);
|
||||
rv = target->Dispatch(ev, NS_DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("failed to post proxy release event");
|
||||
PL_DestroyEvent(ev);
|
||||
// again, it is better to leak the doomed object than risk crashing as
|
||||
// a result of deleting it on the wrong thread.
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsThreadManager.h"
|
||||
#include "prprf.h"
|
||||
#include "prinrval.h"
|
||||
#include "plstr.h"
|
||||
@@ -134,7 +135,8 @@ TestPipe(nsIInputStream* in, nsIOutputStream* out)
|
||||
if (receiver == nsnull) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(receiver);
|
||||
|
||||
rv = NS_NewThread(&thread, receiver, 0, PR_JOINABLE_THREAD);
|
||||
rv = nsThreadManager::NewThread(NS_LITERAL_CSTRING("TestPipe"),
|
||||
receiver, &thread);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRUint32 total = 0;
|
||||
@@ -160,7 +162,7 @@ TestPipe(nsIInputStream* in, nsIOutputStream* out)
|
||||
|
||||
PRIntervalTime end = PR_IntervalNow();
|
||||
|
||||
thread->Join();
|
||||
thread->Shutdown();
|
||||
|
||||
printf("wrote %d bytes, time = %dms\n", total,
|
||||
PR_IntervalToMilliseconds(end - start));
|
||||
@@ -247,7 +249,8 @@ TestShortWrites(nsIInputStream* in, nsIOutputStream* out)
|
||||
if (receiver == nsnull) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(receiver);
|
||||
|
||||
rv = NS_NewThread(&thread, receiver, 0, PR_JOINABLE_THREAD);
|
||||
rv = nsThreadManager::NewThread(NS_LITERAL_CSTRING("TestShortWrites"),
|
||||
receiver, &thread);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRUint32 total = 0;
|
||||
@@ -274,7 +277,7 @@ TestShortWrites(nsIInputStream* in, nsIOutputStream* out)
|
||||
rv = out->Close();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
thread->Join();
|
||||
thread->Shutdown();
|
||||
printf("wrote %d bytes\n", total);
|
||||
|
||||
NS_RELEASE(thread);
|
||||
@@ -472,7 +475,8 @@ TestChainedPipes()
|
||||
if (pump == nsnull) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(pump);
|
||||
|
||||
rv = NS_NewThread(&thread, pump, 0, PR_JOINABLE_THREAD);
|
||||
rv = nsThreadManager::NewThread(NS_LITERAL_CSTRING("TestChainedPipes.pump"),
|
||||
pump, &thread);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsIThread* receiverThread;
|
||||
@@ -480,7 +484,8 @@ TestChainedPipes()
|
||||
if (receiver == nsnull) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(receiver);
|
||||
|
||||
rv = NS_NewThread(&receiverThread, receiver, 0, PR_JOINABLE_THREAD);
|
||||
rv = nsThreadManager::NewThread(NS_LITERAL_CSTRING("TestChainedPipes.receiver"),
|
||||
receiver, &receiverThread);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRUint32 total = 0;
|
||||
@@ -504,8 +509,8 @@ TestChainedPipes()
|
||||
rv = out1->Close();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
thread->Join();
|
||||
receiverThread->Join();
|
||||
thread->Shutdown();
|
||||
receiverThread->Shutdown();
|
||||
|
||||
NS_RELEASE(thread);
|
||||
NS_RELEASE(pump);
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
#include "nsIThread.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsThreadManager.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "nspr.h"
|
||||
@@ -51,7 +52,7 @@ public:
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsresult rv = nsIThread::GetCurrent(getter_AddRefs(thread));
|
||||
nsresult rv = nsThreadManager::get()->GetCurrentThread(getter_AddRefs(thread));
|
||||
if (NS_FAILED(rv)) {
|
||||
printf("failed to get current thread\n");
|
||||
return rv;
|
||||
@@ -80,30 +81,34 @@ TestThreads()
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIThread> runner;
|
||||
rv = NS_NewThread(getter_AddRefs(runner), new nsRunner(0), 0, PR_JOINABLE_THREAD);
|
||||
rv = nsThreadManager::NewThread(NS_LITERAL_CSTRING("TestThreads"),
|
||||
new nsRunner(0), getter_AddRefs(runner));
|
||||
if (NS_FAILED(rv)) {
|
||||
printf("failed to create thread\n");
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
rv = nsIThread::GetCurrent(getter_AddRefs(thread));
|
||||
rv = nsThreadManager::get()->GetCurrentThread(getter_AddRefs(thread));
|
||||
if (NS_FAILED(rv)) {
|
||||
printf("failed to get current thread\n");
|
||||
return rv;
|
||||
}
|
||||
|
||||
#if 0
|
||||
PRThreadScope scope;
|
||||
rv = runner->GetScope(&scope);
|
||||
if (NS_FAILED(rv)) {
|
||||
printf("runner already exited\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
rv = runner->Join(); // wait for the runner to die before quitting
|
||||
rv = runner->Shutdown(); // wait for the runner to die before quitting
|
||||
if (NS_FAILED(rv)) {
|
||||
printf("join failed\n");
|
||||
}
|
||||
|
||||
#if 0
|
||||
rv = runner->GetScope(&scope); // this should fail after Join
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
printf("get scope failed\n");
|
||||
@@ -126,6 +131,7 @@ TestThreads()
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
printf("shouldn't have been able to join an unjoinable thread\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
PR_Sleep(PR_MillisecondsToInterval(100)); // hopefully the runner will quit here
|
||||
|
||||
@@ -181,15 +187,16 @@ static int Stress(int loops, int threads)
|
||||
|
||||
for (k = 0; k < threads; k++) {
|
||||
nsCOMPtr<nsIThread> t;
|
||||
nsresult rv = NS_NewThread(getter_AddRefs(t),
|
||||
new nsStressRunner(k),
|
||||
0, PR_JOINABLE_THREAD);
|
||||
nsCString name("thread:");
|
||||
name.AppendInt(k);
|
||||
nsresult rv = nsThreadManager::NewThread(name, new nsStressRunner(k),
|
||||
getter_AddRefs(t));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "can't create thread");
|
||||
NS_ADDREF(array[k] = t);
|
||||
}
|
||||
|
||||
for (k = threads-1; k >= 0; k--) {
|
||||
array[k]->Join();
|
||||
array[k]->Shutdown();
|
||||
NS_RELEASE(array[k]);
|
||||
}
|
||||
delete [] array;
|
||||
|
||||
@@ -55,37 +55,34 @@ MOZILLA_INTERNAL_API = 1
|
||||
REQUIRES = string \
|
||||
$(NULL)
|
||||
|
||||
CSRCS = \
|
||||
plevent.c \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsAutoLock.cpp \
|
||||
nsTaskQueue.cpp \
|
||||
nsEnvironment.cpp \
|
||||
nsEventQueue.cpp \
|
||||
nsEventQueueService.cpp \
|
||||
nsRunnable.cpp \
|
||||
nsThread.cpp \
|
||||
nsTimerImpl.cpp \
|
||||
nsThreadManager.cpp \
|
||||
nsProcessCommon.cpp \
|
||||
nsTimerImpl.cpp \
|
||||
TimerThread.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
nsAutoLock.h \
|
||||
plevent.h \
|
||||
nsProcess.h \
|
||||
nsEventQueueUtils.h \
|
||||
nsRunnable.h \
|
||||
nsThreadManager.h \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIDispatchTarget.idl \
|
||||
nsIThread.idl \
|
||||
nsIThreadInternal.idl \
|
||||
nsIThreadManager.idl \
|
||||
nsITimer.idl \
|
||||
nsITimerInternal.idl \
|
||||
nsITimerManager.idl \
|
||||
nsIRunnable.idl \
|
||||
nsIEventTarget.idl \
|
||||
nsIEventQueue.idl \
|
||||
nsIEventQueueService.idl \
|
||||
nsIEnvironment.idl \
|
||||
nsIProcess.idl \
|
||||
nsISupportsPriority.idl \
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "TimerThread.h"
|
||||
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsThreadManager.h"
|
||||
#include "pratom.h"
|
||||
|
||||
#include "nsIObserverService.h"
|
||||
@@ -105,29 +106,20 @@ nsresult TimerThread::Init()
|
||||
|
||||
if (PR_AtomicSet(&mInitInProgress, 1) == 0) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIObserverService> observerService
|
||||
(do_GetService("@mozilla.org/observer-service;1", &rv));
|
||||
|
||||
mEventQueueService = do_GetService("@mozilla.org/event-queue-service;1", &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsIObserverService> observerService
|
||||
(do_GetService("@mozilla.org/observer-service;1", &rv));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// We hold on to mThread to keep the thread alive.
|
||||
rv = NS_NewThread(getter_AddRefs(mThread),
|
||||
NS_STATIC_CAST(nsIRunnable*, this),
|
||||
0,
|
||||
PR_JOINABLE_THREAD,
|
||||
PR_PRIORITY_NORMAL,
|
||||
PR_GLOBAL_THREAD);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
mThread = nsnull;
|
||||
}
|
||||
else {
|
||||
// We'll be released at xpcom shutdown
|
||||
observerService->AddObserver(this, "sleep_notification", PR_FALSE);
|
||||
observerService->AddObserver(this, "wake_notification", PR_FALSE);
|
||||
}
|
||||
// We hold on to mThread to keep the thread alive.
|
||||
rv = nsThreadManager::NewThread(NS_LITERAL_CSTRING("xpcom.timer"), this,
|
||||
getter_AddRefs(mThread));
|
||||
if (NS_FAILED(rv)) {
|
||||
mThread = nsnull;
|
||||
}
|
||||
else {
|
||||
// We'll be released at xpcom shutdown
|
||||
observerService->AddObserver(this, "sleep_notification", PR_FALSE);
|
||||
observerService->AddObserver(this, "wake_notification", PR_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +163,7 @@ nsresult TimerThread::Shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
mThread->Join(); // wait for the thread to die
|
||||
mThread->Shutdown(); // wait for the thread to die
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#ifndef TimerThread_h___
|
||||
#define TimerThread_h___
|
||||
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsIThread.h"
|
||||
@@ -78,9 +77,6 @@ public:
|
||||
void UpdateFilter(PRUint32 aDelay, PRIntervalTime aTimeout,
|
||||
PRIntervalTime aNow);
|
||||
|
||||
// For use by nsTimerImpl::Fire()
|
||||
nsCOMPtr<nsIEventQueueService> mEventQueueService;
|
||||
|
||||
void DoBeforeSleep();
|
||||
void DoAfterSleep();
|
||||
|
||||
|
||||
69
mozilla/xpcom/threads/nsIDispatchTarget.idl
Normal file
69
mozilla/xpcom/threads/nsIDispatchTarget.idl
Normal file
@@ -0,0 +1,69 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIRunnable;
|
||||
|
||||
[scriptable, uuid(4e8febe4-6631-49dc-8ac9-308c1cb9b09c)]
|
||||
interface nsIDispatchTarget : nsISupports
|
||||
{
|
||||
/**
|
||||
* Dispatch a task to the target. This function may be called from any
|
||||
* thread. If flags specifies DISPATCH_SYNC, then the dispatch method
|
||||
* will not return until the task has been run. NOTE: Calling dispatch
|
||||
* with DISPATCH_SYNC, may have the side-effect of running other tasks
|
||||
* on the current thread while waiting for the given task to run to
|
||||
* completion. This function is re-entrant.
|
||||
*/
|
||||
void dispatch(in nsIRunnable task, in unsigned long flags);
|
||||
const unsigned long DISPATCH_NORMAL = 0;
|
||||
const unsigned long DISPATCH_SYNC = 1;
|
||||
|
||||
/**
|
||||
* Returns true if tasks dispatched to this target will run on the
|
||||
* current thread (i.e., the thread calling this method).
|
||||
*/
|
||||
boolean isOnCurrentThread();
|
||||
};
|
||||
|
||||
%{C++
|
||||
// convenient aliases:
|
||||
#define NS_DISPATCH_NORMAL nsIDispatchTarget::DISPATCH_NORMAL
|
||||
#define NS_DISPATCH_SYNC nsIDispatchTarget::DISPATCH_SYNC
|
||||
%}
|
||||
@@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@@ -12,18 +13,18 @@
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
@@ -35,110 +36,51 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIDispatchTarget.idl"
|
||||
|
||||
%{C++
|
||||
#include "prthread.h"
|
||||
|
||||
#define NS_THREAD_CID \
|
||||
{ /* 85CE5510-7808-11d3-A181-0050041CAF44 */ \
|
||||
0x85ce5510, \
|
||||
0x7808, \
|
||||
0x11d3, \
|
||||
{0xa1, 0x81, 0x00, 0x50, 0x04, 0x1c, 0xaf, 0x44} \
|
||||
}
|
||||
|
||||
#define NS_THREAD_CONTRACTID "@mozilla.org/thread;1"
|
||||
#define NS_THREAD_CLASSNAME "Thread"
|
||||
#if 0
|
||||
%}
|
||||
|
||||
typedef PRUint32 PRThreadPriority;
|
||||
typedef PRUint32 PRThreadScope;
|
||||
typedef PRUint32 PRThreadState;
|
||||
|
||||
%{C++
|
||||
#endif
|
||||
%}
|
||||
|
||||
interface nsIRunnable;
|
||||
|
||||
[ptr] native PRThread(PRThread);
|
||||
|
||||
[scriptable, uuid(6be5e380-6886-11d3-9382-00104ba0fd40)]
|
||||
interface nsIThread : nsISupports
|
||||
[scriptable, uuid(9c889946-a73a-4af3-ae9a-ea64f7d4e3ca)]
|
||||
interface nsIThread : nsIDispatchTarget
|
||||
{
|
||||
// These must all match the values used in prthread.h
|
||||
const PRUint32 PRIORITY_LOW = 0;
|
||||
const PRUint32 PRIORITY_NORMAL = 1;
|
||||
const PRUint32 PRIORITY_HIGH = 2;
|
||||
const PRUint32 PRIORITY_URGENT = 3;
|
||||
/**
|
||||
* Returns the name of the thread.
|
||||
*/
|
||||
readonly attribute ACString name;
|
||||
|
||||
const PRUint32 SCOPE_LOCAL = 0;
|
||||
const PRUint32 SCOPE_GLOBAL = 1;
|
||||
const PRUint32 SCOPE_BOUND = 2;
|
||||
|
||||
const PRUint32 STATE_JOINABLE = 0;
|
||||
const PRUint32 STATE_UNJOINABLE = 1;
|
||||
|
||||
void join();
|
||||
void interrupt();
|
||||
|
||||
attribute PRThreadPriority priority;
|
||||
readonly attribute PRThreadScope scope;
|
||||
readonly attribute PRThreadState state;
|
||||
|
||||
[noscript] PRThread GetPRThread();
|
||||
|
||||
void init(in nsIRunnable aRunnable,
|
||||
in PRUint32 aStackSize,
|
||||
in PRThreadPriority aPriority,
|
||||
in PRThreadScope aScope,
|
||||
in PRThreadState aState);
|
||||
|
||||
/*
|
||||
* Get the currently running thread (really a static method sort of thing).
|
||||
*/
|
||||
readonly attribute nsIThread currentThread;
|
||||
|
||||
/*
|
||||
* Sleep to at least this many milliseconds (only works on currrent thread).
|
||||
*/
|
||||
void sleep(in PRUint32 msec);
|
||||
|
||||
%{C++
|
||||
// returns the nsIThread for the current thread:
|
||||
static NS_COM nsresult GetCurrent(nsIThread* *result);
|
||||
|
||||
// returns the nsIThread for an arbitrary PRThread:
|
||||
static NS_COM nsresult GetIThread(PRThread* prthread, nsIThread* *result);
|
||||
|
||||
// initializes the "main" thread (really, just saves the current thread
|
||||
// at time of calling. meant to be called once at app startup, in lieu
|
||||
// of proper static initializers, to save the primordial thread
|
||||
// for later recall.)
|
||||
static NS_COM nsresult SetMainThread();
|
||||
|
||||
// return the "main" thread
|
||||
static NS_COM nsresult GetMainThread(nsIThread **result);
|
||||
|
||||
static NS_COM PRBool IsMainThread();
|
||||
%}
|
||||
/**
|
||||
* Shutdown the thread. This method may not be executed from the thread
|
||||
* itself. Instead, it is meant to be executed from another thread (usually
|
||||
* the thread that created this thread). When this function returns, the
|
||||
* thread will be shutdown, and it will no longer be possible to dispatch
|
||||
* tasks to the thread.
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* Run the next task assigned to this thread. This function should block
|
||||
* execution of the current thread until a task is available and run.
|
||||
* This function is re-entrant but may only be called if this thread is the
|
||||
* current thread.
|
||||
* @throws NS_BASE_STREAM_WOULD_BLOCK if RUN_NO_WAIT is specified and there
|
||||
* were no tasks to run.
|
||||
*/
|
||||
void runNextTask(in unsigned long flags);
|
||||
const unsigned long RUN_NORMAL = 0;
|
||||
const unsigned long RUN_NO_WAIT = 1;
|
||||
};
|
||||
|
||||
%{C++
|
||||
extern NS_COM nsresult
|
||||
NS_NewThread(nsIThread* *result,
|
||||
nsIRunnable* runnable,
|
||||
PRUint32 stackSize = 0,
|
||||
PRThreadState state = PR_UNJOINABLE_THREAD,
|
||||
PRThreadPriority priority = PR_PRIORITY_NORMAL,
|
||||
PRThreadScope scope = PR_GLOBAL_THREAD);
|
||||
// Run all pending tasks for a given thread before returning.
|
||||
static inline nsresult
|
||||
NS_RunPendingTasks(nsIThread *thread)
|
||||
{
|
||||
nsresult rv;
|
||||
do {
|
||||
rv = thread->RunNextTask(nsIThread::RUN_NO_WAIT);
|
||||
} while (NS_SUCCEEDED(rv));
|
||||
|
||||
extern NS_COM nsresult
|
||||
NS_NewThread(nsIThread* *result,
|
||||
PRUint32 stackSize = 0,
|
||||
PRThreadState state = PR_UNJOINABLE_THREAD,
|
||||
PRThreadPriority priority = PR_PRIORITY_NORMAL,
|
||||
PRThreadScope scope = PR_GLOBAL_THREAD);
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK)
|
||||
rv = NS_OK;
|
||||
|
||||
return rv;
|
||||
}
|
||||
%}
|
||||
|
||||
121
mozilla/xpcom/threads/nsIThreadInternal.idl
Normal file
121
mozilla/xpcom/threads/nsIThreadInternal.idl
Normal file
@@ -0,0 +1,121 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsIThread.idl"
|
||||
|
||||
interface nsIThreadObserver;
|
||||
|
||||
/**
|
||||
* The standard XPCOM thread object implements this interface, which allows a
|
||||
* consumer to observe dispatch activity on the thread.
|
||||
*/
|
||||
[scriptable, uuid(f89b5063-b06d-42f8-bf23-4dfcf2d80d6a)]
|
||||
interface nsIThreadInternal : nsIThread
|
||||
{
|
||||
/**
|
||||
* The consumer's thread observer.
|
||||
*/
|
||||
attribute nsIThreadObserver observer;
|
||||
|
||||
/**
|
||||
* This method returns true if there is a pending task for this thread.
|
||||
*/
|
||||
boolean hasPendingTask();
|
||||
};
|
||||
|
||||
/**
|
||||
* This interface provides the observer with hooks to implement a layered
|
||||
* event queue. For example, it is possible to overlay processing events
|
||||
* for a GUI toolkit on top of the events for a thread.
|
||||
*
|
||||
* NativeQueue;
|
||||
*
|
||||
* Observer = {
|
||||
* onNewTask(thread, flags) {
|
||||
* NativeQueue.signal();
|
||||
* }
|
||||
* onBeforeRunNextTask(thread, flags) {
|
||||
* NativeQueue.processPendingEvents();
|
||||
* }
|
||||
* onAfterRunNextTask(thread, flags, status) {
|
||||
* NativeQueue.processPendingEvents();
|
||||
* }
|
||||
* onWaitNextTask(thread, flags) {
|
||||
* while (!thread.hasPendingTask()) {
|
||||
* NativeQueue.wait();
|
||||
* NativeQueue.processPendingEvents();
|
||||
* }
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* NOTE: The implementation of this interface must be threadsafe.
|
||||
*/
|
||||
[scriptable, uuid(719d2fb9-54ce-4847-b15b-fa9960e22f9f)]
|
||||
interface nsIThreadObserver : nsISupports
|
||||
{
|
||||
/**
|
||||
* This method is called whenever a new task is added to the thread. This
|
||||
* method may be called from any thread.
|
||||
*/
|
||||
void onNewTask(in nsIThreadInternal thread,
|
||||
in unsigned long dispatchFlags);
|
||||
|
||||
/**
|
||||
* This method is called (from nsIThread.runNextTask) before a task is
|
||||
* processed. This method is only called on the target thread.
|
||||
*/
|
||||
void onBeforeRunNextTask(in nsIThreadInternal thread,
|
||||
in unsigned long runFlags);
|
||||
|
||||
/**
|
||||
* This method is called (from nsIThread.runNextTask) after a task is
|
||||
* processed. This method is only called on the target thread.
|
||||
*/
|
||||
void onAfterRunNextTask(in nsIThreadInternal thread,
|
||||
in unsigned long runFlags,
|
||||
in nsresult status);
|
||||
|
||||
/**
|
||||
* This method is called (from nsIThread.runNextTask) when it may wait for a
|
||||
* pending task to become available. It's possible that a pending task may
|
||||
* already be available when this method is called. This method is only
|
||||
* called on the target thread.
|
||||
*/
|
||||
void onWaitNextTask(in nsIThreadInternal thread,
|
||||
in unsigned long runFlags);
|
||||
};
|
||||
83
mozilla/xpcom/threads/nsIThreadManager.idl
Normal file
83
mozilla/xpcom/threads/nsIThreadManager.idl
Normal file
@@ -0,0 +1,83 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIThread;
|
||||
|
||||
[scriptable, uuid(056216f5-8803-46b4-9199-d95bc1f0446f)]
|
||||
interface nsIThreadManager : nsISupports
|
||||
{
|
||||
/**
|
||||
* Create a new named thread (a global, user PRThread). The name
|
||||
* must be unique.
|
||||
*/
|
||||
nsIThread newThread(in ACString name);
|
||||
|
||||
/**
|
||||
* Find a named thread.
|
||||
*/
|
||||
nsIThread getThread(in ACString name);
|
||||
|
||||
/**
|
||||
* Get the main thread.
|
||||
*/
|
||||
nsIThread getMainThread();
|
||||
|
||||
/**
|
||||
* Get the current thread.
|
||||
*/
|
||||
nsIThread getCurrentThread();
|
||||
|
||||
/**
|
||||
* Set an external nsIThread instance (or null) as the nsIThread for the
|
||||
* current thread. If a nsIThread is already associated with the calling
|
||||
* thread, then this function will replace it with the given nsIThread. If
|
||||
* the given nsIThread is non-null, then its name attribute must be unique.
|
||||
* Its name may be equal to the name of the nsIThread being replaced. This
|
||||
* method returns the nsIThread that was replaced by this method call or null
|
||||
* if there was no previous nsIThread associated with the current thread.
|
||||
*/
|
||||
nsIThread setCurrentThread(in nsIThread thread);
|
||||
|
||||
/**
|
||||
* This method returns true if the calling thread is the main thread of the
|
||||
* application process.
|
||||
*/
|
||||
boolean isMainThread();
|
||||
};
|
||||
48
mozilla/xpcom/threads/nsRunnable.cpp
Normal file
48
mozilla/xpcom/threads/nsRunnable.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsRunnable.h"
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsRunnable, nsIRunnable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsRunnable::Run()
|
||||
{
|
||||
// Do nothing
|
||||
return NS_OK;
|
||||
}
|
||||
60
mozilla/xpcom/threads/nsRunnable.h
Normal file
60
mozilla/xpcom/threads/nsRunnable.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsRunnable_h__
|
||||
#define nsRunnable_h__
|
||||
|
||||
#include "nsIRunnable.h"
|
||||
|
||||
// This class is designed to be subclassed.
|
||||
|
||||
class nsRunnable : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
nsRunnable() {
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~nsRunnable() {
|
||||
}
|
||||
};
|
||||
|
||||
#endif // nsRunnable_h__
|
||||
117
mozilla/xpcom/threads/nsTaskQueue.cpp
Normal file
117
mozilla/xpcom/threads/nsTaskQueue.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsTaskQueue.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
nsTaskQueue::nsTaskQueue()
|
||||
: mMonitor(nsAutoMonitor::NewMonitor("TaskQueue"))
|
||||
, mHead(nsnull)
|
||||
, mTail(nsnull)
|
||||
, mOffsetHead(0)
|
||||
, mOffsetTail(0)
|
||||
{
|
||||
}
|
||||
|
||||
nsTaskQueue::~nsTaskQueue()
|
||||
{
|
||||
nsAutoMonitor::DestroyMonitor(mMonitor);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsTaskQueue::GetPendingTask(PRBool wait, nsIRunnable **result)
|
||||
{
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
while (IsEmpty()) {
|
||||
if (!wait) {
|
||||
if (result)
|
||||
*result = nsnull;
|
||||
return PR_FALSE;
|
||||
}
|
||||
mon.Wait();
|
||||
}
|
||||
|
||||
if (result)
|
||||
*result = mHead->mTasks[mOffsetHead++];
|
||||
|
||||
// Check if mHead points to empty Page
|
||||
if (mOffsetHead == TASKS_PER_PAGE) {
|
||||
Page *dead = mHead;
|
||||
mHead = mHead->mNext;
|
||||
delete dead;
|
||||
mOffsetHead = 0;
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsTaskQueue::PutTask(nsIRunnable *runnable)
|
||||
{
|
||||
// Avoid calling AddRef+Release while holding our monitor.
|
||||
nsCOMPtr<nsIRunnable> task(runnable);
|
||||
PRBool rv = PR_TRUE;
|
||||
{
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
if (!mHead) {
|
||||
mHead = new Page();
|
||||
if (!mHead) {
|
||||
rv = PR_FALSE;
|
||||
} else {
|
||||
mTail = mHead;
|
||||
mOffsetHead = 0;
|
||||
mOffsetTail = 0;
|
||||
}
|
||||
} else if (mOffsetTail == TASKS_PER_PAGE) {
|
||||
Page *page = new Page();
|
||||
if (!page) {
|
||||
rv = PR_FALSE;
|
||||
} else {
|
||||
mTail->mNext = page;
|
||||
mTail = page;
|
||||
mOffsetTail = 0;
|
||||
}
|
||||
}
|
||||
if (rv)
|
||||
task.swap(mTail->mTasks[mOffsetTail++]);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
96
mozilla/xpcom/threads/nsTaskQueue.h
Normal file
96
mozilla/xpcom/threads/nsTaskQueue.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsTaskQueue_h__
|
||||
#define nsTaskQueue_h__
|
||||
|
||||
#include "prmon.h"
|
||||
#include "nsIRunnable.h"
|
||||
|
||||
// A threadsafe FIFO task queue...
|
||||
class nsTaskQueue
|
||||
{
|
||||
public:
|
||||
nsTaskQueue();
|
||||
~nsTaskQueue();
|
||||
|
||||
// This method adds a new task on the pending task queue.
|
||||
PRBool PutTask(nsIRunnable *runnable);
|
||||
|
||||
// This method returns true if there is a pending task.
|
||||
PRBool HasPendingTask() {
|
||||
return GetPendingTask(PR_FALSE, nsnull);
|
||||
}
|
||||
|
||||
// This method returns the next pending task or null.
|
||||
PRBool GetPendingTask(nsIRunnable **runnable) {
|
||||
return GetPendingTask(PR_FALSE, runnable);
|
||||
}
|
||||
|
||||
// This method waits for and returns the next pending task.
|
||||
PRBool WaitPendingTask(nsIRunnable **runnable) {
|
||||
return GetPendingTask(PR_TRUE, runnable);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
PRBool GetPendingTask(PRBool wait, nsIRunnable **runnable);
|
||||
|
||||
PRBool IsEmpty() {
|
||||
return !mHead || (mHead == mTail && mOffsetHead == mOffsetTail);
|
||||
}
|
||||
|
||||
enum { TASKS_PER_PAGE = 15 };
|
||||
|
||||
struct Page {
|
||||
struct Page *mNext;
|
||||
nsIRunnable *mTasks[TASKS_PER_PAGE];
|
||||
|
||||
Page() : mNext(nsnull) {}
|
||||
};
|
||||
|
||||
PRMonitor *mMonitor;
|
||||
|
||||
Page *mHead;
|
||||
Page *mTail;
|
||||
|
||||
PRUint16 mOffsetHead; // offset into mHead where next item is removed
|
||||
PRUint16 mOffsetTail; // offset into mTail where next item is added
|
||||
};
|
||||
|
||||
#endif // nsTaskQueue_h__
|
||||
@@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@@ -12,18 +13,18 @@
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
@@ -36,450 +37,428 @@
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsThread.h"
|
||||
#include "prmem.h"
|
||||
#include "prlog.h"
|
||||
#include "nsThreadManager.h"
|
||||
#include "nsRunnable.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
PRUintn nsThread::kIThreadSelfIndex = 0;
|
||||
static nsIThread *gMainThread = 0;
|
||||
NS_DECL_CI_INTERFACE_GETTER(nsThread)
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
//
|
||||
// Log module for nsIThread logging...
|
||||
//
|
||||
// To enable logging (see prlog.h for full details):
|
||||
//
|
||||
// set NSPR_LOG_MODULES=nsIThread:5
|
||||
// set NSPR_LOG_FILE=nspr.log
|
||||
//
|
||||
// this enables PR_LOG_DEBUG level information and places all output in
|
||||
// the file nspr.log
|
||||
//
|
||||
// gSocketLog is defined in nsSocketTransport.cpp
|
||||
//
|
||||
PRLogModuleInfo* nsIThreadLog = nsnull;
|
||||
//-----------------------------------------------------------------------------
|
||||
// Because we do not have our own nsIFactory, we have to implement nsIClassInfo
|
||||
// somewhat manually.
|
||||
|
||||
#endif /* PR_LOGGING */
|
||||
class nsThreadClassInfo : public nsIClassInfo {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED // no mRefCnt
|
||||
NS_DECL_NSICLASSINFO
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
nsThreadClassInfo() {}
|
||||
};
|
||||
|
||||
nsThread::nsThread()
|
||||
: mThread(nsnull), mDead(PR_FALSE), mStartLock(nsnull)
|
||||
static nsThreadClassInfo sThreadClassInfo;
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt) nsThreadClassInfo::AddRef() { return 2; }
|
||||
NS_IMETHODIMP_(nsrefcnt) nsThreadClassInfo::Release() { return 1; }
|
||||
NS_IMPL_QUERY_INTERFACE1(nsThreadClassInfo, nsIClassInfo)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetInterfaces(PRUint32 *count, nsIID ***array)
|
||||
{
|
||||
#if defined(PR_LOGGING)
|
||||
//
|
||||
// Initialize the global PRLogModule for nsIThread logging
|
||||
// if necessary...
|
||||
//
|
||||
if (nsIThreadLog == nsnull) {
|
||||
nsIThreadLog = PR_NewLogModule("nsIThread");
|
||||
}
|
||||
#endif /* PR_LOGGING */
|
||||
return NS_CI_INTERFACE_GETTER_NAME(nsThread)(count, array);
|
||||
}
|
||||
|
||||
// enforce matching of constants to enums in prthread.h
|
||||
NS_ASSERTION(int(nsIThread::PRIORITY_LOW) == int(PR_PRIORITY_LOW) &&
|
||||
int(nsIThread::PRIORITY_NORMAL) == int(PRIORITY_NORMAL) &&
|
||||
int(nsIThread::PRIORITY_HIGH) == int(PRIORITY_HIGH) &&
|
||||
int(nsIThread::PRIORITY_URGENT) == int(PRIORITY_URGENT) &&
|
||||
int(nsIThread::SCOPE_LOCAL) == int(PR_LOCAL_THREAD) &&
|
||||
int(nsIThread::SCOPE_GLOBAL) == int(PR_GLOBAL_THREAD) &&
|
||||
int(nsIThread::STATE_JOINABLE) == int(PR_JOINABLE_THREAD) &&
|
||||
int(nsIThread::STATE_UNJOINABLE) == int(PR_UNJOINABLE_THREAD),
|
||||
"Bad constant in nsIThread!");
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetHelperForLanguage(PRUint32 lang, nsISupports **result)
|
||||
{
|
||||
*result = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetContractID(char **result)
|
||||
{
|
||||
*result = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetClassDescription(char **result)
|
||||
{
|
||||
*result = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetClassID(nsCID **result)
|
||||
{
|
||||
*result = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetImplementationLanguage(PRUint32 *result)
|
||||
{
|
||||
*result = nsIProgrammingLanguage::CPLUSPLUS;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetFlags(PRUint32 *result)
|
||||
{
|
||||
*result = THREADSAFE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetClassIDNoAlloc(nsCID *result)
|
||||
{
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMPL_THREADSAFE_ADDREF(nsThread)
|
||||
NS_IMPL_THREADSAFE_RELEASE(nsThread)
|
||||
NS_INTERFACE_MAP_BEGIN(nsThread)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIThread)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIThreadInternal)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDispatchTarget)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIThread)
|
||||
if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {
|
||||
foundInterface = NS_STATIC_CAST(nsIClassInfo*, &sThreadClassInfo);
|
||||
} else
|
||||
NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CI_INTERFACE_GETTER4(nsThread, nsIThread, nsIThreadInternal,
|
||||
nsIDispatchTarget, nsISupportsPriority)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsThreadShutdownTask : public nsRunnable {
|
||||
public:
|
||||
nsThreadShutdownTask(nsThread *thr)
|
||||
: mThread(thr) {
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Run() {
|
||||
mThread->mActive = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<nsThread> mThread;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsThreadSyncDispatch : public nsRunnable {
|
||||
public:
|
||||
nsThreadSyncDispatch(nsIRunnable *task)
|
||||
: mSyncTask(task) {
|
||||
}
|
||||
|
||||
NS_IMETHODIMP Run() {
|
||||
mSyncTask->Run();
|
||||
mSyncTask = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool IsPending() {
|
||||
return mSyncTask != nsnull;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIRunnable> mSyncTask;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// This class is used to convey initialization info to the newly created thread.
|
||||
class nsThreadStartInfo {
|
||||
private:
|
||||
PRInt32 mRefCnt;
|
||||
|
||||
~nsThreadStartInfo() {
|
||||
nsAutoMonitor::DestroyMonitor(mMon);
|
||||
}
|
||||
public:
|
||||
PRMonitor *mMon;
|
||||
nsThread *mThread;
|
||||
PRBool mInitialized;
|
||||
|
||||
nsThreadStartInfo(nsThread *thr)
|
||||
: mRefCnt(0)
|
||||
, mMon(nsAutoMonitor::NewMonitor("nsThreadStartInfo"))
|
||||
, mThread(thr)
|
||||
, mInitialized(PR_FALSE) {
|
||||
}
|
||||
|
||||
void AddRef() {
|
||||
PR_AtomicIncrement(&mRefCnt);
|
||||
}
|
||||
|
||||
void Release() {
|
||||
if (PR_AtomicDecrement(&mRefCnt) == 0)
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*static*/ void
|
||||
nsThread::ThreadFunc(void *arg)
|
||||
{
|
||||
nsThreadStartInfo *si = NS_STATIC_CAST(nsThreadStartInfo *, arg);
|
||||
|
||||
nsThread *self = si->mThread;
|
||||
NS_ADDREF(self);
|
||||
|
||||
// Inform the ThreadManager
|
||||
nsThreadManager::get()->SetCurrentThread(self, nsnull);
|
||||
|
||||
// Unblock nsThread::Init
|
||||
{
|
||||
nsAutoMonitor mon(si->mMon);
|
||||
si->mInitialized = PR_TRUE;
|
||||
mon.Notify();
|
||||
}
|
||||
NS_RELEASE(si);
|
||||
|
||||
// Now, process incoming tasks...
|
||||
while (self->mActive)
|
||||
self->RunNextTask(nsIThread::RUN_NORMAL);
|
||||
|
||||
NS_RELEASE(self);
|
||||
|
||||
// Inform the threadmanager that this thread is going away
|
||||
nsThreadManager::get()->SetCurrentThread(nsnull, nsnull);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsThread::nsThread(const nsACString &name)
|
||||
: mObserverLock(PR_NewLock())
|
||||
, mName(name)
|
||||
{
|
||||
}
|
||||
|
||||
nsThread::~nsThread()
|
||||
{
|
||||
if (mStartLock)
|
||||
PR_DestroyLock(mStartLock);
|
||||
|
||||
PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
|
||||
("nsIThread %p destroyed\n", this));
|
||||
|
||||
// This code used to free the nsIThreadLog loginfo stuff
|
||||
// Don't do that; loginfo structures are owned by nspr
|
||||
// and would be freed if we ever called PR_Cleanup()
|
||||
// see bug 142072
|
||||
PR_DestroyLock(mObserverLock);
|
||||
}
|
||||
|
||||
void
|
||||
nsThread::Main(void* arg)
|
||||
{
|
||||
nsThread* self = (nsThread*)arg;
|
||||
|
||||
self->WaitUntilReadyToStartMain();
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
rv = self->RegisterThreadSelf();
|
||||
NS_ASSERTION(rv == NS_OK, "failed to set thread self");
|
||||
|
||||
PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
|
||||
("nsIThread %p start run %p\n", self, self->mRunnable.get()));
|
||||
rv = self->mRunnable->Run();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "runnable failed");
|
||||
|
||||
#ifdef DEBUG
|
||||
// Because a thread can die after gMainThread dies and takes nsIThreadLog with it,
|
||||
// we need to check for it being null so that we don't crash on shutdown.
|
||||
if (nsIThreadLog) {
|
||||
PRThreadState state;
|
||||
rv = self->GetState(&state);
|
||||
PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
|
||||
("nsIThread %p end run %p\n", self, self->mRunnable.get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
// explicitly drop the runnable now in case there are circular references
|
||||
// between it and the thread object
|
||||
self->mRunnable = nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
nsThread::Exit(void* arg)
|
||||
{
|
||||
nsThread* self = (nsThread*)arg;
|
||||
|
||||
if (self->mDead) {
|
||||
NS_ERROR("attempt to Exit() thread twice");
|
||||
return;
|
||||
}
|
||||
|
||||
self->mDead = PR_TRUE;
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
if (nsIThreadLog) {
|
||||
PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
|
||||
("nsIThread %p exited\n", self));
|
||||
}
|
||||
#endif
|
||||
NS_RELEASE(self);
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
nsThread::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
|
||||
{
|
||||
nsThread* thread = new nsThread();
|
||||
if (!thread) return NS_ERROR_OUT_OF_MEMORY;
|
||||
nsresult rv = thread->QueryInterface(aIID, aResult);
|
||||
if (NS_FAILED(rv)) delete thread;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsThread, nsIThread)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::Join()
|
||||
{
|
||||
// don't check for mDead here because nspr calls Exit (cleaning up
|
||||
// thread-local storage) before they let us join with the thread
|
||||
|
||||
PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
|
||||
("nsIThread %p start join\n", this));
|
||||
if (!mThread)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
PRStatus status = PR_JoinThread(mThread);
|
||||
// XXX can't use NS_RELEASE here because the macro wants to set
|
||||
// this to null (bad c++)
|
||||
PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
|
||||
("nsIThread %p end join\n", this));
|
||||
if (status != PR_SUCCESS)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
NS_RELEASE_THIS(); // most likely the final release of this thread
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::GetPriority(PRThreadPriority *result)
|
||||
{
|
||||
if (mDead)
|
||||
return NS_ERROR_FAILURE;
|
||||
if (!mThread)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
*result = PR_GetThreadPriority(mThread);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::SetPriority(PRThreadPriority value)
|
||||
{
|
||||
if (mDead)
|
||||
return NS_ERROR_FAILURE;
|
||||
if (!mThread)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
PR_SetThreadPriority(mThread, value);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::Interrupt()
|
||||
{
|
||||
if (mDead)
|
||||
return NS_ERROR_FAILURE;
|
||||
if (!mThread)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
PRStatus status = PR_Interrupt(mThread);
|
||||
return status == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::GetScope(PRThreadScope *result)
|
||||
{
|
||||
if (mDead)
|
||||
return NS_ERROR_FAILURE;
|
||||
if (!mThread)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
*result = PR_GetThreadScope(mThread);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::GetState(PRThreadState *result)
|
||||
{
|
||||
if (mDead)
|
||||
return NS_ERROR_FAILURE;
|
||||
if (!mThread)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
*result = PR_GetThreadState(mThread);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::GetPRThread(PRThread* *result)
|
||||
{
|
||||
if (mDead) {
|
||||
*result = nsnull;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*result = mThread;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::Init(nsIRunnable* runnable,
|
||||
PRUint32 stackSize,
|
||||
PRThreadPriority priority,
|
||||
PRThreadScope scope,
|
||||
PRThreadState state)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(runnable);
|
||||
if (mRunnable)
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
|
||||
mRunnable = runnable;
|
||||
|
||||
if (mStartLock)
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
|
||||
mStartLock = PR_NewLock();
|
||||
if (mStartLock == nsnull) {
|
||||
mRunnable = nsnull;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
NS_ADDREF_THIS(); // released in nsThread::Exit
|
||||
if (state == PR_JOINABLE_THREAD)
|
||||
NS_ADDREF_THIS(); // released in nsThread::Join
|
||||
|
||||
PR_Lock(mStartLock);
|
||||
mDead = PR_FALSE;
|
||||
mThread = PR_CreateThread(PR_USER_THREAD, Main, this,
|
||||
priority, scope, state, stackSize);
|
||||
/* As soon as we PR_Unlock(mStartLock), if mThread was successfully
|
||||
* created, it could run and exit very quickly. In which case, it
|
||||
* would null mThread and therefore if we check if (mThread) we could
|
||||
* confuse a successfully created, yet already exited thread with
|
||||
* OOM - failure to create the thread. So instead we store a local thr
|
||||
* which we check to see if we really failed to create the thread.
|
||||
*/
|
||||
PRThread *thr = mThread;
|
||||
PR_Unlock(mStartLock);
|
||||
|
||||
if (thr == nsnull) {
|
||||
mDead = PR_TRUE; // otherwise cleared in nsThread::Exit
|
||||
mRunnable = nsnull; // otherwise cleared in nsThread::Main(when done)
|
||||
PR_DestroyLock(mStartLock);
|
||||
mStartLock = nsnull;
|
||||
NS_RELEASE_THIS(); // otherwise released in nsThread::Exit
|
||||
if (state == PR_JOINABLE_THREAD)
|
||||
NS_RELEASE_THIS(); // otherwise released in nsThread::Join
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
|
||||
("nsIThread %p created\n", this));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute nsIThread currentThread; */
|
||||
NS_IMETHODIMP
|
||||
nsThread::GetCurrentThread(nsIThread * *aCurrentThread)
|
||||
{
|
||||
return GetIThread(PR_GetCurrentThread(), aCurrentThread);
|
||||
}
|
||||
|
||||
/* void sleep (in PRUint32 msec); */
|
||||
NS_IMETHODIMP
|
||||
nsThread::Sleep(PRUint32 msec)
|
||||
{
|
||||
if (PR_GetCurrentThread() != mThread)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (PR_Sleep(PR_MillisecondsToInterval(msec)) != PR_SUCCESS)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_COM nsresult
|
||||
NS_NewThread(nsIThread* *result,
|
||||
nsIRunnable* runnable,
|
||||
PRUint32 stackSize,
|
||||
PRThreadState state,
|
||||
PRThreadPriority priority,
|
||||
PRThreadScope scope)
|
||||
{
|
||||
nsresult rv;
|
||||
nsThread* thread = new nsThread();
|
||||
if (thread == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(thread);
|
||||
|
||||
rv = thread->Init(runnable, stackSize, priority, scope, state);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(thread);
|
||||
return rv;
|
||||
}
|
||||
|
||||
*result = thread;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_COM nsresult
|
||||
NS_NewThread(nsIThread* *result,
|
||||
PRUint32 stackSize,
|
||||
PRThreadState state,
|
||||
PRThreadPriority priority,
|
||||
PRThreadScope scope)
|
||||
{
|
||||
nsThread* thread = new nsThread();
|
||||
if (thread == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(thread);
|
||||
*result = thread;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsresult
|
||||
nsThread::RegisterThreadSelf()
|
||||
nsThread::Init()
|
||||
{
|
||||
PRStatus status;
|
||||
// spawn thread and wait until it is fully setup
|
||||
nsThreadStartInfo *si = new nsThreadStartInfo(this);
|
||||
if (!si)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(si);
|
||||
|
||||
if (kIThreadSelfIndex == 0) {
|
||||
status = PR_NewThreadPrivateIndex(&kIThreadSelfIndex, Exit);
|
||||
if (status != PR_SUCCESS) return NS_ERROR_FAILURE;
|
||||
}
|
||||
mActive = PR_TRUE;
|
||||
mThread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, si, PR_PRIORITY_NORMAL,
|
||||
PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
|
||||
if (!mThread) {
|
||||
NS_RELEASE(si);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
status = PR_SetThreadPrivate(kIThreadSelfIndex, this);
|
||||
if (status != PR_SUCCESS) return NS_ERROR_FAILURE;
|
||||
// Wait for thread to call ThreadManager::SetCurrentThread
|
||||
{
|
||||
nsAutoMonitor mon(si->mMon);
|
||||
while (!si->mInitialized)
|
||||
mon.Wait();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
NS_RELEASE(si);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsThread::WaitUntilReadyToStartMain()
|
||||
nsresult
|
||||
nsThread::InitCurrentThread()
|
||||
{
|
||||
PR_Lock(mStartLock);
|
||||
PR_Unlock(mStartLock);
|
||||
PR_DestroyLock(mStartLock);
|
||||
mStartLock = nsnull;
|
||||
mActive = PR_TRUE;
|
||||
mThread = PR_GetCurrentThread();
|
||||
|
||||
nsThreadManager::get()->SetCurrentThread(this, nsnull);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_COM nsresult
|
||||
nsIThread::GetCurrent(nsIThread* *result)
|
||||
PRBool
|
||||
nsThread::PutTask(nsIRunnable *task, PRUint32 dispatchFlags)
|
||||
{
|
||||
return GetIThread(PR_GetCurrentThread(), result);
|
||||
PRBool rv = mTasks.PutTask(task);
|
||||
if (!rv)
|
||||
return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIThreadObserver> obs;
|
||||
{
|
||||
nsAutoLock lock(mObserverLock);
|
||||
obs = mObserver;
|
||||
}
|
||||
if (obs)
|
||||
obs->OnNewTask(this, dispatchFlags);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_COM nsresult
|
||||
nsIThread::GetIThread(PRThread* prthread, nsIThread* *result)
|
||||
NS_IMETHODIMP
|
||||
nsThread::Dispatch(nsIRunnable *runnable, PRUint32 flags)
|
||||
{
|
||||
PRStatus status;
|
||||
nsThread* thread;
|
||||
NS_ENSURE_STATE(mThread);
|
||||
|
||||
if (nsThread::kIThreadSelfIndex == 0) {
|
||||
status = PR_NewThreadPrivateIndex(&nsThread::kIThreadSelfIndex, nsThread::Exit);
|
||||
if (status != PR_SUCCESS) return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (flags == DISPATCH_NORMAL) {
|
||||
PutTask(runnable, flags);
|
||||
} else if (flags & DISPATCH_SYNC) {
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsThreadManager::get()->GetCurrentThread(getter_AddRefs(thread));
|
||||
NS_ENSURE_STATE(thread);
|
||||
|
||||
thread = (nsThread*)PR_GetThreadPrivate(nsThread::kIThreadSelfIndex);
|
||||
if (thread == nsnull) {
|
||||
// if the current thread doesn't have an nsIThread associated
|
||||
// with it, make one
|
||||
thread = new nsThread();
|
||||
if (thread == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(thread); // released by Exit
|
||||
thread->SetPRThread(prthread);
|
||||
nsresult rv = thread->RegisterThreadSelf();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
NS_ADDREF(thread);
|
||||
*result = thread;
|
||||
return NS_OK;
|
||||
nsRefPtr<nsThreadSyncDispatch> task = new nsThreadSyncDispatch(runnable);
|
||||
PutTask(task, flags);
|
||||
|
||||
while (task->IsPending())
|
||||
thread->RunNextTask(nsIThread::RUN_NORMAL);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_COM nsresult
|
||||
nsIThread::SetMainThread()
|
||||
NS_IMETHODIMP
|
||||
nsThread::IsOnCurrentThread(PRBool *result)
|
||||
{
|
||||
// strictly speaking, it could be set twice. but practically speaking,
|
||||
// it's almost certainly an error if it is
|
||||
if (gMainThread != 0) {
|
||||
NS_ERROR("Setting main thread twice?");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return GetCurrent(&gMainThread);
|
||||
*result = (PR_GetCurrentThread() == mThread);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_COM nsresult
|
||||
nsIThread::GetMainThread(nsIThread **result)
|
||||
NS_IMETHODIMP
|
||||
nsThread::GetName(nsACString &result)
|
||||
{
|
||||
NS_ASSERTION(result, "bad result pointer");
|
||||
if (gMainThread == 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
*result = gMainThread;
|
||||
NS_ADDREF(gMainThread);
|
||||
return NS_OK;
|
||||
result = mName; // no need to lock since this never changes
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_COM PRBool
|
||||
nsIThread::IsMainThread()
|
||||
{
|
||||
if (gMainThread == 0)
|
||||
return PR_TRUE;
|
||||
|
||||
PRThread *theMainThread;
|
||||
gMainThread->GetPRThread(&theMainThread);
|
||||
return theMainThread == PR_GetCurrentThread();
|
||||
}
|
||||
|
||||
void
|
||||
NS_IMETHODIMP
|
||||
nsThread::Shutdown()
|
||||
{
|
||||
if (gMainThread) {
|
||||
// XXX nspr doesn't seem to be calling the main thread's destructor
|
||||
// callback, so let's help it out:
|
||||
nsThread::Exit(NS_STATIC_CAST(nsThread*, gMainThread));
|
||||
nsrefcnt cnt;
|
||||
NS_RELEASE2(gMainThread, cnt);
|
||||
NS_WARN_IF_FALSE(cnt == 0, "Main thread being held past XPCOM shutdown.");
|
||||
gMainThread = nsnull;
|
||||
|
||||
kIThreadSelfIndex = 0;
|
||||
}
|
||||
NS_ENSURE_STATE(mThread);
|
||||
NS_ENSURE_STATE(PR_GetCurrentThread() != mThread);
|
||||
|
||||
// shutdown task queue
|
||||
nsCOMPtr<nsIRunnable> task = new nsThreadShutdownTask(this);
|
||||
if (!task)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
PutTask(task, NS_DISPATCH_NORMAL);
|
||||
|
||||
// XXX we could still end up with other tasks being added after the shutdown task
|
||||
|
||||
PR_JoinThread(mThread);
|
||||
mThread = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
NS_IMETHODIMP
|
||||
nsThread::RunNextTask(PRUint32 flags)
|
||||
{
|
||||
NS_ENSURE_STATE(PR_GetCurrentThread() == mThread);
|
||||
NS_ENSURE_STATE(mActive);
|
||||
NS_ENSURE_ARG(flags == RUN_NORMAL || flags == RUN_NO_WAIT);
|
||||
|
||||
nsCOMPtr<nsIThreadObserver> obs;
|
||||
{
|
||||
nsAutoLock lock(mObserverLock);
|
||||
obs = mObserver;
|
||||
}
|
||||
|
||||
if (obs)
|
||||
obs->OnBeforeRunNextTask(this, flags);
|
||||
|
||||
nsCOMPtr<nsIRunnable> task;
|
||||
if (flags == RUN_NORMAL) {
|
||||
if (obs)
|
||||
obs->OnWaitNextTask(this, flags);
|
||||
mTasks.WaitPendingTask(getter_AddRefs(task));
|
||||
} else {
|
||||
mTasks.GetPendingTask(getter_AddRefs(task));
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (task) {
|
||||
task->Run();
|
||||
} else if (flags & RUN_NO_WAIT) {
|
||||
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
if (obs)
|
||||
obs->OnAfterRunNextTask(this, flags, rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::GetPriority(PRInt32 *priority)
|
||||
{
|
||||
*priority = mPriority;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::SetPriority(PRInt32 priority)
|
||||
{
|
||||
NS_ENSURE_STATE(mThread);
|
||||
|
||||
// NSPR defines the following four thread priorities:
|
||||
// PR_PRIORITY_LOW
|
||||
// PR_PRIORITY_NORMAL
|
||||
// PR_PRIORITY_HIGH
|
||||
// PR_PRIORITY_URGENT
|
||||
// We map the priority values defined on nsISupportsPriority to these values.
|
||||
|
||||
mPriority = priority;
|
||||
|
||||
PRThreadPriority pri;
|
||||
if (mPriority <= PRIORITY_HIGHEST) {
|
||||
pri = PR_PRIORITY_URGENT;
|
||||
} else if (mPriority < PRIORITY_NORMAL) {
|
||||
pri = PR_PRIORITY_HIGH;
|
||||
} else if (mPriority > PRIORITY_NORMAL) {
|
||||
pri = PR_PRIORITY_LOW;
|
||||
} else {
|
||||
pri = PR_PRIORITY_NORMAL;
|
||||
}
|
||||
PR_SetThreadPriority(mThread, pri);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::AdjustPriority(PRInt32 delta)
|
||||
{
|
||||
return SetPriority(mPriority + delta);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::GetObserver(nsIThreadObserver **obs)
|
||||
{
|
||||
nsAutoLock lock(mObserverLock);
|
||||
NS_ADDREF(*obs = mObserver);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::SetObserver(nsIThreadObserver *obs)
|
||||
{
|
||||
nsAutoLock lock(mObserverLock);
|
||||
mObserver = obs;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::HasPendingTask(PRBool *result)
|
||||
{
|
||||
*result = mTasks.HasPendingTask();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@@ -12,18 +13,18 @@
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
@@ -33,60 +34,53 @@
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK *****
|
||||
* This Original Code has been modified by IBM Corporation.
|
||||
* Modifications made by IBM described herein are
|
||||
* Copyright (c) International Business Machines
|
||||
* Corporation, 2000
|
||||
*
|
||||
* Modifications to Mozilla code or documentation
|
||||
* identified per MPL Section 3.3
|
||||
*
|
||||
* Date Modified by Description of modification
|
||||
* 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2
|
||||
*/
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsThread_h__
|
||||
#define nsThread_h__
|
||||
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsIThreadInternal.h"
|
||||
#include "nsISupportsPriority.h"
|
||||
#include "nsTaskQueue.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsThread : public nsIThread
|
||||
// A native thread
|
||||
class nsThread : public nsIThreadInternal, public nsISupportsPriority
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDISPATCHTARGET
|
||||
NS_DECL_NSITHREAD
|
||||
NS_DECL_NSITHREADINTERNAL
|
||||
NS_DECL_NSISUPPORTSPRIORITY
|
||||
|
||||
// nsIThread methods:
|
||||
NS_DECL_NSITHREAD
|
||||
|
||||
// nsThread methods:
|
||||
nsThread();
|
||||
nsThread(const nsACString &name);
|
||||
|
||||
nsresult RegisterThreadSelf();
|
||||
void SetPRThread(PRThread* thread) { mThread = thread; }
|
||||
void WaitUntilReadyToStartMain();
|
||||
// Initialize this as a wrapper for a new PRThread.
|
||||
nsresult Init();
|
||||
|
||||
static void PR_CALLBACK Main(void* arg);
|
||||
static void PR_CALLBACK Exit(void* arg);
|
||||
static void PR_CALLBACK Shutdown();
|
||||
|
||||
static PRUintn kIThreadSelfIndex;
|
||||
|
||||
static NS_METHOD
|
||||
Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr);
|
||||
// Initialize this as a wrapper for the current PRThread.
|
||||
nsresult InitCurrentThread();
|
||||
|
||||
private:
|
||||
~nsThread();
|
||||
friend class nsThreadShutdownTask;
|
||||
|
||||
protected:
|
||||
PRThread* mThread;
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
PRBool mDead;
|
||||
PRLock* mStartLock;
|
||||
~nsThread();
|
||||
|
||||
PR_STATIC_CALLBACK(void) ThreadFunc(void *arg);
|
||||
|
||||
// Wrapper for nsTaskQueue::PutTask
|
||||
PRBool PutTask(nsIRunnable *task, PRUint32 dispatchFlags);
|
||||
|
||||
PRLock *mObserverLock;
|
||||
nsCOMPtr<nsIThreadObserver> mObserver;
|
||||
|
||||
nsTaskQueue mTasks;
|
||||
nsCString mName;
|
||||
PRInt32 mPriority;
|
||||
PRThread *mThread;
|
||||
PRIntn mActive;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // nsThread_h__
|
||||
#endif // nsThread_h__
|
||||
|
||||
210
mozilla/xpcom/threads/nsThreadManager.cpp
Normal file
210
mozilla/xpcom/threads/nsThreadManager.cpp
Normal file
@@ -0,0 +1,210 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsThreadManager.h"
|
||||
#include "nsThread.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
PR_STATIC_CALLBACK(void)
|
||||
ReleaseObject(void *data)
|
||||
{
|
||||
NS_STATIC_CAST(nsISupports *, data)->Release();
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(PLDHashOperator)
|
||||
AppendAndRemoveThread(const nsACString &key, nsCOMPtr<nsIThread> &thread,
|
||||
void *arg)
|
||||
{
|
||||
nsCOMArray<nsIThread> *threads =
|
||||
NS_STATIC_CAST(nsCOMArray<nsIThread> *, arg);
|
||||
threads->AppendObject(thread);
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsThreadManager nsThreadManager::sInstance;
|
||||
|
||||
// statically allocated instance
|
||||
NS_IMETHODIMP_(nsrefcnt) nsThreadManager::AddRef() { return 2; }
|
||||
NS_IMETHODIMP_(nsrefcnt) nsThreadManager::Release() { return 1; }
|
||||
NS_IMPL_QUERY_INTERFACE1_CI(nsThreadManager, nsIThreadManager)
|
||||
NS_IMPL_CI_INTERFACE_GETTER1(nsThreadManager, nsIThreadManager)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
nsThreadManager::Init()
|
||||
{
|
||||
if (!mThreads.Init())
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (PR_NewThreadPrivateIndex(&mCurThreadIndex, ReleaseObject) == PR_FAILURE)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Setup "main" thread
|
||||
nsRefPtr<nsThread> mainThread = new nsThread(NS_LITERAL_CSTRING("main"));
|
||||
if (!mainThread)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
mainThread->InitCurrentThread();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsThreadManager::Shutdown()
|
||||
{
|
||||
NS_ASSERTION(IsMainThread(), "shutdown not called from main thread");
|
||||
|
||||
// We move the threads from the hashtable to a list, so that we avoid
|
||||
// holding the hashtable lock while calling nsIThread::Shutdown.
|
||||
|
||||
nsCOMArray<nsIThread> threads;
|
||||
mThreads.Enumerate(AppendAndRemoveThread, &threads);
|
||||
|
||||
// Shutdown all background threads.
|
||||
for (PRInt32 i = 0; i < threads.Count(); ++i) {
|
||||
nsIThread *thread = threads.ObjectAt(i);
|
||||
|
||||
PRBool isMainThread = PR_FALSE;
|
||||
thread->IsOnCurrentThread(&isMainThread);
|
||||
if (!isMainThread)
|
||||
thread->Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadManager::NewThread(const nsACString &name, nsIThread **result)
|
||||
{
|
||||
// make sure name is unique
|
||||
|
||||
nsThread *thr = new nsThread(name);
|
||||
if (!thr)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(thr);
|
||||
|
||||
nsresult rv = thr->Init();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(thr);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// At this point, we expect that the thread has been registered in mThread;
|
||||
// however, it is possible that it could have also been replaced by now, so
|
||||
// we cannot really assert that it was added.
|
||||
|
||||
*result = thr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadManager::GetThread(const nsACString &name, nsIThread **result)
|
||||
{
|
||||
mThreads.Get(name, result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadManager::GetMainThread(nsIThread **result)
|
||||
{
|
||||
mThreads.Get(NS_LITERAL_CSTRING("main"), result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadManager::GetCurrentThread(nsIThread **result)
|
||||
{
|
||||
// read thread local storage
|
||||
void *data = PR_GetThreadPrivate(mCurThreadIndex);
|
||||
if (!data) {
|
||||
*result = nsnull;
|
||||
} else {
|
||||
NS_ADDREF(*result = NS_STATIC_CAST(nsIThread *, data));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadManager::SetCurrentThread(nsIThread *thread, nsIThread **result)
|
||||
{
|
||||
nsCOMPtr<nsIThread> curr;
|
||||
GetCurrentThread(getter_AddRefs(curr));
|
||||
|
||||
nsCString name;
|
||||
if (thread) {
|
||||
thread->GetName(name);
|
||||
|
||||
// make sure thread name is unique
|
||||
nsCOMPtr<nsIThread> temp;
|
||||
GetThread(name, getter_AddRefs(temp));
|
||||
|
||||
if (temp && temp != curr) {
|
||||
NS_NOTREACHED("thread name is not unique");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
mThreads.Put(name, thread);
|
||||
|
||||
NS_ADDREF(thread); // for TLS entry
|
||||
} else {
|
||||
curr->GetName(name);
|
||||
mThreads.Remove(name);
|
||||
}
|
||||
|
||||
// write thread local storage
|
||||
PR_SetThreadPrivate(mCurThreadIndex, thread);
|
||||
|
||||
if (result) {
|
||||
*result = nsnull;
|
||||
curr.swap(*result);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadManager::IsMainThread(PRBool *result)
|
||||
{
|
||||
nsCOMPtr<nsIThread> mainThread;
|
||||
GetMainThread(getter_AddRefs(mainThread));
|
||||
NS_ENSURE_STATE(mainThread);
|
||||
|
||||
return mainThread->IsOnCurrentThread(result);
|
||||
}
|
||||
98
mozilla/xpcom/threads/nsThreadManager.h
Normal file
98
mozilla/xpcom/threads/nsThreadManager.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsThreadManager_h__
|
||||
#define nsThreadManager_h__
|
||||
|
||||
#include "nsIThreadManager.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
|
||||
class nsIRunnable;
|
||||
|
||||
class nsThreadManager : public nsIThreadManager
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITHREADMANAGER
|
||||
|
||||
static nsThreadManager *get() {
|
||||
return &sInstance;
|
||||
}
|
||||
|
||||
nsresult Init();
|
||||
|
||||
// Shutdown all threads. This function should only be called on the main
|
||||
// thread of the application process.
|
||||
void Shutdown();
|
||||
|
||||
static PRBool IsMainThread() {
|
||||
PRBool result;
|
||||
get()->IsMainThread(&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static nsresult NewThread(const nsACString &name, nsIRunnable *runnable,
|
||||
nsIThread **result) {
|
||||
nsresult rv = get()->NewThread(name, result);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = (*result)->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
return rv;
|
||||
}
|
||||
|
||||
private:
|
||||
nsThreadManager() : mCurThreadIndex(0) {}
|
||||
~nsThreadManager() {}
|
||||
|
||||
static nsThreadManager sInstance;
|
||||
|
||||
nsInterfaceHashtableMT<nsCStringHashKey, nsIThread> mThreads;
|
||||
PRUintn mCurThreadIndex; // thread-local-storage index
|
||||
};
|
||||
|
||||
#define NS_THREADMANAGER_CLASSNAME "nsThreadManager"
|
||||
#define NS_THREADMANAGER_CONTRACTID "@mozilla.org/thread-manager;1"
|
||||
#define NS_THREADMANAGER_CID \
|
||||
{ /* 7a4204c6-e45a-4c37-8ebb-6709a22c917c */ \
|
||||
0x7a4204c6, \
|
||||
0xe45a, \
|
||||
0x4c37, \
|
||||
{0x8e, 0xbb, 0x67, 0x09, 0xa2, 0x2c, 0x91, 0x7c} \
|
||||
}
|
||||
|
||||
#endif // nsThreadManager_h__
|
||||
@@ -41,11 +41,10 @@
|
||||
#include "nsTimerImpl.h"
|
||||
#include "TimerThread.h"
|
||||
#include "nsAutoLock.h"
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsVoidArray.h"
|
||||
|
||||
#include "nsIEventQueue.h"
|
||||
|
||||
#include "nsThreadManager.h"
|
||||
#include "nsRunnable.h"
|
||||
#include "prmem.h"
|
||||
|
||||
static PRInt32 gGenerator = 0;
|
||||
@@ -150,7 +149,7 @@ nsTimerImpl::nsTimerImpl() :
|
||||
mTimeout(0)
|
||||
{
|
||||
// XXXbsmedberg: shouldn't this be in Init()?
|
||||
nsIThread::GetCurrent(getter_AddRefs(mCallingThread));
|
||||
nsThreadManager::get()->GetCurrentThread(getter_AddRefs(mCallingThread));
|
||||
|
||||
mCallback.c = nsnull;
|
||||
|
||||
@@ -428,28 +427,45 @@ void nsTimerImpl::Fire()
|
||||
}
|
||||
|
||||
|
||||
struct TimerEventType : public PLEvent {
|
||||
PRInt32 mGeneration;
|
||||
class nsTimerEvent : public nsRunnable {
|
||||
public:
|
||||
NS_IMETHOD Run();
|
||||
|
||||
nsTimerEvent(nsTimerImpl *timer, PRInt32 generation)
|
||||
: mTimer(timer), mGeneration(generation) {
|
||||
// timer is already addref'd for us
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TIMERS
|
||||
PRIntervalTime mInitTime;
|
||||
#endif
|
||||
|
||||
private:
|
||||
~nsTimerEvent() {
|
||||
#ifdef DEBUG
|
||||
if (mTimer)
|
||||
NS_WARNING("leaking reference to nsTimerImpl");
|
||||
#endif
|
||||
}
|
||||
|
||||
nsTimerImpl *mTimer;
|
||||
PRInt32 mGeneration;
|
||||
};
|
||||
|
||||
|
||||
PR_STATIC_CALLBACK(void*) handleTimerEvent(PLEvent* aEvent)
|
||||
NS_IMETHODIMP nsTimerEvent::Run()
|
||||
{
|
||||
TimerEventType *event = NS_STATIC_CAST(TimerEventType*, aEvent);
|
||||
nsRefPtr<nsTimerImpl> timer;
|
||||
timer.swap(mTimer);
|
||||
|
||||
nsTimerImpl* timer = NS_STATIC_CAST(nsTimerImpl*, event->owner);
|
||||
if (event->mGeneration != timer->GetGeneration())
|
||||
return nsnull;
|
||||
if (mGeneration != timer->GetGeneration())
|
||||
return NS_OK;
|
||||
|
||||
#ifdef DEBUG_TIMERS
|
||||
if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
|
||||
PRIntervalTime now = PR_IntervalNow();
|
||||
PR_LOG(gTimerLog, PR_LOG_DEBUG,
|
||||
("[this=%p] time between PostTimerEvent() and Fire(): %dms\n",
|
||||
event->owner, PR_IntervalToMilliseconds(now - event->mInitTime)));
|
||||
this, PR_IntervalToMilliseconds(now - mInitTime)));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -460,43 +476,27 @@ PR_STATIC_CALLBACK(void*) handleTimerEvent(PLEvent* aEvent)
|
||||
NS_ASSERTION(gManager, "Global Thread Manager is null!");
|
||||
if (gManager)
|
||||
gManager->AddIdleTimer(timer);
|
||||
return nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
timer->Fire();
|
||||
|
||||
return nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(void) destroyTimerEvent(PLEvent* aEvent)
|
||||
{
|
||||
TimerEventType *event = NS_STATIC_CAST(TimerEventType*, aEvent);
|
||||
|
||||
nsTimerImpl *timer = NS_STATIC_CAST(nsTimerImpl*, event->owner);
|
||||
NS_RELEASE(timer);
|
||||
PR_DELETE(event);
|
||||
}
|
||||
|
||||
|
||||
void nsTimerImpl::PostTimerEvent()
|
||||
{
|
||||
// XXX we may want to reuse the PLEvent in the case of repeating timers.
|
||||
TimerEventType* event;
|
||||
|
||||
// construct
|
||||
event = PR_NEW(TimerEventType);
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
// initialize
|
||||
PL_InitEvent((PLEvent*)event, this, handleTimerEvent, destroyTimerEvent);
|
||||
// XXX we may want to reuse this nsTimerEvent in the case of repeating timers.
|
||||
|
||||
// Since TimerThread addref'd 'this' for us, we don't need to addref here.
|
||||
// We will release in destroyMyEvent. We do need to copy the generation
|
||||
// number from this timer into the event, so we can avoid firing a timer
|
||||
// that was re-initialized after being canceled.
|
||||
event->mGeneration = mGeneration;
|
||||
// We will release in destroyMyEvent. We need to copy the generation number
|
||||
// from this timer into the event, so we can avoid firing a timer that was
|
||||
// re-initialized after being canceled.
|
||||
|
||||
nsTimerEvent* event = new nsTimerEvent(this, mGeneration);
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
#ifdef DEBUG_TIMERS
|
||||
if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
|
||||
@@ -512,18 +512,7 @@ void nsTimerImpl::PostTimerEvent()
|
||||
gThread->AddTimer(this);
|
||||
}
|
||||
|
||||
PRThread *thread;
|
||||
nsresult rv = mCallingThread->GetPRThread(&thread);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Dropping timer event because thread is dead");
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEventQueue> queue;
|
||||
if (gThread)
|
||||
gThread->mEventQueueService->GetThreadEventQueue(thread, getter_AddRefs(queue));
|
||||
if (queue)
|
||||
queue->PostEvent(event);
|
||||
mCallingThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void nsTimerImpl::SetDelayInternal(PRUint32 aDelay)
|
||||
@@ -614,7 +603,7 @@ nsresult nsTimerManager::AddIdleTimer(nsITimer* timer)
|
||||
|
||||
NS_IMETHODIMP nsTimerManager::FireNextIdleTimer()
|
||||
{
|
||||
if (!gFireOnIdle || !nsIThread::IsMainThread()) {
|
||||
if (!gFireOnIdle || !nsThreadManager::IsMainThread()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,6 @@ public:
|
||||
|
||||
private:
|
||||
~nsTimerImpl();
|
||||
|
||||
nsresult InitCommon(PRUint32 aType, PRUint32 aDelay);
|
||||
|
||||
void ReleaseCallback()
|
||||
|
||||
Reference in New Issue
Block a user