mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-26 23:23:33 +00:00
Bug 443877 - "Need a way to point timers at a different event target". r=bsmedberg.
This commit is contained in:
parent
7950ffdb7c
commit
b4b173d212
@ -80,6 +80,7 @@ CPPSRCS = \
|
||||
TestRegistrationOrder.cpp \
|
||||
TestProxies.cpp \
|
||||
TestThreadPoolListener.cpp \
|
||||
TestTimers.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifndef MOZ_ENABLE_LIBXUL
|
||||
@ -142,6 +143,7 @@ CPP_UNIT_TESTS = \
|
||||
TestServMgr \
|
||||
TestTextFormatter \
|
||||
TestThreadPoolListener \
|
||||
TestTimers \
|
||||
$(NULL)
|
||||
|
||||
ifndef MOZ_ENABLE_LIBXUL
|
||||
|
182
xpcom/tests/TestTimers.cpp
Normal file
182
xpcom/tests/TestTimers.cpp
Normal file
@ -0,0 +1,182 @@
|
||||
/* -*- 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 Timer 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 "nsIThread.h"
|
||||
#include "nsITimer.h"
|
||||
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "prinrval.h"
|
||||
#include "prmon.h"
|
||||
|
||||
typedef nsresult(*TestFuncPtr)();
|
||||
|
||||
class AutoTestThread
|
||||
{
|
||||
public:
|
||||
AutoTestThread() {
|
||||
nsCOMPtr<nsIThread> newThread;
|
||||
nsresult rv = NS_NewThread(getter_AddRefs(newThread));
|
||||
NS_ENSURE_SUCCESS(rv,);
|
||||
|
||||
newThread.swap(mThread);
|
||||
}
|
||||
|
||||
~AutoTestThread() {
|
||||
mThread->Shutdown();
|
||||
}
|
||||
|
||||
operator nsDerivedSafe<nsIThread>*() const {
|
||||
return mThread;
|
||||
}
|
||||
|
||||
nsDerivedSafe<nsIThread>* operator->() const {
|
||||
return mThread;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
};
|
||||
|
||||
class AutoCreateAndDestroyMonitor
|
||||
{
|
||||
public:
|
||||
AutoCreateAndDestroyMonitor() {
|
||||
mMonitor = nsAutoMonitor::NewMonitor("TestTimers::AutoMon");
|
||||
NS_ASSERTION(mMonitor, "Out of memory!");
|
||||
}
|
||||
|
||||
~AutoCreateAndDestroyMonitor() {
|
||||
if (mMonitor) {
|
||||
nsAutoMonitor::DestroyMonitor(mMonitor);
|
||||
}
|
||||
}
|
||||
|
||||
operator PRMonitor*() {
|
||||
return mMonitor;
|
||||
}
|
||||
|
||||
private:
|
||||
PRMonitor* mMonitor;
|
||||
};
|
||||
|
||||
class TimerCallback : public nsITimerCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
TimerCallback(nsIThread** aThreadPtr, PRMonitor* aMonitor)
|
||||
: mThreadPtr(aThreadPtr), mMonitor(aMonitor) { }
|
||||
|
||||
NS_IMETHOD Notify(nsITimer* aTimer) {
|
||||
nsCOMPtr<nsIThread> current(do_GetCurrentThread());
|
||||
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
NS_ASSERTION(!*mThreadPtr, "Timer called back more than once!");
|
||||
*mThreadPtr = current;
|
||||
|
||||
mon.Notify();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
nsIThread** mThreadPtr;
|
||||
PRMonitor* mMonitor;
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(TimerCallback, nsITimerCallback)
|
||||
|
||||
nsresult
|
||||
TestTargetedTimers()
|
||||
{
|
||||
AutoCreateAndDestroyMonitor newMon;
|
||||
NS_ENSURE_TRUE(newMon, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
AutoTestThread testThread;
|
||||
NS_ENSURE_TRUE(testThread, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsIEventTarget* target = static_cast<nsIEventTarget*>(testThread);
|
||||
|
||||
rv = timer->SetTarget(target);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsIThread* notifiedThread = nsnull;
|
||||
|
||||
nsCOMPtr<nsITimerCallback> callback =
|
||||
new TimerCallback(¬ifiedThread, newMon);
|
||||
NS_ENSURE_TRUE(callback, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = timer->InitWithCallback(callback, PR_MillisecondsToInterval(2000),
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoMonitor mon(newMon);
|
||||
while (!notifiedThread) {
|
||||
mon.Wait();
|
||||
}
|
||||
NS_ENSURE_TRUE(notifiedThread == testThread, NS_ERROR_FAILURE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
ScopedXPCOM xpcom("TestTimers");
|
||||
NS_ENSURE_FALSE(xpcom.failed(), 1);
|
||||
|
||||
static TestFuncPtr testsToRun[] = {
|
||||
TestTargetedTimers
|
||||
};
|
||||
static PRUint32 testCount = sizeof(testsToRun) / sizeof(testsToRun[0]);
|
||||
|
||||
for (PRUint32 i = 0; i < testCount; i++) {
|
||||
nsresult rv = testsToRun[i]();
|
||||
NS_ENSURE_SUCCESS(rv, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -40,6 +40,7 @@
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIObserver;
|
||||
interface nsIEventTarget;
|
||||
|
||||
%{C++
|
||||
/**
|
||||
@ -82,7 +83,7 @@ interface nsITimerCallback : nsISupports
|
||||
* delay to avoid the overhead of destroying and creating a timer. It is not
|
||||
* necessary to cancel the timer in that case.
|
||||
*/
|
||||
[scriptable, uuid(436a83fa-b396-11d9-bcfa-00112478d626)]
|
||||
[scriptable, uuid(193fc37a-8aa4-4d29-aa57-1acd87c26b66)]
|
||||
interface nsITimer : nsISupports
|
||||
{
|
||||
/* Timer types */
|
||||
@ -187,6 +188,12 @@ interface nsITimer : nsISupports
|
||||
* The nsITimerCallback object passed to initWithCallback.
|
||||
*/
|
||||
readonly attribute nsITimerCallback callback;
|
||||
|
||||
/**
|
||||
* The nsIEventTarget where the callback will be dispatched. Note that this
|
||||
* target may only be set before the call to one of the init methods above.
|
||||
*/
|
||||
attribute nsIEventTarget target;
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
@ -147,7 +147,7 @@ nsTimerImpl::nsTimerImpl() :
|
||||
mTimeout(0)
|
||||
{
|
||||
// XXXbsmedberg: shouldn't this be in Init()?
|
||||
mCallingThread = do_GetCurrentThread();
|
||||
mEventTarget = static_cast<nsIEventTarget*>(NS_GetCurrentThread());
|
||||
|
||||
mCallback.c = nsnull;
|
||||
|
||||
@ -347,6 +347,26 @@ NS_IMETHODIMP nsTimerImpl::GetCallback(nsITimerCallback **aCallback)
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsTimerImpl::GetTarget(nsIEventTarget** aTarget)
|
||||
{
|
||||
NS_IF_ADDREF(*aTarget = mEventTarget);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsTimerImpl::SetTarget(nsIEventTarget* aTarget)
|
||||
{
|
||||
NS_ENSURE_TRUE(mCallbackType == CALLBACK_TYPE_UNKNOWN,
|
||||
NS_ERROR_ALREADY_INITIALIZED);
|
||||
|
||||
if (aTarget)
|
||||
mEventTarget = aTarget;
|
||||
else
|
||||
mEventTarget = static_cast<nsIEventTarget*>(NS_GetCurrentThread());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
void nsTimerImpl::Fire()
|
||||
{
|
||||
if (mCanceled)
|
||||
@ -522,7 +542,7 @@ nsresult nsTimerImpl::PostTimerEvent()
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = mCallingThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
nsresult rv = mEventTarget->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv) && gThread)
|
||||
gThread->RemoveTimer(this);
|
||||
return rv;
|
||||
|
@ -44,7 +44,7 @@
|
||||
//#define FORCE_PR_LOG /* Allow logging in the release build */
|
||||
|
||||
#include "nsITimer.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsIObserver.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
@ -121,7 +121,7 @@ private:
|
||||
NS_RELEASE(mCallback.o);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> mCallingThread;
|
||||
nsCOMPtr<nsIEventTarget> mEventTarget;
|
||||
|
||||
void * mClosure;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user