Bug 622728 - Add NS_NewRunnableMethodWithArg. r=bsmedberg

This commit is contained in:
Valentin Gosu 2013-09-06 21:29:24 -04:00
parent 6eee8c4679
commit 14afabb9f3
4 changed files with 232 additions and 30 deletions

View File

@ -25,25 +25,6 @@ struct ConnStatus
nsString creationSts;
};
class DashConnStatusRunnable: public nsRunnable
{
public:
DashConnStatusRunnable(Dashboard * aDashboard, ConnStatus aStatus)
: mDashboard(aDashboard)
{
mStatus.creationSts = aStatus.creationSts;
}
NS_IMETHODIMP Run()
{
return mDashboard->GetConnectionStatus(mStatus);
}
private:
ConnStatus mStatus;
Dashboard * mDashboard;
};
Dashboard::Dashboard()
{
mEnableLogging = false;
@ -604,7 +585,8 @@ Dashboard::RequestConnection(const nsACString& aHost, uint32_t aPort,
if (NS_FAILED(rv)) {
ConnStatus status;
CopyASCIItoUTF16(GetErrorString(rv), status.creationSts);
nsCOMPtr<nsIRunnable> event = new DashConnStatusRunnable(this, status);
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethodWithArg<ConnStatus>(this, &Dashboard::GetConnectionStatus, status);
mConn.thread->Dispatch(event, NS_DISPATCH_NORMAL);
return rv;
}
@ -674,7 +656,7 @@ Dashboard::OnTransportStatus(nsITransport *aTransport, nsresult aStatus,
ConnStatus status;
CopyASCIItoUTF16(GetErrorString(aStatus), status.creationSts);
nsCOMPtr<nsIRunnable> event = new DashConnStatusRunnable(this, status);
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethodWithArg<ConnStatus>(this, &Dashboard::GetConnectionStatus, status);
mConn.thread->Dispatch(event, NS_DISPATCH_NORMAL);
return NS_OK;
@ -693,7 +675,7 @@ Dashboard::Notify(nsITimer *timer)
ConnStatus status;
status.creationSts.Assign(NS_LITERAL_STRING("NS_ERROR_NET_TIMEOUT"));
nsCOMPtr<nsIRunnable> event = new DashConnStatusRunnable(this, status);
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethodWithArg<ConnStatus>(this, &Dashboard::GetConnectionStatus, status);
mConn.thread->Dispatch(event, NS_DISPATCH_NORMAL);
return NS_OK;

View File

@ -310,16 +310,29 @@ public:
typedef typename ReturnTypeEnforcer<ReturnType>::ReturnTypeIsSafe check;
};
template <class ClassType, bool Owning>
template <class ClassType, typename Arg, bool Owning>
struct nsRunnableMethodReceiver {
ClassType *mObj;
nsRunnableMethodReceiver(ClassType *obj) : mObj(obj) { NS_IF_ADDREF(mObj); }
~nsRunnableMethodReceiver() { Revoke(); }
Arg mArg;
nsRunnableMethodReceiver(ClassType *obj, Arg arg)
: mObj(obj)
, mArg(arg)
{ NS_IF_ADDREF(mObj); }
~nsRunnableMethodReceiver() { Revoke(); }
void Revoke() { NS_IF_RELEASE(mObj); }
};
template <class ClassType, bool Owning>
struct nsRunnableMethodReceiver<ClassType, void, Owning> {
ClassType *mObj;
nsRunnableMethodReceiver(ClassType *obj) : mObj(obj)
{ NS_IF_ADDREF(mObj); }
~nsRunnableMethodReceiver() { Revoke(); }
void Revoke() { NS_IF_RELEASE(mObj); }
};
template <class ClassType>
struct nsRunnableMethodReceiver<ClassType, false> {
struct nsRunnableMethodReceiver<ClassType, void, false> {
ClassType *mObj;
nsRunnableMethodReceiver(ClassType *obj) : mObj(obj) {}
void Revoke() { mObj = nullptr; }
@ -327,28 +340,70 @@ struct nsRunnableMethodReceiver<ClassType, false> {
template <typename Method, bool Owning> struct nsRunnableMethodTraits;
template <class C, typename R, typename A, bool Owning>
struct nsRunnableMethodTraits<R (C::*)(A), Owning> {
typedef C class_type;
typedef R return_type;
typedef A arg_type;
typedef nsRunnableMethod<C, R, Owning> base_type;
};
template <class C, typename R, bool Owning>
struct nsRunnableMethodTraits<R (C::*)(), Owning> {
typedef C class_type;
typedef R return_type;
typedef void arg_type;
typedef nsRunnableMethod<C, R, Owning> base_type;
};
#ifdef NS_HAVE_STDCALL
template <class C, typename R, typename A, bool Owning>
struct nsRunnableMethodTraits<R (__stdcall C::*)(A), Owning> {
typedef C class_type;
typedef R return_type;
typedef A arg_type;
typedef nsRunnableMethod<C, R, Owning> base_type;
};
template <class C, typename R, bool Owning>
struct nsRunnableMethodTraits<R (NS_STDCALL C::*)(), Owning> {
typedef C class_type;
typedef R return_type;
typedef void arg_type;
typedef nsRunnableMethod<C, R, Owning> base_type;
};
#endif
template <typename Method, bool Owning>
template <typename Method, typename Arg, bool Owning>
class nsRunnableMethodImpl
: public nsRunnableMethodTraits<Method, Owning>::base_type
{
typedef typename nsRunnableMethodTraits<Method, Owning>::class_type ClassType;
nsRunnableMethodReceiver<ClassType, Owning> mReceiver;
nsRunnableMethodReceiver<ClassType, Arg, Owning> mReceiver;
Method mMethod;
public:
nsRunnableMethodImpl(ClassType *obj,
Method method,
Arg arg)
: mReceiver(obj, arg)
, mMethod(method)
{}
NS_IMETHOD Run() {
if (MOZ_LIKELY(mReceiver.mObj))
((*mReceiver.mObj).*mMethod)(mReceiver.mArg);
return NS_OK;
}
void Revoke() {
mReceiver.Revoke();
}
};
template <typename Method, bool Owning>
class nsRunnableMethodImpl<Method, void, Owning>
: public nsRunnableMethodTraits<Method, Owning>::base_type
{
typedef typename nsRunnableMethodTraits<Method, Owning>::class_type ClassType;
nsRunnableMethodReceiver<ClassType, void, Owning> mReceiver;
Method mMethod;
public:
@ -383,14 +438,32 @@ template<typename PtrType, typename Method>
typename nsRunnableMethodTraits<Method, true>::base_type*
NS_NewRunnableMethod(PtrType ptr, Method method)
{
return new nsRunnableMethodImpl<Method, true>(ptr, method);
return new nsRunnableMethodImpl<Method, void, true>(ptr, method);
}
template<typename T>
struct dependent_type
{
typedef T type;
};
// Similar to NS_NewRunnableMethod. Call like so:
// Type myArg;
// nsCOMPtr<nsIRunnable> event =
// NS_NewRunnableMethodWithArg<Type>(myObject, &MyClass::HandleEvent, myArg);
template<typename Arg, typename Method, typename PtrType>
typename nsRunnableMethodTraits<Method, true>::base_type*
NS_NewRunnableMethodWithArg(PtrType ptr, Method method, typename dependent_type<Arg>::type arg)
{
return new nsRunnableMethodImpl<Method, Arg, true>(ptr, method, arg);
}
template<typename PtrType, typename Method>
typename nsRunnableMethodTraits<Method, false>::base_type*
NS_NewNonOwningRunnableMethod(PtrType ptr, Method method)
{
return new nsRunnableMethodImpl<Method, false>(ptr, method);
return new nsRunnableMethodImpl<Method, void, false>(ptr, method);
}
#endif // XPCOM_GLUE_AVOID_NSPR

View File

@ -0,0 +1,146 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http:mozilla.org/MPL/2.0/. */
#include "TestHarness.h"
#include "nsThreadUtils.h"
enum {
TEST_CALL_VOID_ARG_VOID_RETURN,
TEST_CALL_VOID_ARG_NONVOID_RETURN,
TEST_CALL_NONVOID_ARG_VOID_RETURN,
TEST_CALL_NONVOID_ARG_NONVOID_RETURN,
TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT,
TEST_CALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT,
#ifdef HAVE_STDCALL
TEST_STDCALL_VOID_ARG_VOID_RETURN,
TEST_STDCALL_VOID_ARG_NONVOID_RETURN,
TEST_STDCALL_NONVOID_ARG_VOID_RETURN,
TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN,
TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT,
#endif
MAX_TESTS
};
bool gRunnableExecuted[MAX_TESTS];
class nsFoo : public nsISupports {
NS_DECL_ISUPPORTS
nsresult DoFoo(bool* aBool) {
*aBool = true;
return NS_OK;
}
virtual ~nsFoo() {}
};
NS_IMPL_ISUPPORTS0(nsFoo)
class nsBar : public nsISupports {
NS_DECL_ISUPPORTS
virtual ~nsBar() {}
void DoBar1(void) {
gRunnableExecuted[TEST_CALL_VOID_ARG_VOID_RETURN] = true;
}
nsresult DoBar2(void) {
gRunnableExecuted[TEST_CALL_VOID_ARG_NONVOID_RETURN] = true;
return NS_OK;
}
void DoBar3(nsFoo* aFoo) {
aFoo->DoFoo(&gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN]);
}
nsresult DoBar4(nsFoo* aFoo) {
return aFoo->DoFoo(&gRunnableExecuted[TEST_CALL_NONVOID_ARG_NONVOID_RETURN]);
}
void DoBar5(nsFoo* aFoo) {
if (aFoo)
gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true;
}
nsresult DoBar6(char* aFoo) {
if (strlen(aFoo))
gRunnableExecuted[TEST_CALL_NONVOID_ARG_NONVOID_RETURN_EXPLICIT] = true;
return NS_OK;
}
#ifdef HAVE_STDCALL
void __stdcall DoBar1std(void) {
gRunnableExecuted[TEST_STDCALL_VOID_ARG_VOID_RETURN] = true;
}
nsresult __stdcall DoBar2std(void) {
gRunnableExecuted[TEST_STDCALL_VOID_ARG_NONVOID_RETURN] = true;
return NS_OK;
}
void __stdcall DoBar3std(nsFoo* aFoo) {
aFoo->DoFoo(&gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_VOID_RETURN]);
}
nsresult __stdcall DoBar4std(nsFoo* aFoo) {
return aFoo->DoFoo(&gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_NONVOID_RETURN]);
}
void __stdcall DoBar5std(nsFoo* aFoo) {
if (aFoo)
gRunnableExecuted[TEST_STDCALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true;
}
nsresult __stdcall DoBar6std(char* aFoo) {
if (strlen(aFoo))
gRunnableExecuted[TEST_CALL_NONVOID_ARG_VOID_RETURN_EXPLICIT] = true;
return NS_OK;
}
#endif
};
NS_IMPL_ISUPPORTS0(nsBar)
int main(int argc, char** argv)
{
ScopedXPCOM xpcom("ThreadUtils");
NS_ENSURE_FALSE(xpcom.failed(), 1);
memset(gRunnableExecuted, false, MAX_TESTS * sizeof(bool));
// Scope the smart ptrs so that the runnables need to hold on to whatever they need
{
nsRefPtr<nsFoo> foo = new nsFoo();
nsRefPtr<nsBar> bar = new nsBar();
// This pointer will be freed at the end of the block
// Do not dereference this pointer in the runnable method!
nsFoo * rawFoo = new nsFoo();
// Read only string. Dereferencing in runnable method to check this works.
char* message = (char*)"Test message";
NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar1));
NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar2));
NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr<nsFoo> >
(bar, &nsBar::DoBar3, foo));
NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr<nsFoo> >
(bar, &nsBar::DoBar4, foo));
NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<nsFoo*>(bar, &nsBar::DoBar5, rawFoo));
NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<char*>(bar, &nsBar::DoBar6, message));
#ifdef HAVE_STDCALL
NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar1std));
NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar2std));
NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr<nsFoo> >
(bar, &nsBar::DoBar3std, foo));
NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr<nsFoo> >
(bar, &nsBar::DoBar4std, foo));
NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<nsFoo*>(bar, &nsBar::DoBar5std, rawFoo));
NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<char*>(bar, &nsBar::DoBar6std, message));
#endif
delete rawFoo;
}
// Spin the event loop
NS_ProcessPendingEvents(nullptr);
int result = 0;
for (uint32_t i = 0; i < MAX_TESTS; i++) {
if (gRunnableExecuted[i]) {
passed("Test %d passed",i);
} else {
fail("Error in test %d", i);
result = 1;
}
}
return result;
}

View File

@ -78,6 +78,7 @@ CPP_UNIT_TESTS += [
'TestRefPtr.cpp',
'TestTArray.cpp',
'TestTextFormatter.cpp',
'TestThreadUtils.cpp'
]
if CONFIG['MOZ_MEMORY']: