mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-05 08:35:26 +00:00
797 lines
21 KiB
C++
797 lines
21 KiB
C++
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/* ***** 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 Proxy Test Code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Ben Turner <bent.mozilla@gmail.com>.
|
|
* Portions created by the Initial Developer are Copyright (C) 2008
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* 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 "TestHarness.h"
|
|
|
|
#include "nsIEventTarget.h"
|
|
#include "nsIProxyObjectManager.h"
|
|
#include "nsIRunnable.h"
|
|
#include "nsIThread.h"
|
|
#include "nsIThreadPool.h"
|
|
|
|
#include "nsAutoPtr.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsComponentManagerUtils.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "nsXPCOMCIDInternal.h"
|
|
#include "prlog.h"
|
|
|
|
#include "mozilla/Mutex.h"
|
|
using namespace mozilla;
|
|
|
|
typedef nsresult(*TestFuncPtr)();
|
|
|
|
#define TEST_NAME "TestProxies"
|
|
|
|
#ifdef PR_LOGGING
|
|
static PRLogModuleInfo* sLog = PR_NewLogModule(TEST_NAME);
|
|
#endif
|
|
#define LOG(args) PR_LOG(sLog, PR_LOG_DEBUG, args)
|
|
|
|
static nsIThread* gMainThread = nsnull;
|
|
static nsIThread* gTestThread = nsnull;
|
|
|
|
static nsresult
|
|
GetProxyForObject(nsIEventTarget* aTarget,
|
|
REFNSIID aIID,
|
|
nsISupports* aObj,
|
|
PRInt32 aProxyType,
|
|
void** aProxyObject)
|
|
{
|
|
nsresult rv;
|
|
nsCOMPtr<nsIProxyObjectManager> proxyObjMgr =
|
|
do_GetService(NS_XPCOMPROXY_CONTRACTID, &rv);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
return proxyObjMgr->GetProxyForObject(aTarget, aIID, aObj, aProxyType,
|
|
aProxyObject);
|
|
}
|
|
|
|
class nsAutoTestThread
|
|
{
|
|
public:
|
|
nsAutoTestThread(nsIThread** aGlobal = nsnull)
|
|
: mGlobal(aGlobal)
|
|
{
|
|
nsCOMPtr<nsIThread> newThread;
|
|
nsresult rv = NS_NewThread(getter_AddRefs(newThread));
|
|
NS_ENSURE_SUCCESS(rv,);
|
|
|
|
rv = newThread->GetPRThread(&mNativeThread);
|
|
NS_ENSURE_SUCCESS(rv,);
|
|
|
|
LOG(("Created test thread [0x%p]", static_cast<void*>(mNativeThread)));
|
|
|
|
newThread.swap(mThread);
|
|
|
|
if (mGlobal)
|
|
*mGlobal = mThread;
|
|
}
|
|
|
|
~nsAutoTestThread()
|
|
{
|
|
if (mGlobal)
|
|
*mGlobal = nsnull;
|
|
|
|
#ifdef PR_LOGGING
|
|
void* nativeThread = static_cast<void*>(mNativeThread);
|
|
#endif
|
|
|
|
LOG(("Shutting down test thread [0x%p]", nativeThread));
|
|
mThread->Shutdown();
|
|
LOG(("Test thread successfully shut down [0x%p]", nativeThread));
|
|
}
|
|
|
|
operator nsIThread*() const
|
|
{
|
|
return mThread;
|
|
}
|
|
|
|
nsIThread* operator->() const
|
|
{
|
|
return mThread;
|
|
}
|
|
|
|
private:
|
|
nsIThread** mGlobal;
|
|
nsCOMPtr<nsIThread> mThread;
|
|
PRThread* mNativeThread;
|
|
};
|
|
|
|
class SimpleRunnable : public nsRunnable
|
|
{
|
|
public:
|
|
SimpleRunnable(const char* aType = "SimpleRunnable")
|
|
: mType(aType)
|
|
{ }
|
|
|
|
NS_IMETHOD Run()
|
|
{
|
|
LOG(("%s::Run() [0x%p]", mType,
|
|
static_cast<void*>(static_cast<nsISupports*>(this))));
|
|
return NS_OK;
|
|
}
|
|
private:
|
|
const char* mType;
|
|
};
|
|
|
|
class TestTargetThreadRunnable : public SimpleRunnable
|
|
{
|
|
public:
|
|
TestTargetThreadRunnable(nsIThread* aTarget)
|
|
: SimpleRunnable("TestTargetThreadRunnable"),
|
|
mTarget(aTarget)
|
|
{ }
|
|
|
|
NS_IMETHOD Run()
|
|
{
|
|
nsresult rv = SimpleRunnable::Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsIThread> currentThread(do_GetCurrentThread());
|
|
if (currentThread != mTarget) {
|
|
NS_ERROR("Proxy sent call to wrong thread!");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
private:
|
|
nsCOMPtr<nsIThread> mTarget;
|
|
};
|
|
|
|
class ChainedProxyRunnable : public SimpleRunnable
|
|
{
|
|
public:
|
|
ChainedProxyRunnable(nsIThread* aSecondTarget,
|
|
nsIThread* aThirdTarget = nsnull)
|
|
: SimpleRunnable("ChainedProxyRunnable"), mSecondTarget(aSecondTarget),
|
|
mThirdTarget(aThirdTarget)
|
|
{ }
|
|
|
|
NS_IMETHOD Run()
|
|
{
|
|
nsresult rv = SimpleRunnable::Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsRefPtr<SimpleRunnable> runnable = mThirdTarget ?
|
|
new ChainedProxyRunnable(mThirdTarget) :
|
|
new SimpleRunnable();
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
nsCOMPtr<nsIRunnable> proxy;
|
|
rv = GetProxyForObject(mSecondTarget, NS_GET_IID(nsIRunnable), runnable,
|
|
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
|
getter_AddRefs(proxy));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = proxy->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
private:
|
|
nsCOMPtr<nsIThread> mSecondTarget;
|
|
nsCOMPtr<nsIThread> mThirdTarget;
|
|
};
|
|
|
|
class IncrementingRunnable : public SimpleRunnable
|
|
{
|
|
public:
|
|
IncrementingRunnable(PRUint32* aCounter, Mutex* aLock = nsnull)
|
|
: SimpleRunnable("IncrementingRunnable"), mCounter(aCounter), mLock(aLock)
|
|
{ }
|
|
|
|
NS_IMETHOD Run()
|
|
{
|
|
nsresult rv = SimpleRunnable::Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (mLock)
|
|
mLock->Lock();
|
|
|
|
(*mCounter)++;
|
|
|
|
if (mLock)
|
|
mLock->Unlock();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
private:
|
|
PRUint32* mCounter;
|
|
Mutex* mLock;
|
|
};
|
|
|
|
class NonThreadsafeRunnable : public nsIRunnable
|
|
{
|
|
public:
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NonThreadsafeRunnable(PRUint32* aCounter,
|
|
const char* aType = "NonThreadsafeRunnable")
|
|
: mCounter(aCounter),
|
|
mType(aType)
|
|
{ }
|
|
|
|
virtual ~NonThreadsafeRunnable()
|
|
{ };
|
|
|
|
NS_IMETHOD Run()
|
|
{
|
|
LOG(("%s::Run() [0x%p]", mType,
|
|
static_cast<void*>(static_cast<nsISupports*>(this))));
|
|
|
|
(*mCounter)++;
|
|
return NS_OK;
|
|
}
|
|
|
|
private:
|
|
PRUint32* mCounter;
|
|
const char* mType;
|
|
};
|
|
|
|
NS_IMPL_ISUPPORTS1(NonThreadsafeRunnable, nsIRunnable)
|
|
|
|
class MainThreadRunnable : public NonThreadsafeRunnable
|
|
{
|
|
public:
|
|
NS_DECL_ISUPPORTS_INHERITED
|
|
|
|
MainThreadRunnable(PRUint32* aCounter)
|
|
: NonThreadsafeRunnable(aCounter, "MainThreadRunnable")
|
|
{
|
|
if (!NS_IsMainThread()) {
|
|
NS_ERROR("Not running on the main thread!");
|
|
}
|
|
}
|
|
|
|
virtual ~MainThreadRunnable()
|
|
{
|
|
if (!NS_IsMainThread()) {
|
|
NS_ERROR("Not running on the main thread!");
|
|
}
|
|
}
|
|
|
|
NS_IMETHOD Run()
|
|
{
|
|
if (!NS_IsMainThread()) {
|
|
NS_ERROR("Not running on the main thread!");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsresult rv = NonThreadsafeRunnable::Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
return NS_OK;
|
|
}
|
|
};
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED0(MainThreadRunnable, NonThreadsafeRunnable)
|
|
|
|
class ProxyGetter : public nsRunnable
|
|
{
|
|
public:
|
|
ProxyGetter(nsIRunnable* aRunnable, nsIRunnable** retval)
|
|
: mRunnable(aRunnable), _retval(retval)
|
|
{ }
|
|
|
|
NS_IMETHOD Run()
|
|
{
|
|
*_retval = nsnull;
|
|
|
|
if (NS_IsMainThread()) {
|
|
NS_ERROR("Shouldn't be running on the main thread!");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsCOMPtr<nsIRunnable> proxy;
|
|
nsresult rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable),
|
|
mRunnable, NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
|
getter_AddRefs(proxy));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
proxy.forget(_retval);
|
|
return NS_OK;
|
|
}
|
|
|
|
private:
|
|
nsIRunnable* mRunnable;
|
|
nsIRunnable** _retval;
|
|
};
|
|
|
|
class RunnableGetter : public nsRunnable
|
|
{
|
|
public:
|
|
RunnableGetter(PRUint32* aCounter, nsIRunnable** retval)
|
|
: mCounter(aCounter), _retval(retval)
|
|
{ }
|
|
|
|
NS_IMETHOD Run()
|
|
{
|
|
*_retval = nsnull;
|
|
|
|
if (NS_IsMainThread()) {
|
|
NS_ERROR("Shouldn't be running on the main thread!");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsCOMPtr<nsIRunnable> runnable = new NonThreadsafeRunnable(mCounter);
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
runnable.forget(_retval);
|
|
return NS_OK;
|
|
}
|
|
|
|
private:
|
|
PRUint32* mCounter;
|
|
nsIRunnable** _retval;
|
|
};
|
|
|
|
nsresult
|
|
TestTargetThread()
|
|
{
|
|
LOG(("--- Running TestTargetThread ---"));
|
|
|
|
nsRefPtr<TestTargetThreadRunnable> runnable =
|
|
new TestTargetThreadRunnable(gMainThread);
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
nsCOMPtr<nsIRunnable> proxy;
|
|
nsresult rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable),
|
|
runnable, NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
|
getter_AddRefs(proxy));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = proxy->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
runnable = new TestTargetThreadRunnable(gTestThread);
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
rv = GetProxyForObject(gTestThread, NS_GET_IID(nsIRunnable), runnable,
|
|
NS_PROXY_SYNC | NS_PROXY_ALWAYS, getter_AddRefs(proxy));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = proxy->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
TestNonThreadsafeProxy()
|
|
{
|
|
LOG(("--- Running TestNonThreadsafeProxy 1 ---"));
|
|
|
|
// Make sure a non-threadsafe object and proxy to it (both created on the same
|
|
// thread) can be used on the same thread.
|
|
|
|
PRUint32 counter = 0;
|
|
nsCOMPtr<nsIRunnable> runnable(new MainThreadRunnable(&counter));
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
nsCOMPtr<nsIRunnable> proxy;
|
|
nsresult rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable),
|
|
runnable, NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
|
getter_AddRefs(proxy));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
for (PRUint32 otherCounter = 0; otherCounter < 5;) {
|
|
rv = gTestThread->Dispatch(proxy, NS_DISPATCH_SYNC);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
|
}
|
|
|
|
// Make sure a non-threadsafe object and proxy to it (both created on the same
|
|
// thread) can be used on a different thread.
|
|
|
|
LOG(("--- Running TestNonThreadsafeProxy 2 ---"));
|
|
|
|
counter = 0;
|
|
runnable = new NonThreadsafeRunnable(&counter);
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
rv = GetProxyForObject(gTestThread, NS_GET_IID(nsIRunnable),
|
|
runnable, NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
|
getter_AddRefs(proxy));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
runnable = nsnull;
|
|
|
|
for (PRUint32 otherCounter = 0; otherCounter < 5;) {
|
|
rv = proxy->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
|
}
|
|
|
|
NS_ENSURE_TRUE(counter == 5, NS_ERROR_FAILURE);
|
|
|
|
// Make sure a non-threadsafe object and proxy to it (created on different
|
|
// threads) can be used by any thread.
|
|
|
|
LOG(("--- Running TestNonThreadsafeProxy 3 ---"));
|
|
|
|
counter = 0;
|
|
proxy = nsnull;
|
|
|
|
runnable = new MainThreadRunnable(&counter);
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
nsCOMPtr<nsIRunnable> proxyGetter =
|
|
new ProxyGetter(runnable, getter_AddRefs(proxy));
|
|
NS_ENSURE_TRUE(proxyGetter, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
rv = gTestThread->Dispatch(proxyGetter, NS_DISPATCH_SYNC);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
NS_ENSURE_TRUE(proxy, NS_ERROR_FAILURE);
|
|
|
|
for (PRUint32 otherCounter = 0; otherCounter < 5;) {
|
|
rv = proxy->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
|
}
|
|
|
|
// Make sure a non-threadsafe object (created on thread 1) and proxy to it
|
|
// (created on thread 2) can be used by thread 3.
|
|
|
|
LOG(("--- Running TestNonThreadsafeProxy 4 ---"));
|
|
|
|
counter = 0;
|
|
proxy = nsnull;
|
|
runnable = nsnull;
|
|
|
|
nsCOMPtr<nsIRunnable> runnableGetter =
|
|
new RunnableGetter(&counter, getter_AddRefs(runnable));
|
|
NS_ENSURE_TRUE(runnableGetter, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
rv = gTestThread->Dispatch(runnableGetter, NS_DISPATCH_SYNC);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_FAILURE);
|
|
|
|
proxyGetter = new ProxyGetter(runnable, getter_AddRefs(proxy));
|
|
NS_ENSURE_TRUE(proxyGetter, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
nsAutoTestThread otherTestThread;
|
|
NS_ENSURE_TRUE(otherTestThread, NS_ERROR_FAILURE);
|
|
|
|
rv = otherTestThread->Dispatch(proxyGetter, NS_DISPATCH_SYNC);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
NS_ENSURE_TRUE(proxy, NS_ERROR_FAILURE);
|
|
|
|
for (PRUint32 otherCounter = 0; otherCounter < 5;) {
|
|
rv = proxy->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
TestChainedProxy()
|
|
{
|
|
LOG(("--- Running TestChainedProxy ---"));
|
|
|
|
nsRefPtr<ChainedProxyRunnable> runnable =
|
|
new ChainedProxyRunnable(gMainThread);
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
nsCOMPtr<nsIRunnable> proxy;
|
|
nsresult rv = GetProxyForObject(gTestThread, NS_GET_IID(nsIRunnable),
|
|
runnable, NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
|
getter_AddRefs(proxy));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// This will do a test->main call
|
|
rv = proxy->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
runnable = new ChainedProxyRunnable(gTestThread);
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable), runnable,
|
|
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
|
getter_AddRefs(proxy));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// This will do a main->test call
|
|
rv = proxy->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
runnable = new ChainedProxyRunnable(gMainThread);
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable), runnable,
|
|
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
|
getter_AddRefs(proxy));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// This will do a main->main call
|
|
rv = proxy->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
runnable = new ChainedProxyRunnable(gTestThread);
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
rv = GetProxyForObject(gTestThread, NS_GET_IID(nsIRunnable), runnable,
|
|
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
|
getter_AddRefs(proxy));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// This will do a test->test call
|
|
rv = proxy->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
runnable = new ChainedProxyRunnable(gMainThread, gTestThread);
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
rv = GetProxyForObject(gTestThread, NS_GET_IID(nsIRunnable), runnable,
|
|
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
|
getter_AddRefs(proxy));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// This will do a test->main->test call
|
|
rv = proxy->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
TestReleaseOfRealObjects()
|
|
{
|
|
LOG(("--- Running TestReleaseOfRealObjects ---"));
|
|
|
|
PRUint32 counter = 0, otherCounter = 0;
|
|
|
|
nsRefPtr<IncrementingRunnable> runnable(new IncrementingRunnable(&counter));
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
nsCOMPtr<nsIRunnable> proxy1;
|
|
nsresult rv = GetProxyForObject(gTestThread, NS_GET_IID(nsIRunnable),
|
|
runnable, NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
|
getter_AddRefs(proxy1));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsIRunnable> proxy2;
|
|
rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable), runnable,
|
|
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
|
getter_AddRefs(proxy2));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsIRunnable> proxy3;
|
|
rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable), runnable,
|
|
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
|
getter_AddRefs(proxy3));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
NS_ENSURE_FALSE(proxy1 == proxy2, NS_ERROR_FAILURE);
|
|
NS_ENSURE_TRUE(proxy2 == proxy3, NS_ERROR_FAILURE);
|
|
proxy3 = nsnull;
|
|
|
|
rv = proxy1->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
|
|
|
rv = proxy2->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
|
|
|
runnable = nsnull;
|
|
|
|
rv = proxy1->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
|
|
|
rv = proxy2->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
|
|
|
proxy1 = nsnull;
|
|
|
|
rv = proxy2->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
TestCurrentThreadProxy()
|
|
{
|
|
LOG(("--- Running TestCurrentThreadProxy ---"));
|
|
|
|
PRUint32 counter = 0, otherCounter = 0;
|
|
nsRefPtr<IncrementingRunnable> runnable(new IncrementingRunnable(&counter));
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
nsCOMPtr<nsIRunnable> proxy1;
|
|
nsresult rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable),
|
|
runnable, NS_PROXY_SYNC,
|
|
getter_AddRefs(proxy1));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsIRunnable> proxy2;
|
|
rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable), runnable,
|
|
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
|
getter_AddRefs(proxy2));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
NS_ENSURE_FALSE(proxy1 == proxy2, NS_ERROR_FAILURE);
|
|
|
|
nsCOMPtr<nsIRunnable> realRunnable(do_QueryInterface(runnable));
|
|
NS_ENSURE_TRUE(realRunnable, NS_ERROR_FAILURE);
|
|
|
|
NS_ENSURE_TRUE(static_cast<void*>(realRunnable) == static_cast<void*>(runnable),
|
|
NS_ERROR_FAILURE);
|
|
|
|
rv = proxy1->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
|
|
|
rv = proxy2->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
TestAsyncProxy()
|
|
{
|
|
LOG(("--- Running TestAsyncProxy ---"));
|
|
|
|
// Test async proxies to the current thread.
|
|
|
|
PRUint32 counter = 0;
|
|
nsRefPtr<SimpleRunnable> runnable(new IncrementingRunnable(&counter));
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
nsCOMPtr<nsIRunnable> proxy;
|
|
nsresult rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable),
|
|
runnable, NS_PROXY_ASYNC,
|
|
getter_AddRefs(proxy));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
runnable = nsnull;
|
|
|
|
for (PRUint32 i = 0; i < 5; i++) {
|
|
rv = proxy->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
|
|
while (counter < 5) {
|
|
rv = NS_ProcessPendingEvents(gMainThread, PR_SecondsToInterval(1));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
|
|
// Now test async proxies to another thread.
|
|
|
|
Mutex* counterLock = new Mutex("counterLock");
|
|
NS_ENSURE_TRUE(counterLock, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
counter = 0;
|
|
runnable = new IncrementingRunnable(&counter, counterLock);
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
rv = GetProxyForObject(gTestThread, NS_GET_IID(nsIRunnable), runnable,
|
|
NS_PROXY_ASYNC, getter_AddRefs(proxy));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
for (PRUint32 i = 0; i < 5; i++) {
|
|
rv = proxy->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
|
|
PRUint32 safeCounter = 0;
|
|
while (safeCounter < 5) {
|
|
rv = NS_ProcessPendingEvents(gMainThread, PR_SecondsToInterval(1));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
MutexAutoLock lock(*counterLock);
|
|
safeCounter = counter;
|
|
}
|
|
|
|
delete counterLock;
|
|
|
|
// Now test async proxies to another thread that create sync proxies to this
|
|
// thread.
|
|
|
|
runnable = new ChainedProxyRunnable(gMainThread);
|
|
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
rv = GetProxyForObject(gTestThread, NS_GET_IID(nsIRunnable),
|
|
runnable, NS_PROXY_ASYNC,
|
|
getter_AddRefs(proxy));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = proxy->Run();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// That was async, so make sure to wait for all the events on the test thread
|
|
// to be processed before we return. This is easy to do with an empty sync
|
|
// event.
|
|
nsCOMPtr<nsIRunnable> flusher = new nsRunnable();
|
|
NS_ENSURE_TRUE(flusher, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
LOG(("Flushing events on test thread"));
|
|
|
|
rv = gTestThread->Dispatch(flusher, NS_DISPATCH_SYNC);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
LOG(("Flushing events completed"));
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
ScopedXPCOM xpcom(TEST_NAME);
|
|
NS_ENSURE_FALSE(xpcom.failed(), 1);
|
|
|
|
nsCOMPtr<nsIThread> mainThread(do_GetMainThread());
|
|
NS_ENSURE_TRUE(mainThread, 1);
|
|
|
|
LOG(("Got main thread"));
|
|
gMainThread = mainThread;
|
|
|
|
nsAutoTestThread testThread(&gTestThread);
|
|
NS_ENSURE_TRUE(testThread, 1);
|
|
|
|
static TestFuncPtr testsToRun[] = {
|
|
TestTargetThread,
|
|
// TestNonThreadsafeProxy, /* Not currently supported! */
|
|
TestChainedProxy,
|
|
TestReleaseOfRealObjects,
|
|
TestCurrentThreadProxy,
|
|
TestAsyncProxy
|
|
};
|
|
static PRUint32 testCount = sizeof(testsToRun) / sizeof(testsToRun[0]);
|
|
|
|
for (PRUint32 i = 0; i < testCount; i++) {
|
|
nsresult rv = testsToRun[i]();
|
|
NS_ENSURE_SUCCESS(rv, 1);
|
|
}
|
|
|
|
LOG(("--- Finished all tests ---"));
|
|
return 0;
|
|
}
|