From c2fcce456ccb2e43ce83aca70b8d86996734cc71 Mon Sep 17 00:00:00 2001 From: "ramiro%netscape.com" Date: Fri, 16 Jul 1999 14:38:29 +0000 Subject: [PATCH] Prepare to move the timers out of gfx and into their little place in the world. NOT PART OF THE BUILD YET. --- timer/.cvsignore | 1 + timer/Makefile.in | 33 ++ timer/makefile.win | 22 + timer/public/.cvsignore | 1 + timer/public/MANIFEST | 6 + timer/public/Makefile.in | 37 ++ timer/public/makefile.win | 29 ++ timer/public/nsITimer.h | 102 +++++ timer/public/nsITimerCallback.h | 43 ++ timer/src/.cvsignore | 1 + timer/src/Makefile.in | 33 ++ timer/src/beos/.cvsignore | 1 + timer/src/beos/Makefile.in | 44 ++ timer/src/beos/nsTimer.cpp | 362 ++++++++++++++++ timer/src/mac/nsTimer.cpp | 357 +++++++++++++++ timer/src/makefile.win | 23 + timer/src/os2/.cvsignore | 1 + timer/src/os2/Makefile.in | 48 ++ timer/src/os2/nsTimerOS2.cpp | 601 ++++++++++++++++++++++++++ timer/src/os2/nsTimerOS2.h | 116 +++++ timer/src/photon/.cvsignore | 1 + timer/src/photon/Makefile.in | 44 ++ timer/src/photon/nsTimer.cpp | 264 +++++++++++ timer/src/rhapsody/.cvsignore | 1 + timer/src/rhapsody/Makefile.in | 44 ++ timer/src/rhapsody/nsTimer.cpp | 200 +++++++++ timer/src/unix/.cvsignore | 1 + timer/src/unix/Makefile.in | 42 ++ timer/src/unix/gtk/.cvsignore | 1 + timer/src/unix/gtk/Makefile.in | 47 ++ timer/src/unix/gtk/nsTimerGtk.cpp | 161 +++++++ timer/src/unix/gtk/nsTimerGtk.h | 67 +++ timer/src/unix/motif/.cvsignore | 1 + timer/src/unix/motif/Makefile.in | 47 ++ timer/src/unix/motif/nsTimerMotif.cpp | 152 +++++++ timer/src/unix/motif/nsTimerMotif.h | 66 +++ timer/src/unix/xlib/.cvsignore | 1 + timer/src/unix/xlib/Makefile.in | 47 ++ timer/src/unix/xlib/nsTimerXlib.cpp | 273 ++++++++++++ timer/src/unix/xlib/nsTimerXlib.h | 67 +++ timer/src/windows/makefile.win | 52 +++ timer/src/windows/nsTimer.cpp | 362 ++++++++++++++++ 42 files changed, 3802 insertions(+) create mode 100644 timer/.cvsignore create mode 100644 timer/Makefile.in create mode 100644 timer/makefile.win create mode 100644 timer/public/.cvsignore create mode 100644 timer/public/MANIFEST create mode 100644 timer/public/Makefile.in create mode 100644 timer/public/makefile.win create mode 100644 timer/public/nsITimer.h create mode 100644 timer/public/nsITimerCallback.h create mode 100644 timer/src/.cvsignore create mode 100644 timer/src/Makefile.in create mode 100644 timer/src/beos/.cvsignore create mode 100644 timer/src/beos/Makefile.in create mode 100644 timer/src/beos/nsTimer.cpp create mode 100644 timer/src/mac/nsTimer.cpp create mode 100644 timer/src/makefile.win create mode 100644 timer/src/os2/.cvsignore create mode 100644 timer/src/os2/Makefile.in create mode 100644 timer/src/os2/nsTimerOS2.cpp create mode 100644 timer/src/os2/nsTimerOS2.h create mode 100644 timer/src/photon/.cvsignore create mode 100644 timer/src/photon/Makefile.in create mode 100644 timer/src/photon/nsTimer.cpp create mode 100644 timer/src/rhapsody/.cvsignore create mode 100644 timer/src/rhapsody/Makefile.in create mode 100644 timer/src/rhapsody/nsTimer.cpp create mode 100644 timer/src/unix/.cvsignore create mode 100644 timer/src/unix/Makefile.in create mode 100644 timer/src/unix/gtk/.cvsignore create mode 100644 timer/src/unix/gtk/Makefile.in create mode 100644 timer/src/unix/gtk/nsTimerGtk.cpp create mode 100644 timer/src/unix/gtk/nsTimerGtk.h create mode 100644 timer/src/unix/motif/.cvsignore create mode 100644 timer/src/unix/motif/Makefile.in create mode 100644 timer/src/unix/motif/nsTimerMotif.cpp create mode 100644 timer/src/unix/motif/nsTimerMotif.h create mode 100644 timer/src/unix/xlib/.cvsignore create mode 100644 timer/src/unix/xlib/Makefile.in create mode 100644 timer/src/unix/xlib/nsTimerXlib.cpp create mode 100644 timer/src/unix/xlib/nsTimerXlib.h create mode 100644 timer/src/windows/makefile.win create mode 100644 timer/src/windows/nsTimer.cpp diff --git a/timer/.cvsignore b/timer/.cvsignore new file mode 100644 index 000000000000..f3c7a7c5da68 --- /dev/null +++ b/timer/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/timer/Makefile.in b/timer/Makefile.in new file mode 100644 index 000000000000..0fc8e2ab66a5 --- /dev/null +++ b/timer/Makefile.in @@ -0,0 +1,33 @@ +#!gmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +DIRS = public src + +#ifdef ENABLE_TESTS +#DIRS += tests +#endif + +include $(topsrcdir)/config/config.mk + +include $(topsrcdir)/config/rules.mk diff --git a/timer/makefile.win b/timer/makefile.win new file mode 100644 index 000000000000..1166b03f9140 --- /dev/null +++ b/timer/makefile.win @@ -0,0 +1,22 @@ +#!nmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH=.. + +DIRS= public src + +include <$(DEPTH)\config\rules.mak> diff --git a/timer/public/.cvsignore b/timer/public/.cvsignore new file mode 100644 index 000000000000..f3c7a7c5da68 --- /dev/null +++ b/timer/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/timer/public/MANIFEST b/timer/public/MANIFEST new file mode 100644 index 000000000000..92c048e7edc7 --- /dev/null +++ b/timer/public/MANIFEST @@ -0,0 +1,6 @@ +# +# This is a list of local files which get copied to the mozilla:dist:widget directory +# + +nsITimer.h +nsITimerCallback.h diff --git a/timer/public/Makefile.in b/timer/public/Makefile.in new file mode 100644 index 000000000000..ef9a555650cb --- /dev/null +++ b/timer/public/Makefile.in @@ -0,0 +1,37 @@ +#!gmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH=../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +EXPORTS = \ + nsITimer.h \ + nsITimerCallback.h \ + nsTimerCIID.h \ + $(NULL) + +EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) + +MODULE = timer + +include $(topsrcdir)/config/config.mk + +include $(topsrcdir)/config/rules.mk diff --git a/timer/public/makefile.win b/timer/public/makefile.win new file mode 100644 index 000000000000..80d654192fce --- /dev/null +++ b/timer/public/makefile.win @@ -0,0 +1,29 @@ +#!nmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +EXPORTS = \ + nsITimer.h \ + nsITimerCallback.h \ + $(NULL) + +MODULE=timer + +include <$(DEPTH)\config\rules.mak> + diff --git a/timer/public/nsITimer.h b/timer/public/nsITimer.h new file mode 100644 index 000000000000..55f071beb7d5 --- /dev/null +++ b/timer/public/nsITimer.h @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#ifndef nsITimer_h___ +#define nsITimer_h___ + +#include "nscore.h" +#include "nsISupports.h" + +class nsITimer; +class nsITimerCallback; + +// Implementations of nsITimer should be written such that there are no limitations +// on what can be called by the TimerCallbackFunc. On platforms like the Macintosh this +// means that callback functions must be called from the main event loop NOT from +// an interrupt. + +/// Signature of timer callback function +typedef void +(*nsTimerCallbackFunc) (nsITimer *aTimer, void *aClosure); + +/// Interface IID for nsITimer +#define NS_ITIMER_IID \ +{ 0x497eed20, 0xb740, 0x11d1, \ +{ 0x9b, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } } + +/** + * Timer class, used to invoke a function or method after a fixed + * millisecond interval. Note that this interface is subject to + * change! + */ +class nsITimer : public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ITIMER_IID) + + /** + * Initialize a timer to fire after the given millisecond interval. + * This version takes a function to call and a closure to pass to + * that function. + * + * @param aFunc - The function to invoke + * @param aClosure - an opaque pointer to pass to that function + * @param aRepeat - (Not yet implemented) One-shot or repeating + * @param aDelay - The millisecond interval + * @result - NS_OK if this operation was successful + */ + virtual nsresult Init(nsTimerCallbackFunc aFunc, + void *aClosure, +// PRBool aRepeat, + PRUint32 aDelay)=0; + + /** + * Initialize a timer to fire after the given millisecond interval. + * This version takes an interface of type nsITimerCallback. + * The Notify method of this method is invoked. + * + * @param aCallback - The interface to notify + * @param aRepeat - (Not yet implemented) One-shot or repeating + * @param aDelay - The millisecond interval + * @result - NS_OK if this operation was successful + */ + virtual nsresult Init(nsITimerCallback *aCallback, +// PRBool aRepeat, + PRUint32 aDelay)=0; + + /// Cancels the timeout + virtual void Cancel()=0; + + /// @return the millisecond delay of the timeout + virtual PRUint32 GetDelay()=0; + + /// Change the millisecond interval for the timeout + virtual void SetDelay(PRUint32 aDelay)=0; + + /// @return the opaque pointer + virtual void* GetClosure()=0; +}; + +/** Factory method for creating an nsITimer */ +extern +#ifdef XP_MAC // On the macintosh, this is built into the network library. +NS_NET +#else +NS_GFX +#endif +nsresult NS_NewTimer(nsITimer** aInstancePtrResult); + +#endif diff --git a/timer/public/nsITimerCallback.h b/timer/public/nsITimerCallback.h new file mode 100644 index 000000000000..801272104779 --- /dev/null +++ b/timer/public/nsITimerCallback.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#ifndef nsITimerCallback_h___ +#define nsITimerCallback_h___ + +#include "nscore.h" +#include "nsISupports.h" + +class nsITimer; + +/// Interface IID for nsITimerCallback +#define NS_ITIMERCALLBACK_IID \ +{ 0x5079b3a0, 0xb743, 0x11d1, \ +{ 0x9b, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } } + +/** + * Interface implemented by users of the nsITimer class. An instance + * of this interface is passed in when creating a timer. The Notify() + * method of that instance is invoked after the specified delay. + */ +class nsITimerCallback : public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ITIMERCALLBACK_IID) + + virtual void Notify(nsITimer *timer) = 0; +}; + +#endif diff --git a/timer/src/.cvsignore b/timer/src/.cvsignore new file mode 100644 index 000000000000..f3c7a7c5da68 --- /dev/null +++ b/timer/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/timer/src/Makefile.in b/timer/src/Makefile.in new file mode 100644 index 000000000000..bb95eb8f598a --- /dev/null +++ b/timer/src/Makefile.in @@ -0,0 +1,33 @@ +#!gmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifneq (,$(filter beos os2 rhapsody photon,$(OS_ARCH))) +DIRS = $(MOZ_GFX_TOOLKIT) +else +DIRS = unix +endif + +include $(topsrcdir)/config/rules.mk diff --git a/timer/src/beos/.cvsignore b/timer/src/beos/.cvsignore new file mode 100644 index 000000000000..f3c7a7c5da68 --- /dev/null +++ b/timer/src/beos/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/timer/src/beos/Makefile.in b/timer/src/beos/Makefile.in new file mode 100644 index 000000000000..5597f68375fa --- /dev/null +++ b/timer/src/beos/Makefile.in @@ -0,0 +1,44 @@ +#!gmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +LIBRARY_NAME = timer_beos_s + +MODULE=timer + +REQUIRES=xpcom + +CXXFLAGS += $(TK_CFLAGS) +INCLUDES += $(TK_CFLAGS) -I$(srcdir)/.. + +CPPSRCS = \ + nsTimer.cpp \ + $(NULL) + +MKSHLIB = +override NO_SHARED_LIB=1 +override NO_STATIC_LIB= + +include $(topsrcdir)/config/rules.mk diff --git a/timer/src/beos/nsTimer.cpp b/timer/src/beos/nsTimer.cpp new file mode 100644 index 000000000000..708819514880 --- /dev/null +++ b/timer/src/beos/nsTimer.cpp @@ -0,0 +1,362 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsITimer.h" +#include "nsITimerCallback.h" +#include "nsCRT.h" +#include "prlog.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static NS_DEFINE_IID(kITimerIID, NS_ITIMER_IID); + +struct ThreadInterfaceData +{ + void *data; + int32 sync; +}; + +static sem_id my_find_sem(const char *name) +{ + sem_id ret = B_ERROR; + + /* Get the sem_info for every sempahore in this team. */ + sem_info info; + int32 cookie = 0; + + while(get_next_sem_info(0, &cookie, &info) == B_OK) + if(strcmp(name, info.name) == 0) + { + ret = info.sem; + break; + } + + return ret; +} + + +class TimerImpl; +class TimerManager; + +class TimerManager : public BList +{ +public: + TimerManager(); + ~TimerManager(); + void AddRequest(TimerImpl *); + bool RemoveRequest(TimerImpl *); + +private: + BLocker mLocker; + sem_id mSyncSem; + thread_id mTimerThreadID; + bool mQuitRequested; + + static int32 sTimerThreadFunc(void *); + int32 TimerThreadFunc(); + TimerImpl *FirstRequest() { return (TimerImpl *)FirstItem(); } +}; + + +class TimerImpl : public nsITimer +{ + friend class TimerManager; +public: + TimerImpl(); + virtual ~TimerImpl(); + + virtual nsresult Init(nsTimerCallbackFunc aFunc, + void *aClosure, +// PRBool aRepeat, + PRUint32 aDelay); + + virtual nsresult Init(nsITimerCallback *aCallback, +// PRBool aRepeat, + PRUint32 aDelay); + + NS_DECL_ISUPPORTS + + virtual void Cancel(); + virtual PRUint32 GetDelay() { return mDelay; } + virtual void SetDelay(PRUint32); + virtual void* GetClosure() { return mClosure; } + + void FireTimeout(); + +private: + nsresult Init(PRUint32 aDelay); // Initialize the timer. + + bigtime_t mWhen; // Time when this request should be done + PRUint32 mDelay; // The delay set in Init() + nsTimerCallbackFunc mFunc; // The function to call back when expired + void *mClosure; // The argumnet to pass it. + nsITimerCallback *mCallback; // An interface to notify when expired. + bool mCanceled; + PRThread *mThread; +// PRBool mRepeat; // A repeat, not implemented yet. + +public: + static TimerManager sTimerManager; +}; + +TimerManager TimerImpl::sTimerManager; + +TimerManager::TimerManager() + : BList(40) +{ + mQuitRequested = false; + mSyncSem = create_sem(0, "timer sync"); + if(mSyncSem < 0) + debugger("Failed to create sem..."); + + mTimerThreadID = spawn_thread(&sTimerThreadFunc, "timer roster", B_URGENT_DISPLAY_PRIORITY, (void *)this); + if(mTimerThreadID < B_OK) + // is it the right way ? + debugger("Failed to spawn timer thread..."); + + resume_thread(mTimerThreadID); +} + +TimerManager::~TimerManager() +{ + // should we empty the list here and NS_RELEASE ? + mQuitRequested = true; + delete_sem(mSyncSem); + + int32 junk; + wait_for_thread(mTimerThreadID, &junk); +} + +void TimerManager::AddRequest(TimerImpl *inRequest) +{ + if(mLocker.Lock()) + { + NS_ADDREF(inRequest); // this is for the timer list + + // insert sorted into timer event list + int32 count = CountItems(); + int32 pos; + for(pos = 0; pos < count; pos++) + { + TimerImpl *entry = (TimerImpl *)ItemAtFast(pos); + if(entry->mWhen > inRequest->mWhen) + break; + } + AddItem(inRequest, pos); + + if(pos == 0) + // We need to wake the thread to wait on the newly added event + release_sem(mSyncSem); + + mLocker.Unlock(); + } +} + +bool TimerManager::RemoveRequest(TimerImpl *inRequest) +{ + bool found = false; + + if(mLocker.Lock()) + { + if(RemoveItem(inRequest)) + { + NS_RELEASE(inRequest); + found = true; + } + + mLocker.Unlock(); + } + + return found; +} + +int32 TimerManager::sTimerThreadFunc(void *inData) +{ + return ((TimerManager *)inData)->TimerThreadFunc(); +} + +int32 TimerManager::TimerThreadFunc() +{ + char portname[64]; + char semname[64]; + port_id eventport; + sem_id syncsem; + PRThread *cached = (PRThread *)-1; + + while(! mQuitRequested) + { + TimerImpl *tobj = 0; + + mLocker.Lock(); + + bigtime_t now = system_time(); + + // Fire expired pending requests + while((tobj = FirstRequest()) != 0 && tobj->mWhen <= now) + { + RemoveItem((int32)0); + mLocker.Unlock(); + + if(! tobj->mCanceled) + { + // fire it + if(tobj->mThread != cached) + { + sprintf(portname, "event%lx", tobj->mThread); + sprintf(semname, "sync%lx", tobj->mThread); + + eventport = find_port(portname); + syncsem = my_find_sem(semname); + cached = tobj->mThread; + } + + // call timer synchronously so we're sure tobj is alive + ThreadInterfaceData id; + id.data = tobj; + id.sync = true; + if(write_port(eventport, 'WMti', &id, sizeof(id)) == B_OK) + while(acquire_sem(syncsem) == B_INTERRUPTED) + ; + } + NS_RELEASE(tobj); + + mLocker.Lock(); + } + mLocker.Unlock(); + + if(acquire_sem_etc(mSyncSem, 1, B_ABSOLUTE_TIMEOUT, + tobj ? tobj->mWhen : B_INFINITE_TIMEOUT) == B_BAD_SEM_ID) + break; + } + + return B_OK; +} + +// +// TimerImpl +// +void TimerImpl::FireTimeout() +{ + if( ! mCanceled) + { + if(mFunc != NULL) + (*mFunc)(this, mClosure); // If there's a function, call it. + else if(mCallback != NULL) + mCallback->Notify(this); // But if there's an interface, notify it. + } +} + +TimerImpl::TimerImpl() +{ + NS_INIT_REFCNT(); + mFunc = 0; + mCallback = 0; + mDelay = 0; + mClosure = 0; + mWhen = 0; + mCanceled = false; +} + +TimerImpl::~TimerImpl() +{ + Cancel(); + NS_IF_RELEASE(mCallback); +} + +void TimerImpl::SetDelay(PRUint32 aDelay) +{ + mDelay = aDelay; + mWhen = system_time() + mDelay * 1000; + + NS_ADDREF(this); + if (TimerImpl::sTimerManager.RemoveRequest(this)) + TimerImpl::sTimerManager.AddRequest(this); +// NS_RELEASE(this); // ?*?*?*?* doesn't work... + Release(); // Is it the right way ? +} + +nsresult TimerImpl::Init(nsTimerCallbackFunc aFunc, void *aClosure, +// PRBool aRepeat, + PRUint32 aDelay) +{ + mFunc = aFunc; + mClosure = aClosure; + // mRepeat = aRepeat; + + return Init(aDelay); +} + +nsresult TimerImpl::Init(nsITimerCallback *aCallback, +// PRBool aRepeat, + PRUint32 aDelay) +{ + mCallback = aCallback; + NS_ADDREF(mCallback); + // mRepeat = aRepeat; + return Init(aDelay); +} + + +nsresult TimerImpl::Init(PRUint32 aDelay) +{ + mDelay = aDelay; + NS_ADDREF(this); // this is for clients of the timer + mWhen = system_time() + aDelay * 1000; + + mThread = PR_GetCurrentThread(); + + sTimerManager.AddRequest(this); + + return NS_OK; +} + +NS_IMPL_ISUPPORTS(TimerImpl, kITimerIID); + + +void TimerImpl::Cancel() +{ + mCanceled = true; + TimerImpl::sTimerManager.RemoveRequest(this); +} + +NS_BASE nsresult NS_NewTimer(nsITimer** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if(nsnull == aInstancePtrResult) + return NS_ERROR_NULL_POINTER; + + TimerImpl *timer = new TimerImpl(); + if(nsnull == timer) + return NS_ERROR_OUT_OF_MEMORY; + + return timer->QueryInterface(kITimerIID, (void **) aInstancePtrResult); +} + +void nsTimerExpired(void *aCallData) +{ + TimerImpl* timer = (TimerImpl *)aCallData; + timer->FireTimeout(); + NS_RELEASE(timer); +} diff --git a/timer/src/mac/nsTimer.cpp b/timer/src/mac/nsTimer.cpp new file mode 100644 index 000000000000..ab16b217fab8 --- /dev/null +++ b/timer/src/mac/nsTimer.cpp @@ -0,0 +1,357 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +// +// Mac implementation of the nsITimer interface +// + + + +#include "nsITimer.h" +#include "nsITimerCallback.h" +#include "prlog.h" +#include "nsRepeater.h" + +#include +#include + + + +#pragma mark class TimerImpl + +//======================================================================================== +class TimerImpl : public nsITimer +// TimerImpl implements nsITimer API +//======================================================================================== +{ + friend class TimerPeriodical; + + private: + nsTimerCallbackFunc mCallbackFunc; + nsITimerCallback * mCallbackObject; + void * mClosure; + PRUint32 mDelay; + PRUint32 mFireTime; // Timer should fire when TickCount >= this number + TimerImpl * mPrev; + TimerImpl * mNext; + + public: + + // constructors + + TimerImpl(); + + virtual ~TimerImpl(); + + NS_DECL_ISUPPORTS + + PRUint32 GetFireTime() const { return mFireTime; } + + void Fire(); + + // nsITimer overrides + + virtual nsresult Init(nsTimerCallbackFunc aFunc, + void *aClosure, + PRUint32 aDelay); + + virtual nsresult Init(nsITimerCallback *aCallback, + PRUint32 aDelay); + + virtual void Cancel(); + + virtual PRUint32 GetDelay(); + + virtual void SetDelay(PRUint32 aDelay); + + virtual void* GetClosure(); + +#if DEBUG + enum { + eGoodTimerSignature = 'Barf', + eDeletedTimerSignature = 'oops' + }; + + Boolean IsGoodTimer() const { return (mSignature == eGoodTimerSignature); } +#endif + + private: + // Calculates mFireTime too + void SetDelaySelf( PRUint32 aDelay ); + +#if DEBUG + UInt32 mSignature; +#endif + +}; + +#pragma mark class TimerPeriodical + +//======================================================================================== +class TimerPeriodical : public Repeater +// TimerPeriodical is a singleton Repeater subclass that fires +// off TimerImpl. The firing is done on idle. +//======================================================================================== +{ + static TimerPeriodical * gPeriodical; + + TimerImpl* mTimers; + + public: + // Returns the singleton instance + static TimerPeriodical * GetPeriodical(); + + TimerPeriodical(); + + virtual ~TimerPeriodical(); + + virtual void RepeatAction( const EventRecord &inMacEvent); + + nsresult AddTimer( TimerImpl * aTimer); + + nsresult RemoveTimer( TimerImpl * aTimer); + +}; + + +//======================================================================================== +// TimerImpl implementation +//======================================================================================== + +NS_IMPL_ISUPPORTS(TimerImpl, nsITimer::GetIID()) + +//---------------------------------------------------------------------------------------- +TimerImpl::TimerImpl() +//---------------------------------------------------------------------------------------- +: mCallbackFunc(nsnull) +, mCallbackObject(nsnull) +, mClosure(nsnull) +, mDelay(0) +, mFireTime(0) +, mPrev(nsnull) +, mNext(nsnull) +#if DEBUG +, mSignature(eGoodTimerSignature) +#endif +{ + NS_INIT_REFCNT(); +} + +//---------------------------------------------------------------------------------------- +TimerImpl::~TimerImpl() +//---------------------------------------------------------------------------------------- +{ + Cancel(); + NS_IF_RELEASE(mCallbackObject); +#if DEBUG + mSignature = eDeletedTimerSignature; +#endif +} + +//---------------------------------------------------------------------------------------- +nsresult TimerImpl::Init(nsTimerCallbackFunc aFunc, + void *aClosure, + PRUint32 aDelay) +//---------------------------------------------------------------------------------------- +{ + mCallbackFunc = aFunc; + mClosure = aClosure; + SetDelaySelf(aDelay); + return TimerPeriodical::GetPeriodical()->AddTimer(this); +} + +//---------------------------------------------------------------------------------------- +nsresult TimerImpl::Init(nsITimerCallback *aCallback, + PRUint32 aDelay) +//---------------------------------------------------------------------------------------- +{ + NS_ADDREF(aCallback); + mCallbackObject = aCallback; + SetDelaySelf(aDelay); + return TimerPeriodical::GetPeriodical()->AddTimer(this); +} + +//---------------------------------------------------------------------------------------- +void TimerImpl::Cancel() +//---------------------------------------------------------------------------------------- +{ + TimerPeriodical::GetPeriodical()->RemoveTimer(this); +} + +//---------------------------------------------------------------------------------------- +PRUint32 TimerImpl::GetDelay() +//---------------------------------------------------------------------------------------- +{ + return mDelay; +} + +//---------------------------------------------------------------------------------------- +void TimerImpl::SetDelay(PRUint32 aDelay) +//---------------------------------------------------------------------------------------- +{ + SetDelaySelf(aDelay); +} + +//---------------------------------------------------------------------------------------- +void* TimerImpl::GetClosure() +//---------------------------------------------------------------------------------------- +{ + return mClosure; +} + +//---------------------------------------------------------------------------------------- +void TimerImpl::Fire() +//---------------------------------------------------------------------------------------- +{ + NS_PRECONDITION(mRefCnt > 0, "Firing a disposed Timer!"); + if (mCallbackFunc != NULL) { + (*mCallbackFunc)(this, mClosure); + } + else if (mCallbackObject != NULL) { + mCallbackObject->Notify(this); // Fire the timer + } +} + +//---------------------------------------------------------------------------------------- +void TimerImpl::SetDelaySelf( PRUint32 aDelay ) +//---------------------------------------------------------------------------------------- +{ + + mDelay = aDelay; + mFireTime = TickCount() + (mDelay * 3) / 50; // We need mFireTime in ticks (1/60th) + // but aDelay is in 1000th (60/1000 = 3/50) +} + +TimerPeriodical * TimerPeriodical::gPeriodical = nsnull; + +TimerPeriodical * TimerPeriodical::GetPeriodical() +{ + if (gPeriodical == NULL) + gPeriodical = new TimerPeriodical(); + return gPeriodical; +} + +TimerPeriodical::TimerPeriodical() +{ + mTimers = nsnull; +} + +TimerPeriodical::~TimerPeriodical() +{ + PR_ASSERT(mTimers == 0); +} + +nsresult TimerPeriodical::AddTimer( TimerImpl * aTimer) +{ + // make sure it's not already there + RemoveTimer(aTimer); + // keep list sorted by fire time + if (mTimers) + { + if (aTimer->GetFireTime() < mTimers->GetFireTime()) + { + mTimers->mPrev = aTimer; + aTimer->mNext = mTimers; + mTimers = aTimer; + } + else + { + TimerImpl *t = mTimers; + TimerImpl *prevt; + // we know we will enter the while loop at least the first + // time, and thus prevt will be initialized + while (t && (t->GetFireTime() <= aTimer->GetFireTime())) + { + prevt = t; + t = t->mNext; + } + aTimer->mPrev = prevt; + aTimer->mNext = prevt->mNext; + prevt->mNext = aTimer; + if (aTimer->mNext) aTimer->mNext->mPrev = aTimer; + } + } + else mTimers = aTimer; + + StartRepeating(); + return NS_OK; +} + +nsresult TimerPeriodical::RemoveTimer( TimerImpl * aTimer) +{ + TimerImpl* t = mTimers; + TimerImpl* next_t = nsnull; + if (t) next_t = t->mNext; + while (t) + { + if (t == aTimer) + { + if (mTimers == t) mTimers = t->mNext; + if (t->mPrev) t->mPrev->mNext = t->mNext; + if (t->mNext) t->mNext->mPrev = t->mPrev; + t->mNext = nsnull; + t->mPrev = nsnull; + } + t = next_t; + if (t) next_t = t->mNext; + } + + if ( mTimers == nsnull ) + StopRepeating(); + return NS_OK; +} + +// Called through every event loop +// Loops through the list of available timers, and +// fires off the appropriate ones +void TimerPeriodical::RepeatAction( const EventRecord &inMacEvent) +{ + PRBool done = false; + while (!done) + { + TimerImpl* t = mTimers; + while (t) + { + NS_ASSERTION(t->IsGoodTimer(), "Bad timer!"); + + if (t->GetFireTime() <= inMacEvent.when) + { + RemoveTimer(t); + t->Fire(); + break; + } + t = t->mNext; + } + done = true; + } +} + + +NS_GFX nsresult NS_NewTimer(nsITimer** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + TimerImpl *timer = new TimerImpl(); + if (nsnull == timer) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return timer->QueryInterface(nsITimer::GetIID(), (void **) aInstancePtrResult); +} diff --git a/timer/src/makefile.win b/timer/src/makefile.win new file mode 100644 index 000000000000..2d46a61323bf --- /dev/null +++ b/timer/src/makefile.win @@ -0,0 +1,23 @@ +#!nmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH=..\.. +IGNORE_MANIFEST=1 + +DIRS = windows + +include <$(DEPTH)\config\rules.mak> diff --git a/timer/src/os2/.cvsignore b/timer/src/os2/.cvsignore new file mode 100644 index 000000000000..f3c7a7c5da68 --- /dev/null +++ b/timer/src/os2/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/timer/src/os2/Makefile.in b/timer/src/os2/Makefile.in new file mode 100644 index 000000000000..5aa5778de9c5 --- /dev/null +++ b/timer/src/os2/Makefile.in @@ -0,0 +1,48 @@ +# +# 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 the Mozilla OS/2 libraries. +# +# The Initial Developer of the Original Code is John Fairhurst, +# . Portions created by John Fairhurst are +# Copyright (C) 1999 John Fairhurst. All Rights Reserved. +# +# Contributor(s): +# +# Makefile for timer/src/os2 + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +LIBRARY_NAME = timer_os2_s + +MODULE=timer + +REQUIRES=xpcom + +CXXFLAGS += $(TK_CFLAGS) +INCLUDES += $(TK_CFLAGS) -I$(srcdir)/.. + +CPPSRCS = \ + nsTimer.cpp \ + $(NULL) + +MKSHLIB = +override NO_SHARED_LIB=1 +override NO_STATIC_LIB= + +include $(topsrcdir)/config/rules.mk diff --git a/timer/src/os2/nsTimerOS2.cpp b/timer/src/os2/nsTimerOS2.cpp new file mode 100644 index 000000000000..b2140aa290a3 --- /dev/null +++ b/timer/src/os2/nsTimerOS2.cpp @@ -0,0 +1,601 @@ +/* + * 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 the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#define INCL_DOS +#define INCL_WIN +#include + +#include // UINT_MAX (don't ask...) +#include + +#include "nsHashtable.h" + +//#define PROFILE_TIMERS // print stats on timer usage +//#define VERIFY_THREADS // check timers are being used thread-correctly + +#include "nsTimerOS2.h" + +// Implementation of timers lifted from os2fe timer.cpp. +// Which was itself lifted pretty much from the winfe. +// +// mjf 28-9-98 +// +// Rewrite 16-3-1999 to work correctly in a multithreaded world: +// Now, each thread has an nsTimerManager. +// This has a Timer window owned by the thread, and +// a queue (linked list) of timer objects. +// There is a static hashtable of these TimerManager +// object, keyed by TID. Thus things work. Ahem. +// +// Problem: nsTimerManagers are not cleaned up until +// module unload time. +// +// Update 16-4-1999 to recycle timers and collect statistics on how effective +// this is. + +// Declarations, prototypes of useful functions +MRESULT EXPENTRY fnwpTimer( HWND h, ULONG msg, MPARAM mp1, MPARAM mp2); +#define NSTIMER_TIMER (TID_USERMAX - 2) +#define TIMEOUT_NEVER ((ULONG)-1) +#define TIMERCLASS ("WarpzillaTimerClass") +#define TIMER_CACHESIZE 20 + +static TID QueryCurrentTID(); + +// Timer object (funky 'release' method for recycler) +NS_IMPL_ADDREF(nsTimer) +NS_IMPL_QUERY_INTERFACE(nsTimer, nsITimer::GetIID()) + +nsrefcnt nsTimer::Release() +{ + if( --mRefCnt == 0) + mManager->DisposeTimer( this); + + return mRefCnt; +} + +nsTimer::nsTimer( nsTimerManager *aManager) +{ + Construct(); + mManager = aManager; +} + +void nsTimer::Construct() +{ + NS_INIT_REFCNT(); + mDelay = 0; + mFunc = nsnull; + mClosure = nsnull; + mCallback = nsnull; + mFireTime = 0; + mNext = nsnull; +} + +void nsTimer::Destruct() +{ + Cancel(); +} + +nsTimer::~nsTimer() +{ + Destruct(); +} + +nsresult nsTimer::Init( nsTimerCallbackFunc aFunc, + void *aClosure, PRUint32 aDelay) +{ + mFunc = aFunc; + mClosure = aClosure; + + return mManager->InitTimer( this, aDelay); +} + +nsresult nsTimer::Init( nsITimerCallback *aCallback, PRUint32 aDelay) +{ + mCallback = aCallback; + NS_ADDREF(mCallback); // this is daft, but test14 traps without it + + return mManager->InitTimer( this, aDelay); +} + +void nsTimer::Cancel() +{ + if( mCallback || mFunc) // guard against double-cancel + { + mManager->CancelTimer( this); + NS_IF_RELEASE(mCallback); + mFunc = nsnull; + } +} + +void nsTimer::Fire( ULONG aNow) +{ + if( mFunc) + (*mFunc)( this, mClosure); + else if( mCallback) + mCallback->Notify( this); +} + +// Timer manager + +// First, GUI stuff. + +nsTimerManager::nsTimerManager() : mTimerList(nsnull), mTimerSet(FALSE), + mNextFire(TIMEOUT_NEVER), mHWNDTimer(0), + mBusy(FALSE), mBase(nsnull), mSize(0) +#ifdef PROFILE_TIMERS + ,mDeleted(0),mActive(0),mCount(0),mPeak(0) +#endif +{ + // As a part of the PM setup protocol (see somewhere under + // http://www.mozilla.org/ports/os2/code_docs/), create a HMQ if + // appropriate. + if( FALSE == WinQueryQueueInfo( HMQ_CURRENT, 0, 0)) + { + HAB hab = WinInitialize( 0); + WinCreateMsgQueue( hab, 0); + } + // Register timer window class if we haven't done that yet. + EnsureWndClass(); + + // Create timer window + mHWNDTimer = WinCreateWindow( HWND_DESKTOP, TIMERCLASS, 0, 0, 0, 0, 0, + 0, HWND_DESKTOP, HWND_TOP, 0, 0, 0); + NS_ASSERTION(mHWNDTimer, "Couldn't create Timer window"); + + // stick pointer to us in the window word + WinSetWindowPtr( mHWNDTimer, QWL_USER, this); + +#ifdef PROFILE_TIMERS + mTID = QueryCurrentTID(); +#endif +} + +nsTimerManager::~nsTimerManager() +{ + // I reckon PM has already gone down by this point. + // There might be an API to do this (register listener for app shutdown) + // at some point, or maybe when we get into the widget DLL. + if( mHWNDTimer) + WinDestroyWindow( mHWNDTimer); + +#ifdef PROFILE_TIMERS + printf( "\n----- Timer Statistics %d -----\n", (int)mTID); + printf( " Calls to NS_NewTimer: %d\n", mCount); + printf( " Actual timers created: %d\n", mPeak); + double d = mCount ? (double)(mCount - mPeak) / (double)mCount : 0; + printf( " Timers recycled: %d (%d%%)\n", mCount - mPeak, (int)(d*100.0)); + UINT i = mSize+mActive+mDeleted; + printf( " Cache+Active+Deleted: %d\n", i); + if( i != mPeak) + printf( " WARNING: Timers leaked: %d\n", mPeak - i); + printf( "------------------------------\n\n"); +#endif + + // delete timers in the 'cache' list + nsTimer *pTemp, *pNext = mBase; + while( 0 != pNext) + { + pTemp = pNext->mNext; + delete pNext; + pNext = pTemp; + // and then the 'active' list... + if( 0 == pNext) { pNext = mTimerList; mTimerList = 0; } + } +} + +void nsTimerManager::EnsureWndClass() +{ + static BOOL bRegistered = FALSE; + + if( !bRegistered) + { + BOOL rc = WinRegisterClass( 0, TIMERCLASS, fnwpTimer, 0, 4); + NS_ASSERTION(rc,"Can't register class"); + bRegistered = TRUE; + } +} + +MRESULT nsTimerManager::HandleMsg( ULONG msg, MPARAM mp1, MPARAM mp2) +{ + MRESULT mRC = 0; + + if( msg == WM_TIMER && SHORT1FROMMP(mp1) == NSTIMER_TIMER) + { + // Block only one entry into this function, or else. + // (windows does this; don't completely understand or belive + // it's necessary -- maybe if nested eventloops happen). + if( !mBusy) + { + mBusy = TRUE; + // see if we need to fork off any timeout functions + if( mTimerList) + ProcessTimeouts( 0); + mBusy = FALSE; + } + else + printf( "mBusy == TRUE but want to fire Timer!\n"); + } + else + mRC = WinDefWindowProc( mHWNDTimer, msg, mp1, mp2); + + return mRC; +} + +void nsTimerManager::StopTimer() +{ + WinStopTimer( 0/*hab*/, mHWNDTimer, NSTIMER_TIMER); +} + +void nsTimerManager::StartTimer( UINT aDelay) +{ + WinStartTimer( 0/*hab*/, mHWNDTimer, NSTIMER_TIMER, aDelay); +} + +MRESULT EXPENTRY fnwpTimer( HWND h, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + nsTimerManager *pMgr = (nsTimerManager*) WinQueryWindowPtr( h, QWL_USER); + MRESULT mRet = 0; + if( pMgr) + mRet = pMgr->HandleMsg( msg, mp1, mp2); + else + mRet = WinDefWindowProc( h, msg, mp1, mp2); + return mRet; +} + +// Recycling management +nsTimer *nsTimerManager::CreateTimer() +{ + nsTimer *rc; + if( !mBase) + { + rc = new nsTimer( this); +#ifdef PROFILE_TIMERS + mPeak++; +#endif + } + else + { + rc = mBase; + mBase = rc->mNext; + rc->Construct(); + mSize--; + } +#ifdef PROFILE_TIMERS + mCount++; +#endif + return rc; +} + +void nsTimerManager::DisposeTimer( nsTimer *aTimer) +{ + if( TIMER_CACHESIZE == mSize) + { + delete aTimer; +#ifdef PROFILE_TIMERS + mDeleted++; +#endif + } + else + { + aTimer->Destruct(); + aTimer->mNext = mBase; + mBase = aTimer; + mSize++; + } +} + +// Complicated functions to maintain the list of timers. +// This code has something of a pedigree -- I worked it through once, +// ages ago, for os2fe, and convinced myself it was correct. + +// Adjust the period of the window timer according to the contents of +// the timer list, and record the absolute time that the next firing +// will occur. May well stop the window timer entirely. +void nsTimerManager::SyncTimeoutPeriod( ULONG aTickCount) +{ + // May want us to set tick count ourselves. + if( 0 == aTickCount) + aTickCount = WinGetCurrentTime( 0/*hab*/); + + // If there's no list, we should clear the timer. + if( !mTimerList) + { + if( mTimerSet) + { + StopTimer(); + mNextFire = TIMEOUT_NEVER; + mTimerSet = FALSE; + } + } + else + { + // See if we need to clear the current timer. + // Circumstances are that if the timer will not + // fire on time for the next timeout. + BOOL bSetTimer = FALSE; + nsTimer *pTimeout = mTimerList; + if( mTimerSet) + { + if( pTimeout->mFireTime != mNextFire) + { + StopTimer(); + mNextFire = TIMEOUT_NEVER; + mTimerSet = FALSE; + + // Set the timer. + bSetTimer = TRUE; + } + } + else + { + // No timer set, attempt. + bSetTimer = TRUE; + } + + if( bSetTimer) + { + ULONG ulFireWhen = pTimeout->mFireTime > aTickCount ? + pTimeout->mFireTime - aTickCount : 0; + if( ulFireWhen > UINT_MAX) + ulFireWhen = UINT_MAX; + + NS_ASSERTION(mTimerSet == FALSE,"logic error in timer sync magic"); + StartTimer( ulFireWhen); + + // Set the fire time. + mNextFire = pTimeout->mFireTime; + } + } +} + +// Walk down the timeout list and fire those which are due. +void nsTimerManager::ProcessTimeouts( ULONG aNow) +{ + nsTimer *p = mTimerList; + + if( 0 == aNow) + aNow = WinGetCurrentTime( 0/*hab*/); + + BOOL bCalledSync = FALSE; + + // loop over all entries + while( p) + { + // send it + if( p->mFireTime < aNow) + { + // Fire it, making sure the timer doesn't die. + NS_ADDREF(p); + p->Fire( aNow); + + // Clear the timer. + // Period synced. + p->Cancel(); + bCalledSync = TRUE; + NS_RELEASE(p); + + // Reset the loop (can't look at p->pNext now, and called + // code may have added/cleared timers). + // (could do this by going recursive and returning). + p = mTimerList; + } + else + { + // Make sure we fire a timer. + // Also, we need to check to see if things are backing up (they + // may be asking to be fired long before we ever get to them, + // and we don't want to pass in negative values to the real + // timer code, or it takes days to fire.... + if( FALSE == bCalledSync) + { + SyncTimeoutPeriod( aNow); + bCalledSync = TRUE; + } + // Get next timer. + p = p->mNext; + } + } +} + +// Init a timer - insert it into the list, adjust the window timer to be +// running fast enough to make sure it fires when it should. +nsresult nsTimerManager::InitTimer( nsTimer *aTimer, PRUint32 aDelay) +{ +#ifdef VERIFY_THREADS + if( aTimer->mTID != QueryCurrentTID()) + printf( "*** Thread assumption violated in base/src/os2/nsTimerOS2.cpp\n"); +#endif + + ULONG ulNow = WinGetCurrentTime( 0/*hab*/); + + aTimer->mDelay = aDelay; + aTimer->mFireTime = (ULONG) aDelay + ulNow; + aTimer->mNext = nsnull; + + // add it to the list + if( !mTimerList) + mTimerList = aTimer; + else + { + // is it before everything else on the list? + if( aTimer->mFireTime < mTimerList->mFireTime) + { + aTimer->mNext = mTimerList; + mTimerList = aTimer; + } + else + { + nsTimer *pPrev = mTimerList; + nsTimer *pCurrent = mTimerList; + + while( pCurrent && + (pCurrent->mFireTime <= aTimer->mFireTime)) + { + pPrev = pCurrent; + pCurrent = pCurrent->mNext; + } + + NS_ASSERTION(pPrev,"logic error in InitTimer"); + + // insert it after pPrev (this could be at the end of the list) + aTimer->mNext = pPrev->mNext; + pPrev->mNext = aTimer; + } + } + +#ifdef PROFILE_TIMERS + mActive++; +#endif + + // Sync the timer fire period. + SyncTimeoutPeriod( ulNow); + + return NS_OK; +} + +// Cancel a timer - remove it from the list, adjust the window timer as +// appropriate. +void nsTimerManager::CancelTimer( nsTimer *aTimer) +{ + if( mTimerList == aTimer) + { + // first element in the list lossage + mTimerList = aTimer->mNext; + } + else + { + // walk until no next pointer + nsTimer *p = mTimerList; + while( p && p->mNext && (p->mNext != aTimer)) + p = p->mNext; + + // if we found something valid pull it out of the list + if( p && p->mNext && p->mNext == aTimer) + { + p->mNext = aTimer->mNext; + } + else + { + // we come here at app-shutdown/crash when timers which are still in the + // active-timer list are deleted. + return; + } + } + +#ifdef PROFILE_TIMERS + mActive--; +#endif + + // Adjust window timer + SyncTimeoutPeriod( 0); +} + +// Data structure to hold and create nsTimerManagers. +// This is (meant to be) thread-safe. +class nsTimerManagers +{ + nsHashtable mTable; + HMTX mMutex; + + struct TIDKey : public nsVoidKey + { + TIDKey() : nsVoidKey((void*)QueryCurrentTID()) + {} + }; + + struct Lock + { + HMTX mHmtx; + Lock( HMTX hmtx) : mHmtx(hmtx) + { + DosRequestMutexSem( mHmtx, SEM_INDEFINITE_WAIT); + } + ~Lock() + { + DosReleaseMutexSem( mHmtx); + } + }; + + public: + nsTimerManagers() : mMutex(0) + { + DosCreateMutexSem( 0, &mMutex, 0, 0 /*unowned*/); + } + + static PRBool mgr_dtor( nsHashKey *aKey, void *aData, void */*aClosure*/) + { + nsTimerManager *pManager = (nsTimerManager*) aData; + delete pManager; + return PR_TRUE; + } + + ~nsTimerManagers() + { + mTable.Enumerate( &mgr_dtor); + if( mMutex) + DosCloseMutexSem( mMutex); + } + + nsTimerManager *Get() + { + Lock lock(mMutex); + TIDKey key; + + nsTimerManager *aMgr = (nsTimerManager*) mTable.Get( &key); + + if( !aMgr) + { + aMgr = new nsTimerManager; + mTable.Put( &key, aMgr); + } + + return aMgr; + } + +} TimerManagers; + +// Entry into the DLL. No, I dunno why there's not a normal factory +// for this either. Ease of use? + +NS_BASE nsresult NS_NewTimer( nsITimer **aInstance) +{ + if( !aInstance) + return NS_ERROR_NULL_POINTER; + + // Assumption: timers are created in the same thread they are to be + // used in. This seems likely, but we shall see. + // If things seem screwy, set the VERIFY_THREADS flag on this file. + + nsTimer *timer = TimerManagers.Get()->CreateTimer(); + if( !timer) + return NS_ERROR_OUT_OF_MEMORY; + + return timer->QueryInterface( nsITimer::GetIID(), (void **) aInstance); +} + +TID QueryCurrentTID() +{ + PTIB pTib = 0; + PPIB pPib = 0; + DosGetInfoBlocks( &pTib, &pPib); + return pTib->tib_ptib2->tib2_ultid; +} diff --git a/timer/src/os2/nsTimerOS2.h b/timer/src/os2/nsTimerOS2.h new file mode 100644 index 000000000000..cba33e2c6f72 --- /dev/null +++ b/timer/src/os2/nsTimerOS2.h @@ -0,0 +1,116 @@ +/* + * 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 the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nstimeros2_h +#define _nstimeros2_h + +// Class definitions for the timers. +// +// These timer classes are reentrant, thread-correct and supports recycling of +// timer objects on a per-thread basis. + +#include "nsITimer.h" +#include "nsITimerCallback.h" + +// Implementation of the timer interface. + +class nsTimerManager; + +class nsTimer : public nsITimer +{ + public: + nsTimer( nsTimerManager *aManager); + virtual ~nsTimer(); + + // nsISupports + NS_DECL_ISUPPORTS + + // Explicit init-term for recycler + void Construct(); + void Destruct(); + + nsresult Init( nsTimerCallbackFunc aFunc, void *aClosure, PRUint32 aDelay); + nsresult Init( nsITimerCallback *aCallback, PRUint32 aDelay); + void Cancel(); + PRUint32 GetDelay() { return mDelay; } + void SetDelay( PRUint32 aDelay) {}; // XXX Windows does this too... + void *GetClosure() { return mClosure; } + + // Implementation + void Fire( ULONG aNow); + + private: + PRUint32 mDelay; + nsTimerCallbackFunc mFunc; + void *mClosure; + nsITimerCallback *mCallback; + ULONG mFireTime; + nsTimer *mNext; + + friend class nsTimerManager; + + nsTimerManager *mManager; +}; + + +// Timer manager class, one of these per-thread + +class nsTimerManager +{ + public: + nsTimerManager(); + ~nsTimerManager(); + + nsresult InitTimer( nsTimer *aTimer, PRUint32 aDelay); + void CancelTimer( nsTimer *aTimer); + + MRESULT HandleMsg( ULONG msg, MPARAM mp1, MPARAM mp2); + + nsTimer *CreateTimer(); + void DisposeTimer( nsTimer *aTimer); + + private: + nsTimer *mTimerList; // linked list of active timers, sorted in priority order + BOOL mTimerSet; // timer running? + ULONG mNextFire; // absolute time of next fire + HWND mHWNDTimer; // window for timer messages + BOOL mBusy; // dubious lock thingy + + void StartTimer( UINT delay); + void StopTimer(); + void EnsureWndClass(); + + void ProcessTimeouts( ULONG aNow); + void SyncTimeoutPeriod( ULONG aTickCount); + + // timer-cache + nsTimer *mBase; + UINT mSize; +#ifdef PROFILE_TIMERS + UINT mDeleted; + UINT mActive; + UINT mCount; + UINT mPeak; + TID mTID; +#endif +}; + +#endif diff --git a/timer/src/photon/.cvsignore b/timer/src/photon/.cvsignore new file mode 100644 index 000000000000..f3c7a7c5da68 --- /dev/null +++ b/timer/src/photon/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/timer/src/photon/Makefile.in b/timer/src/photon/Makefile.in new file mode 100644 index 000000000000..85c1df52ad1e --- /dev/null +++ b/timer/src/photon/Makefile.in @@ -0,0 +1,44 @@ +#!gmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +LIBRARY_NAME = timer_photon_s + +MODULE=timer + +REQUIRES=xpcom + +CXXFLAGS += $(TK_CFLAGS) +INCLUDES += $(TK_CFLAGS) -I$(srcdir)/.. + +CPPSRCS = \ + nsTimer.cpp \ + $(NULL) + +MKSHLIB = +override NO_SHARED_LIB=1 +override NO_STATIC_LIB= + +include $(topsrcdir)/config/rules.mk diff --git a/timer/src/photon/nsTimer.cpp b/timer/src/photon/nsTimer.cpp new file mode 100644 index 000000000000..5b949e57c6ca --- /dev/null +++ b/timer/src/photon/nsTimer.cpp @@ -0,0 +1,264 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "nsITimer.h" +#include "nsITimerCallback.h" +#include "nsCRT.h" +#include "prlog.h" +#include +#include +#include +#include +#include + +#include + +static NS_DEFINE_IID(kITimerIID, NS_ITIMER_IID); + +/* Use the Widget Debug log */ +extern PRLogModuleInfo *PhWidLog; + +/* + * Implementation of timers QNX/Neutrino timers. + */ + +class TimerImpl : public nsITimer { +public: + +public: + TimerImpl(); + virtual ~TimerImpl(); + + NS_DECL_ISUPPORTS + + virtual nsresult Init( nsTimerCallbackFunc aFunc, void *aClosure, PRUint32 aDelay ); + virtual nsresult Init( nsITimerCallback *aCallback, PRUint32 aDelay ); + virtual void Cancel(); + virtual PRUint32 GetDelay() { return mDelay; } + virtual void SetDelay( PRUint32 aDelay ) { mDelay=aDelay; }; + virtual void* GetClosure() { return mClosure; } + + static int TimerEventHandler( void *aData, pid_t aRcvId, void *aMsg, size_t aMsgLen ); + +private: + + nsresult SetupTimer( PRUint32 aDelay ); + + PRUint32 mDelay; + nsTimerCallbackFunc mFunc; + void *mClosure; + nsITimerCallback *mCallback; + timer_t mTimerId; + pid_t mPulsePid; + PtPulseMsg_t mPulseMsg; + PtPulseMsgId_t *mPulseMsgId; + PtInputId_t *mInputId; +}; + + +TimerImpl::TimerImpl() +{ + NS_INIT_REFCNT(); + mFunc = NULL; + mClosure = NULL; + mCallback = NULL; + mDelay = 0; + mTimerId = -1; + mPulsePid = 0; + mPulseMsgId = NULL; + mInputId = NULL; +} + + +TimerImpl::~TimerImpl() +{ + Cancel(); + NS_IF_RELEASE(mCallback); +} + + +NS_IMPL_ISUPPORTS(TimerImpl, kITimerIID) + + +NS_METHOD TimerImpl::SetupTimer( PRUint32 aDelay ) +{ + struct itimerspec tv; + int err; + + if ((aDelay > 10000) || (aDelay < 0)) + { + NS_WARNING("TimerImpl::SetupTimer called with bogus value\n"); + return NS_ERROR_FAILURE; + } + + mDelay = aDelay; + if( mPulsePid ) + { + NS_ASSERTION(0,"TimerImpl::SetupTimer - reuse of timer not allowed!"); + return NS_ERROR_FAILURE; + } + if(( mPulsePid = PtAppCreatePulse( NULL, -1 )) > -2 ) + { + NS_ASSERTION(0,"TimerImpl::SetupTimer - failed to create pulse"); + return NS_ERROR_FAILURE; + } + if(( mPulseMsgId = PtPulseArmPid( NULL, mPulsePid, getpid(), &mPulseMsg )) == NULL ) + { + NS_ASSERTION(0,"TimerImpl::SetupTimer - failed to arm pulse!"); + return NS_ERROR_FAILURE; + } + if(( mInputId = PtAppAddInput( NULL, mPulsePid, TimerEventHandler, this )) == NULL ) + { + NS_ASSERTION(0,"TimerImpl::SetupTimer - failed to add input handler!"); + return NS_ERROR_FAILURE; + } + + err = timer_create( CLOCK_SOFTTIME, &mPulseMsg, &mTimerId ); + if( err != 0 ) + { + NS_ASSERTION(0,"TimerImpl::SetupTimer - timer_create error"); + return NS_ERROR_FAILURE; + } + + tv.it_interval.tv_sec = 0; + tv.it_interval.tv_nsec = 0; + tv.it_value.tv_sec = ( aDelay / 1000 ); + tv.it_value.tv_nsec = ( aDelay % 1000 ) * 1000000L; + + /* If delay is set to 0 seconds then change it to 1 nsec. */ + if ( (tv.it_value.tv_sec == 0) && (tv.it_value.tv_nsec == 0)) + { + tv.it_value.tv_nsec = 1; + } + + err = timer_settime( mTimerId, 0, &tv, 0 ); + if( err != 0 ) + { + NS_ASSERTION(0,"TimerImpl::SetupTimer timer_settime"); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + + +NS_METHOD TimerImpl::Init( nsTimerCallbackFunc aFunc, void *aClosure, PRUint32 aDelay ) +{ + nsresult err; + + mFunc = aFunc; + mClosure = aClosure; + err = SetupTimer( aDelay ); + return err; +} + + +NS_METHOD TimerImpl::Init( nsITimerCallback *aCallback, PRUint32 aDelay ) +{ + nsresult err; + + mCallback = aCallback; + err = SetupTimer(aDelay); + NS_ADDREF(mCallback); + return err; +} + + +void TimerImpl::Cancel() +{ + int err; + + if( mTimerId >= 0) + { + err = timer_delete( mTimerId ); + if (err < 0) + { + char buf[256]; + sprintf(buf, "TimerImpl::Cancel Failed in timer_delete mTimerId=<%d> err=<%d> errno=<%d>", mTimerId, err, errno); + //NS_ASSERTION(0,"TimerImpl::Cancel Failed in timer_delete"); + NS_ASSERTION(0,buf); + return; + } + + mTimerId *= -1; // HACK for Debug + } + + if( mInputId ) + { + PtAppRemoveInput( NULL, mInputId ); + mInputId = NULL; + } + + if( mPulseMsgId ) + { + PtPulseDisarm( mPulseMsgId ); + mPulseMsgId = NULL; + } + + if( mPulsePid ) + { + PtAppDeletePulse( NULL, mPulsePid ); + mPulsePid = 0; + } +} + + +// This is the timer handler that gets called by the Photon +// input proc + +int TimerImpl::TimerEventHandler( void *aData, pid_t aRcvId, void *aMsg, size_t aMsgLen ) +{ + int localTimerId; + + TimerImpl* timer = (TimerImpl *)aData; + if( timer ) + { + localTimerId = timer->mTimerId; + + if( timer->mFunc != NULL ) + { + (*timer->mFunc)( timer, timer->mClosure ); + } + else if ( timer->mCallback != NULL ) + { + timer->mCallback->Notify( timer ); + } + +/* These stupid people destroy this object inside the callback */ +/* so don't do anything with it from here on */ + } + + return Pt_CONTINUE; +} + + +NS_BASE nsresult NS_NewTimer(nsITimer** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "NS_NewTimer - null ptr"); + if (nsnull == aInstancePtrResult) + { + return NS_ERROR_NULL_POINTER; + } + + TimerImpl *timer = new TimerImpl(); + if (nsnull == timer) + { + return NS_ERROR_OUT_OF_MEMORY; + } + + return timer->QueryInterface(kITimerIID, (void **) aInstancePtrResult); +} diff --git a/timer/src/rhapsody/.cvsignore b/timer/src/rhapsody/.cvsignore new file mode 100644 index 000000000000..f3c7a7c5da68 --- /dev/null +++ b/timer/src/rhapsody/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/timer/src/rhapsody/Makefile.in b/timer/src/rhapsody/Makefile.in new file mode 100644 index 000000000000..2a4b468cfb6d --- /dev/null +++ b/timer/src/rhapsody/Makefile.in @@ -0,0 +1,44 @@ +#!gmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +LIBRARY_NAME = timer_rhapsody_s + +MODULE=timer + +REQUIRES=xpcom + +CXXFLAGS += $(TK_CFLAGS) +INCLUDES += $(TK_CFLAGS) -I$(srcdir)/.. + +CPPSRCS = \ + nsTimer.cpp \ + $(NULL) + +MKSHLIB = +override NO_SHARED_LIB=1 +override NO_STATIC_LIB= + +include $(topsrcdir)/config/rules.mk diff --git a/timer/src/rhapsody/nsTimer.cpp b/timer/src/rhapsody/nsTimer.cpp new file mode 100644 index 000000000000..d93a2bb28046 --- /dev/null +++ b/timer/src/rhapsody/nsTimer.cpp @@ -0,0 +1,200 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "nsITimer.h" +#include "nsITimerCallback.h" +#include "nsCRT.h" +#include "prlog.h" +#include +#include + +// +// Copied from the unix version, Rhapsody needs to +// make this work. Stubs to compile things for now. +// + +#if 0 +Michael Hanni suggests: + + I understand that nsTimer.cpp in base/rhapsody/ needs to be completed, + yes? Wouldn't this code just use some NSTimers in the NSRunLoop? + + Timer = [NSTimer timerWithTimeInterval:0.02 //seconds + target:self + selector:@selector(doThis:) + userInfo:nil + repeats:YES]; + [[NSRunLoop currentRunLoop] addTimer:Timer + forMode:NSDefaultRunLoopMode]; + + I only looked at nsTimer.cpp briefly, but could something like this work + if imbedded in all that c++? ;-) + +#endif + +static NS_DEFINE_IID(kITimerIID, NS_ITIMER_IID); + +extern void nsTimerExpired(void *aCallData); + +class TimerImpl : public nsITimer { +public: + +public: + TimerImpl(); + virtual ~TimerImpl(); + + virtual nsresult Init(nsTimerCallbackFunc aFunc, + void *aClosure, +// PRBool aRepeat, + PRUint32 aDelay); + + virtual nsresult Init(nsITimerCallback *aCallback, +// PRBool aRepeat, + PRUint32 aDelay); + + NS_DECL_ISUPPORTS + + virtual void Cancel(); + virtual PRUint32 GetDelay() { return mDelay; } + virtual void SetDelay(PRUint32 aDelay) { mDelay=aDelay; }; + virtual void* GetClosure() { return mClosure; } + + void FireTimeout(); + +private: + nsresult Init(PRUint32 aDelay); + + PRUint32 mDelay; + nsTimerCallbackFunc mFunc; + void *mClosure; + nsITimerCallback *mCallback; + // PRBool mRepeat; + TimerImpl *mNext; + int mTimerId; +}; + +void TimerImpl::FireTimeout() +{ + if (mFunc != NULL) { + (*mFunc)(this, mClosure); + } + else if (mCallback != NULL) { + mCallback->Notify(this); // Fire the timer + } + +// Always repeating here + +// if (mRepeat) +// mTimerId = XtAppAddTimeOut(gAppContext, GetDelay(),(XtTimerCallbackProc)nsTimerExpired, this); +} + + +TimerImpl::TimerImpl() +{ + NS_INIT_REFCNT(); + mFunc = NULL; + mCallback = NULL; + mNext = NULL; + mTimerId = 0; + mDelay = 0; + mClosure = NULL; +} + +TimerImpl::~TimerImpl() +{ +} + +nsresult +TimerImpl::Init(nsTimerCallbackFunc aFunc, + void *aClosure, +// PRBool aRepeat, + PRUint32 aDelay) +{ + mFunc = aFunc; + mClosure = aClosure; + // mRepeat = aRepeat; + + printf("TimerImpl::Init() not implemented\n"); + +#ifdef RHAPSODY_NEEDS_TO_IMPLEMENT_THIS + mTimerId = XtAppAddTimeOut(gAppContext, aDelay,(XtTimerCallbackProc)nsTimerExpired, this); +#endif + + return Init(aDelay); +} + +nsresult +TimerImpl::Init(nsITimerCallback *aCallback, +// PRBool aRepeat, + PRUint32 aDelay) +{ + mCallback = aCallback; + // mRepeat = aRepeat; + +printf("TimerImpl::Init() not implmented.\n"); + +#ifdef RHAPSODY_NEEDS_TO_IMPLEMENT_THIS + mTimerId = XtAppAddTimeOut(gAppContext, aDelay, (XtTimerCallbackProc)nsTimerExpired, this); +#endif + + return Init(aDelay); +} + +nsresult +TimerImpl::Init(PRUint32 aDelay) +{ + mDelay = aDelay; + NS_ADDREF(this); + + return NS_OK; +} + +NS_IMPL_ISUPPORTS(TimerImpl, kITimerIID) + + +void +TimerImpl::Cancel() +{ + + printf("TimerImpl::Cancel() not implemented.\n"); + +#ifdef RHAPSODY_NEEDS_TO_IMPLEMENT_THIS + XtRemoveTimeOut(mTimerId); +#endif +} + +NS_GFX nsresult NS_NewTimer(nsITimer** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + TimerImpl *timer = new TimerImpl(); + if (nsnull == timer) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return timer->QueryInterface(kITimerIID, (void **) aInstancePtrResult); +} + + +void nsTimerExpired(void *aCallData) +{ + TimerImpl* timer = (TimerImpl *)aCallData; + timer->FireTimeout(); +} diff --git a/timer/src/unix/.cvsignore b/timer/src/unix/.cvsignore new file mode 100644 index 000000000000..f3c7a7c5da68 --- /dev/null +++ b/timer/src/unix/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/timer/src/unix/Makefile.in b/timer/src/unix/Makefile.in new file mode 100644 index 000000000000..6d0752474618 --- /dev/null +++ b/timer/src/unix/Makefile.in @@ -0,0 +1,42 @@ +#!gmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +DIRS = $(MOZ_GFX_TOOLKIT) +### XXX ### DIRS = gtk motif xlib +### XXX ### +### XXX ### LIBRARY_NAME = timerutil_s +### XXX ### +### XXX ### REQUIRES=xpcom +### XXX ### +### XXX ### CPPSRCS =\ +### XXX ### nsNewTimer.cpp \ +### XXX ### $(NULL) +### XXX ### +### XXX ### MKSHLIB = +### XXX ### override NO_SHARED_LIB=1 +### XXX ### override NO_STATIC_LIB= + +include $(topsrcdir)/config/rules.mk diff --git a/timer/src/unix/gtk/.cvsignore b/timer/src/unix/gtk/.cvsignore new file mode 100644 index 000000000000..f3c7a7c5da68 --- /dev/null +++ b/timer/src/unix/gtk/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/timer/src/unix/gtk/Makefile.in b/timer/src/unix/gtk/Makefile.in new file mode 100644 index 000000000000..0cba3118724a --- /dev/null +++ b/timer/src/unix/gtk/Makefile.in @@ -0,0 +1,47 @@ +#!gmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +LIBRARY_NAME = timer_gtk_s +### XXX ### IS_COMPONENT=1 + +REQUIRES=xpcom + +### XXX ### DEFINES += -D_IMPL_NS_GFXNONXP +CXXFLAGS += $(TK_CFLAGS) +INCLUDES += $(TK_CFLAGS) -I$(srcdir)/.. + +CPPSRCS = \ + nsTimerGtk.cpp \ +### XXX ### nsTimerGtkFactory.cpp \ + $(NULL) + +### XXX ### EXTRA_DSO_LDOPTS += $(TK_LIBS) + +MKSHLIB = +override NO_SHARED_LIB=1 +override NO_STATIC_LIB= + +include $(topsrcdir)/config/rules.mk diff --git a/timer/src/unix/gtk/nsTimerGtk.cpp b/timer/src/unix/gtk/nsTimerGtk.cpp new file mode 100644 index 000000000000..1f0e8fb464a5 --- /dev/null +++ b/timer/src/unix/gtk/nsTimerGtk.cpp @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsTimerGtk.h" + +static NS_DEFINE_IID(kITimerIID, NS_ITIMER_IID); + +extern "C" gint nsTimerExpired(gpointer aCallData); + +void nsTimerGtk::FireTimeout() +{ + if (mFunc != NULL) { + (*mFunc)(this, mClosure); + } + else if (mCallback != NULL) { + mCallback->Notify(this); // Fire the timer + } + +// Always repeating here + +// if (mRepeat) +// mTimerId = gtk_timeout_add(aDelay, nsTimerExpired, this); +} + + +nsTimerGtk::nsTimerGtk() +{ + // printf("nsTimerGtke::nsTimerGtk called for %p\n", this); + NS_INIT_REFCNT(); + mFunc = NULL; + mCallback = NULL; + mNext = NULL; + mTimerId = 0; + mDelay = 0; + mClosure = NULL; +} + +nsTimerGtk::~nsTimerGtk() +{ + +// printf("nsTimerGtk::~nsTimerGtk called for %p\n", this); + + Cancel(); + NS_IF_RELEASE(mCallback); +} + +nsresult +nsTimerGtk::Init(nsTimerCallbackFunc aFunc, + void *aClosure, +// PRBool aRepeat, + PRUint32 aDelay) +{ + //printf("nsTimerGtk::Init called with func + closure for %p\n", this); + mFunc = aFunc; + mClosure = aClosure; + // mRepeat = aRepeat; + +// This is ancient debug code that is making it impossible to have timeouts +// greater than 10 seconds. -re + +// if ((aDelay > 10000) || (aDelay < 0)) { +// printf("Timer::Init() called with bogus value \"%d\"! Not enabling timer.\n", +// aDelay); +// return Init(aDelay); +// } + + mTimerId = gtk_timeout_add(aDelay, nsTimerExpired, this); + + return Init(aDelay); +} + +nsresult +nsTimerGtk::Init(nsITimerCallback *aCallback, +// PRBool aRepeat, + PRUint32 aDelay) +{ + //printf("nsTimerGtk::Init called with callback only for %p\n", this); + mCallback = aCallback; + NS_ADDREF(mCallback); + // mRepeat = aRepeat; + +// This is ancient debug code that is making it impossible to have timeouts +// greater than 10 seconds. -re + +// if ((aDelay > 10000) || (aDelay < 0)) { +// printf("Timer::Init() called with bogus value \"%d\"! Not enabling timer.\n", +// aDelay); +// return Init(aDelay); +// } + + mTimerId = gtk_timeout_add(aDelay, nsTimerExpired, this); + + return Init(aDelay); +} + +nsresult +nsTimerGtk::Init(PRUint32 aDelay) +{ + //printf("nsTimerGtk::Init called with delay %d only for %p\n", aDelay, this); + + mDelay = aDelay; + // NS_ADDREF(this); + + return NS_OK; +} + +NS_IMPL_ISUPPORTS(nsTimerGtk, kITimerIID) + + +void +nsTimerGtk::Cancel() +{ + //printf("nsTimerGtk::Cancel called for %p\n", this); + + nsTimerGtk *me = this; + + if (mTimerId) + gtk_timeout_remove(mTimerId); + + NS_RELEASE(me); +} + +gint nsTimerExpired(gpointer aCallData) +{ + //printf("nsTimerExpired for %p\n", aCallData); + nsTimerGtk* timer = (nsTimerGtk *)aCallData; + timer->FireTimeout(); + return 0; +} + +#if 1 +/* NS_GFXNONXP */ nsresult NS_NewTimer(nsITimer** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + nsTimerGtk *timer = new nsTimerGtk(); + if (nsnull == timer) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return timer->QueryInterface(kITimerIID, (void **) aInstancePtrResult); +} +#endif diff --git a/timer/src/unix/gtk/nsTimerGtk.h b/timer/src/unix/gtk/nsTimerGtk.h new file mode 100644 index 000000000000..d63b6bb0c69f --- /dev/null +++ b/timer/src/unix/gtk/nsTimerGtk.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef __nsTimerGtk_h +#define __nsTimerGtk_h + +#include "nsITimer.h" +#include "nsITimerCallback.h" + +#include + +/* + * Implementation of timers using Gtk timer facility + */ +class nsTimerGtk : public nsITimer +{ +public: + + nsTimerGtk(); + virtual ~nsTimerGtk(); + + virtual nsresult Init(nsTimerCallbackFunc aFunc, + void *aClosure, +// PRBool aRepeat, + PRUint32 aDelay); + + virtual nsresult Init(nsITimerCallback *aCallback, +// PRBool aRepeat, + PRUint32 aDelay); + + NS_DECL_ISUPPORTS + + virtual void Cancel(); + virtual PRUint32 GetDelay() { return mDelay; } + virtual void SetDelay(PRUint32 aDelay) { mDelay=aDelay; }; + virtual void* GetClosure() { return mClosure; } + + void FireTimeout(); + +private: + nsresult Init(PRUint32 aDelay); + + PRUint32 mDelay; + nsTimerCallbackFunc mFunc; + void * mClosure; + nsITimerCallback * mCallback; + // PRBool mRepeat; + nsTimerGtk * mNext; + guint mTimerId; +}; + +#endif // __nsTimerGtk_h diff --git a/timer/src/unix/motif/.cvsignore b/timer/src/unix/motif/.cvsignore new file mode 100644 index 000000000000..f3c7a7c5da68 --- /dev/null +++ b/timer/src/unix/motif/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/timer/src/unix/motif/Makefile.in b/timer/src/unix/motif/Makefile.in new file mode 100644 index 000000000000..0e53e0c9d70d --- /dev/null +++ b/timer/src/unix/motif/Makefile.in @@ -0,0 +1,47 @@ +#!gmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +LIBRARY_NAME = timer_motif_s +### XXX ### IS_COMPONENT=1 + +REQUIRES=xpcom + +### XXX ### DEFINES += -D_IMPL_NS_GFXNONXP +CXXFLAGS += $(TK_CFLAGS) +INCLUDES += $(TK_CFLAGS) -I$(srcdir)/.. + +CPPSRCS = \ + nsTimerMotif.cpp \ +### XXX ### nsTimerMotifFactory.cpp \ + $(NULL) + +### XXX ### EXTRA_DSO_LDOPTS += $(TK_LIBS) + +MKSHLIB = +override NO_SHARED_LIB=1 +override NO_STATIC_LIB= + +include $(topsrcdir)/config/rules.mk diff --git a/timer/src/unix/motif/nsTimerMotif.cpp b/timer/src/unix/motif/nsTimerMotif.cpp new file mode 100644 index 000000000000..c15439394cda --- /dev/null +++ b/timer/src/unix/motif/nsTimerMotif.cpp @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsTimerMotif.h" + +// #include "nsITimerCallback.h" +// #include "nsCRT.h" +// #include "prlog.h" +// #include +// #include +// #include + +static NS_DEFINE_IID(kITimerIID, NS_ITIMER_IID); + +// Hack for now. This is Bad because it creates a dependency between the widget +// library and this library. This needs to be replaced with having code +// to pass an interface which can be queried for the app context. +XtAppContext gAppContext; + +extern void nsTimerExpired(XtPointer aCallData); + + +void nsTimerMotif::FireTimeout() +{ + if (mFunc != NULL) { + (*mFunc)(this, mClosure); + } + else if (mCallback != NULL) { + mCallback->Notify(this); // Fire the timer + } + +// Always repeating here + +// if (mRepeat) +// mTimerId = XtAppAddTimeOut(gAppContext, GetDelay(),(XtTimerCallbackProc)nsTimerExpired, this); +} + + +nsTimerMotif::nsTimerMotif() +{ + NS_INIT_REFCNT(); + mFunc = NULL; + mCallback = NULL; + mNext = NULL; + mTimerId = 0; + mDelay = 0; + mClosure = NULL; +} + +nsTimerMotif::~nsTimerMotif() +{ +} + +nsresult +nsTimerMotif::Init(nsTimerCallbackFunc aFunc, + void *aClosure, +// PRBool aRepeat, + PRUint32 aDelay) +{ + mFunc = aFunc; + mClosure = aClosure; + // mRepeat = aRepeat; + + mTimerId = XtAppAddTimeOut(gAppContext, aDelay,(XtTimerCallbackProc)nsTimerExpired, this); + + return Init(aDelay); +} + +nsresult +nsTimerMotif::Init(nsITimerCallback *aCallback, +// PRBool aRepeat, + PRUint32 aDelay) +{ + mCallback = aCallback; + // mRepeat = aRepeat; + + mTimerId = XtAppAddTimeOut(gAppContext, aDelay, (XtTimerCallbackProc)nsTimerExpired, this); + + return Init(aDelay); +} + +nsresult +nsTimerMotif::Init(PRUint32 aDelay) +{ + mDelay = aDelay; + NS_ADDREF(this); + + return NS_OK; +} + +NS_IMPL_ISUPPORTS(nsTimerMotif, kITimerIID) + + +void +nsTimerMotif::Cancel() +{ + XtRemoveTimeOut(mTimerId); +} + +NS_GFX nsresult NS_NewTimer(nsITimer** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + nsTimerMotif *timer = new nsTimerMotif(); + if (nsnull == timer) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return timer->QueryInterface(kITimerIID, (void **) aInstancePtrResult); +} + + +void nsTimerExpired(XtPointer aCallData) +{ + nsTimerMotif* timer = (nsTimerMotif *)aCallData; + timer->FireTimeout(); +} + +#if 1 +/* NS_GFXNONXP */ nsresult NS_NewTimer(nsITimer** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + nsTimerMotif *timer = new nsTimerMotif(); + if (nsnull == timer) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return timer->QueryInterface(kITimerIID, (void **) aInstancePtrResult); +} +#endif diff --git a/timer/src/unix/motif/nsTimerMotif.h b/timer/src/unix/motif/nsTimerMotif.h new file mode 100644 index 000000000000..1716ba7634f6 --- /dev/null +++ b/timer/src/unix/motif/nsTimerMotif.h @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef __nsTimerMotif_h +#define __nsTimerMotif_h + +#include "nsITimer.h" +#include "nsITimerCallback.h" + +#include + +/* + * Implementation of timers using Xt timer facility + */ +class nsTimerMotif : public nsITimer +{ +public: + nsTimerMotif(); + virtual ~nsTimerMotif(); + + virtual nsresult Init(nsTimerCallbackFunc aFunc, + void *aClosure, +// PRBool aRepeat, + PRUint32 aDelay); + + virtual nsresult Init(nsITimerCallback *aCallback, +// PRBool aRepeat, + PRUint32 aDelay); + + NS_DECL_ISUPPORTS + + virtual void Cancel(); + virtual PRUint32 GetDelay() { return mDelay; } + virtual void SetDelay(PRUint32 aDelay) { mDelay=aDelay; }; + virtual void* GetClosure() { return mClosure; } + + void FireTimeout(); + +private: + nsresult Init(PRUint32 aDelay); + + PRUint32 mDelay; + nsTimerCallbackFunc mFunc; + void * mClosure; + nsITimerCallback * mCallback; + // PRBool mRepeat; + nsTimerMotif * mNext; + XtIntervalId mTimerId; +}; + +#endif // __nsTimerMotif_h diff --git a/timer/src/unix/xlib/.cvsignore b/timer/src/unix/xlib/.cvsignore new file mode 100644 index 000000000000..f3c7a7c5da68 --- /dev/null +++ b/timer/src/unix/xlib/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/timer/src/unix/xlib/Makefile.in b/timer/src/unix/xlib/Makefile.in new file mode 100644 index 000000000000..973a42438de5 --- /dev/null +++ b/timer/src/unix/xlib/Makefile.in @@ -0,0 +1,47 @@ +#!gmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +LIBRARY_NAME = timer_xlib_s +### XXX ### IS_COMPONENT=1 + +REQUIRES=xpcom + +### XXX ### DEFINES += -D_IMPL_NS_GFXNONXP +CXXFLAGS += $(TK_CFLAGS) +INCLUDES += $(TK_CFLAGS) -I$(srcdir)/.. + +CPPSRCS = \ + nsTimerXlib.cpp \ +### XXX ### nsTimerXlibFactory.cpp \ + $(NULL) + +### XXX ### EXTRA_DSO_LDOPTS += $(TK_LIBS) + +MKSHLIB = +override NO_SHARED_LIB=1 +override NO_STATIC_LIB= + +include $(topsrcdir)/config/rules.mk diff --git a/timer/src/unix/xlib/nsTimerXlib.cpp b/timer/src/unix/xlib/nsTimerXlib.cpp new file mode 100644 index 000000000000..7666aa008db4 --- /dev/null +++ b/timer/src/unix/xlib/nsTimerXlib.cpp @@ -0,0 +1,273 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsTimerXlib.h" + +#include +#include + +#include "prlog.h" + +static NS_DEFINE_IID(kITimerIID, NS_ITIMER_IID); + +extern "C" int NS_TimeToNextTimeout(struct timeval *aTimer); +extern "C" void NS_ProcessTimeouts(void); + +nsTimerXlib *nsTimerXlib::gTimerList = NULL; +struct timeval nsTimerXlib::gTimer = {0, 0}; +struct timeval nsTimerXlib::gNextFire = {0, 0}; + +nsTimerXlib::nsTimerXlib() +{ + //printf("nsTimerXlib::nsTimerXlib (%p) called.\n", + //this); + NS_INIT_REFCNT(); + mFunc = NULL; + mCallback = NULL; + mNext = NULL; + mClosure = NULL; +} + +nsTimerXlib::~nsTimerXlib() +{ + //printf("nsTimerXlib::~nsTimerXlib (%p) called.\n", + // this); + Cancel(); + NS_IF_RELEASE(mCallback); +} + +NS_IMPL_ISUPPORTS(nsTimerXlib, kITimerIID) + +nsresult +nsTimerXlib::Init(nsTimerCallbackFunc aFunc, + void *aClosure, + PRUint32 aDelay) +{ + mFunc = aFunc; + mClosure = aClosure; + return Init(aDelay); +} + +nsresult +nsTimerXlib::Init(nsITimerCallback *aCallback, + PRUint32 aDelay) +{ + mCallback = aCallback; + NS_ADDREF(mCallback); + + return Init(aDelay); +} + +nsresult +nsTimerXlib::Init(PRUint32 aDelay) +{ + struct timeval Now; + // printf("nsTimerXlib::Init (%p) called with delay %d\n", + //this, aDelay); + // get the cuurent time + gettimeofday(&Now, NULL); + mFireTime.tv_sec = Now.tv_sec + (aDelay / 1000); + mFireTime.tv_usec = Now.tv_usec + (aDelay * 1000); + //printf("fire set to %ld / %ld\n", + //mFireTime.tv_sec, mFireTime.tv_usec); + // set the next pointer to nothing. + mNext = NULL; + // add ourself to the list + if (!gTimerList) { + // no list here. I'm the start! + //printf("This is the beginning of the list..\n"); + gTimerList = this; + } + else { + // is it before everything else on the list? + if ((mFireTime.tv_sec < gTimerList->mFireTime.tv_sec) && + (mFireTime.tv_usec < gTimerList->mFireTime.tv_usec)) { + // printf("This is before the head of the list...\n"); + mNext = gTimerList; + gTimerList = this; + } + else { + nsTimerXlib *pPrev = gTimerList; + nsTimerXlib *pCurrent = gTimerList; + while (pCurrent && ((pCurrent->mFireTime.tv_sec <= mFireTime.tv_sec) && + (pCurrent->mFireTime.tv_usec <= mFireTime.tv_usec))) { + pPrev = pCurrent; + pCurrent = pCurrent->mNext; + } + PR_ASSERT(pPrev); + + // isnert it after pPrev ( this could be at the end of the list) + mNext = pPrev->mNext; + pPrev->mNext = this; + } + } + NS_ADDREF(this); + return NS_OK; +} + +void +nsTimerXlib::Fire(struct timeval *aNow) +{ + // printf("nsTimerXlib::Fire (%p) called at %ld / %ld\n", + // this, + //aNow->tv_sec, aNow->tv_usec); + if (mFunc != NULL) { + (*mFunc)(this, mClosure); + } + else if (mCallback != NULL) { + mCallback->Notify(this); + } +} + +void +nsTimerXlib::Cancel() +{ + nsTimerXlib *me = this; + nsTimerXlib *p; + // printf("nsTimerXlib::Cancel (%p) called.\n", + // this); + if (gTimerList == this) { + // first element in the list lossage... + gTimerList = mNext; + } + else { + // walk until there's no next pointer + for (p = gTimerList; p && p->mNext && (p->mNext != this); p = p->mNext) + ; + + // if we found something valid pull it out of the list + if (p && p->mNext && p->mNext == this) { + p->mNext = mNext; + } + else { + // get out before we delete something that looks bogus + return; + } + } + // if we got here it must have been a valid element so trash it + NS_RELEASE(me); + +} + +void +nsTimerXlib::ProcessTimeouts(struct timeval *aNow) +{ + nsTimerXlib *p = gTimerList; + if (aNow->tv_sec == 0 && + aNow->tv_usec == 0) { + gettimeofday(aNow, NULL); + } + // printf("nsTimerXlib::ProcessTimeouts called at %ld / %ld\n", + // aNow->tv_sec, aNow->tv_usec); + while (p) { + if ((p->mFireTime.tv_sec < aNow->tv_sec) || + ((p->mFireTime.tv_sec == aNow->tv_sec) && + (p->mFireTime.tv_usec <= aNow->tv_usec))) { + // Make sure that the timer cannot be deleted during the + // Fire(...) call which may release *all* other references + // to p... + //printf("Firing timeout for (%p)\n", + // p); + NS_ADDREF(p); + p->Fire(aNow); + // Clear the timer. + // Period synced. + p->Cancel(); + NS_RELEASE(p); + // Reset the loop (can't look at p->pNext now, and called + // code may have added/cleared timers). + // (could do this by going recursive and returning). + p = gTimerList; + } + else { + p = p->mNext; + } + } +} + +#if 0 +NS_GFX nsresult NS_NewTimer(nsITimer **aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + nsTimerXlib *timer = new nsTimerXlib(); + if (nsnull == timer) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return timer->QueryInterface(kITimerIID, (void **) aInstancePtrResult); +} +#endif + +int NS_TimeToNextTimeout(struct timeval *aTimer) { + nsTimerXlib *timer; + timer = nsTimerXlib::gTimerList; + if (timer) { + if ((timer->mFireTime.tv_sec < aTimer->tv_sec) || + ((timer->mFireTime.tv_sec == aTimer->tv_sec) && + (timer->mFireTime.tv_usec <= aTimer->tv_usec))) { + aTimer->tv_sec = 0; + aTimer->tv_usec = 0; + return 1; + } + else { + aTimer->tv_sec -= timer->mFireTime.tv_sec; + // handle the overflow case + if (aTimer->tv_usec < timer->mFireTime.tv_usec) { + aTimer->tv_usec = timer->mFireTime.tv_usec - aTimer->tv_usec; + // make sure we don't go past zero when we decrement + if (aTimer->tv_sec) + aTimer->tv_sec--; + } + else { + aTimer->tv_usec -= timer->mFireTime.tv_usec; + } + return 1; + } + } + else { + return 0; + } +} + +void NS_ProcessTimeouts(void) { + struct timeval now; + now.tv_sec = 0; + now.tv_usec = 0; + nsTimerXlib::ProcessTimeouts(&now); +} + +#if 1 +/* NS_GFXNONXP */ nsresult NS_NewTimer(nsITimer** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + nsTimerXlib *timer = new nsTimerXlib(); + if (nsnull == timer) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return timer->QueryInterface(kITimerIID, (void **) aInstancePtrResult); +} +#endif diff --git a/timer/src/unix/xlib/nsTimerXlib.h b/timer/src/unix/xlib/nsTimerXlib.h new file mode 100644 index 000000000000..5017374b087a --- /dev/null +++ b/timer/src/unix/xlib/nsTimerXlib.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef __nsTimerXlib_h +#define __nsTimerXlib_h + +#include "nsITimer.h" +#include "nsITimerCallback.h" + +#include + +class nsTimerXlib : public nsITimer +{ +public: + static nsTimerXlib *gTimerList; + static struct timeval gTimer; + static struct timeval gNextFire; + static void ProcessTimeouts(struct timeval *aNow); + nsTimerXlib(); + virtual ~nsTimerXlib(); + + virtual nsresult Init(nsTimerCallbackFunc aFunc, + void *aClosure, + PRUint32 aDelay); + + virtual nsresult Init(nsITimerCallback *aCallback, + PRUint32 aDelay); + + NS_DECL_ISUPPORTS + + virtual void Cancel(); + void Fire(struct timeval *aNow); + + virtual PRUint32 GetDelay() { return 0; }; + virtual void SetDelay(PRUint32 aDelay) {}; + virtual void *GetClosure() { return mClosure; } + + // this needs to be public so that the mainloop can + // find the next fire time... + struct timeval mFireTime; + nsTimerXlib * mNext; + +private: + nsresult Init(PRUint32 aDelay); + + nsTimerCallbackFunc mFunc; + void * mClosure; + PRUint32 mDelay; + nsITimerCallback * mCallback; +}; + +#endif // __nsTimerXlib_h diff --git a/timer/src/windows/makefile.win b/timer/src/windows/makefile.win new file mode 100644 index 000000000000..a155ac69c712 --- /dev/null +++ b/timer/src/windows/makefile.win @@ -0,0 +1,52 @@ +#!nmake +# +# The contents of this file are subject to the Netscape Public License +# Version 1.0 (the "NPL"); you may not use this file except in +# compliance with the NPL. You may obtain a copy of the NPL at +# http://www.mozilla.org/NPL/ +# +# Software distributed under the NPL is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL +# for the specific language governing rights and limitations under the +# NPL. +# +# The Initial Developer of this code under the NPL is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All Rights +# Reserved. + +DEPTH=..\..\.. +LIBRARY_NAME=timer_s + +DEFINES=#-D_IMPL_NS_GFX -D_IMPL_NS_GFXNONXP -DWIN32_LEAN_AND_MEAN -DSTRICT + +CPPSRCS = \ + nsTimer.cpp \ + $(NULL) + +MODULE=timer + +REQUIRES=xpcom + +CPP_OBJS= \ + .\$(OBJDIR)\nsTimer.obj \ + $(NULL) + +LINCS= \ + -I..\ + -I$(PUBLIC)\xpcom \ + $(NULL) + +LCFLAGS = \ + $(LCFLAGS) \ + $(DEFINES) \ + $(NULL) + +include <$(DEPTH)\config\rules.mak> + +libs:: $(LIBRARY) + $(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib + +clobber:: + rm -f $(DIST)\lib\$(LIBRARY_NAME).lib + rm -f $(PDBFILE).pdb diff --git a/timer/src/windows/nsTimer.cpp b/timer/src/windows/nsTimer.cpp new file mode 100644 index 000000000000..b652feecb707 --- /dev/null +++ b/timer/src/windows/nsTimer.cpp @@ -0,0 +1,362 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "nsITimer.h" +#include "nsITimerCallback.h" +#include "nsCRT.h" +#include "prlog.h" +#include +#include +#include + +static NS_DEFINE_IID(kITimerIID, NS_ITIMER_IID); + +/* + * Implementation of timers lifted from Windows front-end file timer.cpp + */ +class TimerImpl : public nsITimer { +public: + static TimerImpl *gTimerList; + static UINT gWindowsTimer; + static DWORD gNextFire; + + static void ProcessTimeouts(DWORD aNow); + static void SyncTimeoutPeriod(DWORD aTickCount); + +public: + TimerImpl(); + virtual ~TimerImpl(); + + virtual nsresult Init(nsTimerCallbackFunc aFunc, + void *aClosure, +// PRBool aRepeat, + PRUint32 aDelay); + + virtual nsresult Init(nsITimerCallback *aCallback, +// PRBool aRepeat, + PRUint32 aDelay); + + NS_DECL_ISUPPORTS + + virtual void Cancel(); + void Fire(DWORD aNow); + + virtual PRUint32 GetDelay() { return mDelay; } + virtual void SetDelay(PRUint32 aDelay) {}; + + virtual void* GetClosure() { return mClosure; } + +private: + nsresult Init(PRUint32 aDelay); + + PRUint32 mDelay; + nsTimerCallbackFunc mFunc; + void *mClosure; + nsITimerCallback *mCallback; + DWORD mFireTime; + // PRBool mRepeat; + TimerImpl *mNext; +}; + +TimerImpl *TimerImpl::gTimerList = NULL; +UINT TimerImpl::gWindowsTimer = 0; +DWORD TimerImpl::gNextFire = (DWORD)-1; + +void CALLBACK FireTimeout(HWND aWindow, + UINT aMessage, + UINT aTimerID, + DWORD aTime) +{ + static BOOL bCanEnter = TRUE; + + // Don't allow old timer messages in here. + if(aMessage != WM_TIMER) { + PR_ASSERT(0); + return; + } + + if(aTimerID != TimerImpl::gWindowsTimer) { + return; + } + + // Block only one entry into this function, or else. + if(bCanEnter) { + bCanEnter = FALSE; + // see if we need to fork off any timeout functions + if(TimerImpl::gTimerList) { + TimerImpl::ProcessTimeouts(aTime); + } + bCanEnter = TRUE; + } +} + +// Function to correctly have the timer be set. +void +TimerImpl::SyncTimeoutPeriod(DWORD aTickCount) +{ + // May want us to set tick count ourselves. + if(aTickCount == 0) { + aTickCount = ::GetTickCount(); + } + + // If there's no list, we should clear the timer. + if(!gTimerList) { + if(gWindowsTimer) { + ::KillTimer(NULL, gWindowsTimer); + gWindowsTimer = 0; + gNextFire = (DWORD)-1; + } + } + else { + // See if we need to clear the current timer. + // Curcumstances are that if the timer will not + // fire on time for the next timeout. + BOOL bSetTimer = FALSE; + TimerImpl *pTimeout = gTimerList; + if(gWindowsTimer) { + if(pTimeout->mFireTime != gNextFire) { + ::KillTimer(NULL, gWindowsTimer); + gWindowsTimer = 0; + gNextFire = (DWORD)-1; + + // Set the timer. + bSetTimer = TRUE; + } + } + else { + // No timer set, attempt. + bSetTimer = TRUE; + } + + if(bSetTimer) { + DWORD dwFireWhen = pTimeout->mFireTime > aTickCount ? + pTimeout->mFireTime - aTickCount : 0; + if(dwFireWhen > UINT_MAX) { + dwFireWhen = UINT_MAX; + } + UINT uFireWhen = (UINT)dwFireWhen; + + PR_ASSERT(gWindowsTimer == 0); + gWindowsTimer = ::SetTimer(NULL, 0, uFireWhen, (TIMERPROC)FireTimeout); + + if(gWindowsTimer) { + // Set the fire time. + gNextFire = pTimeout->mFireTime; + } + } + } +} + +// Walk down the timeout list and launch anyone appropriate +void +TimerImpl::ProcessTimeouts(DWORD aNow) +{ + TimerImpl *p = gTimerList; + if(aNow == 0) { + aNow = ::GetTickCount(); + } + + BOOL bCalledSync = FALSE; + + // loop over all entries + while(p) { + // send it + if(p->mFireTime < aNow) { + // Make sure that the timer cannot be deleted during the + // Fire(...) call which may release *all* other references + // to p... + NS_ADDREF(p); + p->Fire(aNow); + + // Clear the timer. + // Period synced. + p->Cancel(); + bCalledSync = TRUE; + NS_RELEASE(p); + + // Reset the loop (can't look at p->pNext now, and called + // code may have added/cleared timers). + // (could do this by going recursive and returning). + p = gTimerList; + } else { + // Make sure we fire an timer. + // Also, we need to check to see if things are backing up (they + // may be asking to be fired long before we ever get to them, + // and we don't want to pass in negative values to the real + // timer code, or it takes days to fire.... + if(bCalledSync == FALSE) { + SyncTimeoutPeriod(aNow); + bCalledSync = TRUE; + } + // Get next timer. + p = p->mNext; + } + } +} + + +TimerImpl::TimerImpl() +{ + NS_INIT_REFCNT(); + mFunc = NULL; + mCallback = NULL; + mNext = NULL; + mClosure = nsnull; +} + +TimerImpl::~TimerImpl() +{ + Cancel(); + NS_IF_RELEASE(mCallback); +} + +nsresult +TimerImpl::Init(nsTimerCallbackFunc aFunc, + void *aClosure, +// PRBool aRepeat, + PRUint32 aDelay) +{ + mFunc = aFunc; + mClosure = aClosure; + // mRepeat = aRepeat; + + return Init(aDelay); +} + +nsresult +TimerImpl::Init(nsITimerCallback *aCallback, +// PRBool aRepeat, + PRUint32 aDelay) +{ + mCallback = aCallback; + NS_ADDREF(mCallback); + // mRepeat = aRepeat; + + return Init(aDelay); +} + +nsresult +TimerImpl::Init(PRUint32 aDelay) +{ + DWORD dwNow = ::GetTickCount(); + + mDelay = aDelay; + mFireTime = (DWORD) aDelay + dwNow; + mNext = NULL; + + // add it to the list + if(!gTimerList) { + // no list add it + gTimerList = this; + } + else { + + // is it before everything else on the list? + if(mFireTime < gTimerList->mFireTime) { + + mNext = gTimerList; + gTimerList = this; + + } else { + + TimerImpl * pPrev = gTimerList; + TimerImpl * pCurrent = gTimerList; + + while(pCurrent && (pCurrent->mFireTime <= mFireTime)) { + pPrev = pCurrent; + pCurrent = pCurrent->mNext; + } + + PR_ASSERT(pPrev); + + // insert it after pPrev (this could be at the end of the list) + mNext = pPrev->mNext; + pPrev->mNext = this; + + } + + } + + NS_ADDREF(this); + + // Sync the timer fire period. + SyncTimeoutPeriod(dwNow); + + return NS_OK; +} + +NS_IMPL_ISUPPORTS(TimerImpl, kITimerIID) + +void +TimerImpl::Fire(DWORD aNow) +{ + if (mFunc != NULL) { + (*mFunc)(this, mClosure); + } + else if (mCallback != NULL) { + mCallback->Notify(this); + } +} + +void +TimerImpl::Cancel() +{ + TimerImpl *me = this; + + if(gTimerList == this) { + + // first element in the list lossage + gTimerList = mNext; + + } else { + + // walk until no next pointer + for(TimerImpl * p = gTimerList; p && p->mNext && (p->mNext != this); p = p->mNext) + ; + + // if we found something valid pull it out of the list + if(p && p->mNext && p->mNext == this) { + p->mNext = mNext; + + } else { + // get out before we delete something that looks bogus + return; + } + + } + + // if we got here it must have been a valid element so trash it + NS_RELEASE(me); + + // If there's now no be sure to clear the timer. + SyncTimeoutPeriod(0); +} + +NS_GFX nsresult NS_NewTimer(nsITimer** aInstancePtrResult) +{ + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if (nsnull == aInstancePtrResult) { + return NS_ERROR_NULL_POINTER; + } + + TimerImpl *timer = new TimerImpl(); + if (nsnull == timer) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return timer->QueryInterface(kITimerIID, (void **) aInstancePtrResult); +}