mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 08:12:05 +00:00
Bug 622728 - Add NS_NewRunnableMethodWithArg. r=bsmedberg
This commit is contained in:
parent
ab4de2a416
commit
77d1d37b73
@ -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;
|
||||
|
@ -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); }
|
||||
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
|
||||
|
146
xpcom/tests/TestThreadUtils.cpp
Normal file
146
xpcom/tests/TestThreadUtils.cpp
Normal 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;
|
||||
}
|
@ -78,6 +78,7 @@ CPP_UNIT_TESTS += [
|
||||
'TestRefPtr.cpp',
|
||||
'TestTArray.cpp',
|
||||
'TestTextFormatter.cpp',
|
||||
'TestThreadUtils.cpp'
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_MEMORY']:
|
||||
|
Loading…
Reference in New Issue
Block a user