summaryrefslogtreecommitdiffstats
path: root/src/libs/xpcom18a4/xpcom/threads
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/xpcom18a4/xpcom/threads')
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/Makefile.in105
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/TimerThread.cpp462
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/TimerThread.h122
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsAutoLock.cpp435
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h383
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsEnvironment.cpp202
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsEnvironment.h67
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsEventQueue.cpp632
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsEventQueue.h89
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.cpp450
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.h77
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsEventQueueUtils.h78
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsIEnvironment.idl89
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsIEventQueue.idl107
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsIEventQueueService.idl151
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsIEventTarget.idl67
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsIProcess.idl32
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsIRunnable.idl44
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsIThread.idl144
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsITimer.idl191
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsITimerInternal.idl48
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsITimerManager.idl61
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsPIEventQueueChain.h93
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsProcess.h71
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsProcessCommon.cpp363
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsProcessMac.cpp188
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsThread.cpp457
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsThread.h92
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.cpp642
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.h195
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/plevent.c1774
-rw-r--r--src/libs/xpcom18a4/xpcom/threads/plevent.h690
33 files changed, 8602 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/xpcom/threads/.cvsignore b/src/libs/xpcom18a4/xpcom/threads/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/xpcom/threads/Makefile.in b/src/libs/xpcom18a4/xpcom/threads/Makefile.in
new file mode 100644
index 00000000..83433706
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/Makefile.in
@@ -0,0 +1,105 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1998
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of the GNU General Public License Version 2 or later (the "GPL"),
+# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = xpcom
+ifeq ($(OS_ARCH),WINNT)
+XPIDL_MODULE = xpcom_thread
+else
+XPIDL_MODULE = xpcom_threads
+endif
+LIBRARY_NAME = xpcomthreads_s
+GRE_MODULE = 1
+REQUIRES = string \
+ $(NULL)
+
+
+CSRCS = \
+ plevent.c \
+ $(NULL)
+
+CPPSRCS = \
+ nsAutoLock.cpp \
+ nsEnvironment.cpp \
+ nsEventQueue.cpp \
+ nsEventQueueService.cpp \
+ nsThread.cpp \
+ nsTimerImpl.cpp \
+ nsProcessCommon.cpp \
+ TimerThread.cpp \
+ $(NULL)
+
+EXPORTS = \
+ nsAutoLock.h \
+ plevent.h \
+ nsProcess.h \
+ nsEventQueueUtils.h \
+ $(NULL)
+
+XPIDLSRCS = \
+ nsIThread.idl \
+ nsITimer.idl \
+ nsITimerInternal.idl \
+ nsITimerManager.idl \
+ nsIRunnable.idl \
+ nsIEventTarget.idl \
+ nsIEventQueue.idl \
+ nsIEventQueueService.idl \
+ nsIEnvironment.idl \
+ nsIProcess.idl \
+ $(NULL)
+
+EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS))
+
+LOCAL_INCLUDES = -I$(srcdir)/../components
+
+# we don't want the shared lib, but we want to force the creation of a static lib.
+FORCE_STATIC_LIB = 1
+
+# Force use of PIC
+FORCE_USE_PIC = 1
+
+include $(topsrcdir)/config/rules.mk
+
+DEFINES += -D_IMPL_NS_COM
+
diff --git a/src/libs/xpcom18a4/xpcom/threads/TimerThread.cpp b/src/libs/xpcom18a4/xpcom/threads/TimerThread.cpp
new file mode 100644
index 00000000..94076892
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/TimerThread.cpp
@@ -0,0 +1,462 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Stuart Parmenter <pavlov@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsTimerImpl.h"
+#include "TimerThread.h"
+
+#include "nsAutoLock.h"
+#include "pratom.h"
+
+#include "nsIObserverService.h"
+#include "nsIServiceManager.h"
+
+NS_IMPL_THREADSAFE_ISUPPORTS3(TimerThread, nsIRunnable, nsISupportsWeakReference, nsIObserver)
+
+TimerThread::TimerThread() :
+ mInitInProgress(0),
+ mInitialized(PR_FALSE),
+ mLock(nsnull),
+ mCondVar(nsnull),
+ mShutdown(PR_FALSE),
+ mWaiting(PR_FALSE),
+ mSleeping(PR_FALSE),
+ mDelayLineCounter(0),
+ mMinTimerPeriod(0),
+ mTimeoutAdjustment(0)
+{
+}
+
+TimerThread::~TimerThread()
+{
+ if (mCondVar)
+ PR_DestroyCondVar(mCondVar);
+ if (mLock)
+ PR_DestroyLock(mLock);
+
+ mThread = nsnull;
+
+ PRInt32 n = mTimers.Count();
+ while (--n >= 0) {
+ nsTimerImpl *timer = NS_STATIC_CAST(nsTimerImpl *, mTimers[n]);
+ NS_RELEASE(timer);
+ }
+
+ nsCOMPtr<nsIObserverService> observerService = do_GetService("@mozilla.org/observer-service;1");
+ if (observerService) {
+ observerService->RemoveObserver(this, "sleep_notification");
+ observerService->RemoveObserver(this, "wake_notification");
+ }
+
+}
+
+nsresult
+TimerThread::InitLocks()
+{
+ NS_ASSERTION(!mLock, "InitLocks called twice?");
+ mLock = PR_NewLock();
+ if (!mLock)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ mCondVar = PR_NewCondVar(mLock);
+ if (!mCondVar)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ return NS_OK;
+}
+
+nsresult TimerThread::Init()
+{
+ if (mInitialized) {
+ if (!mThread)
+ return NS_ERROR_FAILURE;
+
+ return NS_OK;
+ }
+
+ if (PR_AtomicSet(&mInitInProgress, 1) == 0) {
+ nsresult rv;
+
+ mEventQueueService = do_GetService("@mozilla.org/event-queue-service;1", &rv);
+ if (NS_SUCCEEDED(rv)) {
+ nsCOMPtr<nsIObserverService> observerService
+ (do_GetService("@mozilla.org/observer-service;1", &rv));
+
+ if (NS_SUCCEEDED(rv)) {
+ // We hold on to mThread to keep the thread alive.
+ rv = NS_NewThread(getter_AddRefs(mThread),
+ NS_STATIC_CAST(nsIRunnable*, this),
+ 0,
+ PR_JOINABLE_THREAD,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD);
+
+ if (NS_FAILED(rv)) {
+ mThread = nsnull;
+ }
+ else {
+ observerService->AddObserver(this, "sleep_notification", PR_TRUE);
+ observerService->AddObserver(this, "wake_notification", PR_TRUE);
+ }
+ }
+ }
+
+ PR_Lock(mLock);
+ mInitialized = PR_TRUE;
+ PR_NotifyAllCondVar(mCondVar);
+ PR_Unlock(mLock);
+ }
+ else {
+ PR_Lock(mLock);
+ while (!mInitialized) {
+ PR_WaitCondVar(mCondVar, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(mLock);
+ }
+
+ if (!mThread)
+ return NS_ERROR_FAILURE;
+
+ return NS_OK;
+}
+
+nsresult TimerThread::Shutdown()
+{
+ if (!mThread)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ { // lock scope
+ nsAutoLock lock(mLock);
+
+ mShutdown = PR_TRUE;
+
+ // notify the cond var so that Run() can return
+ if (mCondVar && mWaiting)
+ PR_NotifyCondVar(mCondVar);
+
+ nsTimerImpl *timer;
+ for (PRInt32 i = mTimers.Count() - 1; i >= 0; i--) {
+ timer = NS_STATIC_CAST(nsTimerImpl*, mTimers[i]);
+ RemoveTimerInternal(timer);
+ }
+ }
+
+ mThread->Join(); // wait for the thread to die
+ return NS_OK;
+}
+
+// Keep track of how early (positive slack) or late (negative slack) timers
+// are running, and use the filtered slack number to adaptively estimate how
+// early timers should fire to be "on time".
+void TimerThread::UpdateFilter(PRUint32 aDelay, PRIntervalTime aTimeout,
+ PRIntervalTime aNow)
+{
+ PRInt32 slack = (PRInt32) (aTimeout - aNow);
+ double smoothSlack = 0;
+ PRUint32 i, filterLength;
+ static PRIntervalTime kFilterFeedbackMaxTicks =
+ PR_MillisecondsToInterval(FILTER_FEEDBACK_MAX);
+
+ if (slack > 0) {
+ if (slack > (PRInt32)kFilterFeedbackMaxTicks)
+ slack = kFilterFeedbackMaxTicks;
+ } else {
+ if (slack < -(PRInt32)kFilterFeedbackMaxTicks)
+ slack = -(PRInt32)kFilterFeedbackMaxTicks;
+ }
+ mDelayLine[mDelayLineCounter & DELAY_LINE_LENGTH_MASK] = slack;
+ if (++mDelayLineCounter < DELAY_LINE_LENGTH) {
+ // Startup mode: accumulate a full delay line before filtering.
+ PR_ASSERT(mTimeoutAdjustment == 0);
+ filterLength = 0;
+ } else {
+ // Past startup: compute number of filter taps based on mMinTimerPeriod.
+ if (mMinTimerPeriod == 0) {
+ mMinTimerPeriod = (aDelay != 0) ? aDelay : 1;
+ } else if (aDelay != 0 && aDelay < mMinTimerPeriod) {
+ mMinTimerPeriod = aDelay;
+ }
+
+ filterLength = (PRUint32) (FILTER_DURATION / mMinTimerPeriod);
+ if (filterLength > DELAY_LINE_LENGTH)
+ filterLength = DELAY_LINE_LENGTH;
+ else if (filterLength < 4)
+ filterLength = 4;
+
+ for (i = 1; i <= filterLength; i++)
+ smoothSlack += mDelayLine[(mDelayLineCounter-i) & DELAY_LINE_LENGTH_MASK];
+ smoothSlack /= filterLength;
+
+ // XXXbe do we need amplification? hacking a fudge factor, need testing...
+ mTimeoutAdjustment = (PRInt32) (smoothSlack * 1.5);
+ }
+
+#ifdef DEBUG_TIMERS
+ if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
+ PR_LOG(gTimerLog, PR_LOG_DEBUG,
+ ("UpdateFilter: smoothSlack = %g, filterLength = %u\n",
+ smoothSlack, filterLength));
+ }
+#endif
+}
+
+/* void Run(); */
+NS_IMETHODIMP TimerThread::Run()
+{
+ nsAutoLock lock(mLock);
+
+ while (!mShutdown) {
+ PRIntervalTime waitFor;
+
+ if (mSleeping) {
+ // Sleep for 0.1 seconds while not firing timers.
+ waitFor = PR_MillisecondsToInterval(100);
+ } else {
+ waitFor = PR_INTERVAL_NO_TIMEOUT;
+ PRIntervalTime now = PR_IntervalNow();
+ nsTimerImpl *timer = nsnull;
+
+ if (mTimers.Count() > 0) {
+ timer = NS_STATIC_CAST(nsTimerImpl*, mTimers[0]);
+
+ if (!TIMER_LESS_THAN(now, timer->mTimeout + mTimeoutAdjustment)) {
+ next:
+ // NB: AddRef before the Release under RemoveTimerInternal to avoid
+ // mRefCnt passing through zero, in case all other refs than the one
+ // from mTimers have gone away (the last non-mTimers[i]-ref's Release
+ // must be racing with us, blocked in gThread->RemoveTimer waiting
+ // for TimerThread::mLock, under nsTimerImpl::Release.
+
+ NS_ADDREF(timer);
+ RemoveTimerInternal(timer);
+
+ // We release mLock around the Fire call to avoid deadlock.
+ lock.unlock();
+
+#ifdef DEBUG_TIMERS
+ if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
+ PR_LOG(gTimerLog, PR_LOG_DEBUG,
+ ("Timer thread woke up %dms from when it was supposed to\n",
+ (now >= timer->mTimeout)
+ ? PR_IntervalToMilliseconds(now - timer->mTimeout)
+ : -(PRInt32)PR_IntervalToMilliseconds(timer->mTimeout-now))
+ );
+ }
+#endif
+
+ // We are going to let the call to PostTimerEvent here handle the
+ // release of the timer so that we don't end up releasing the timer
+ // on the TimerThread instead of on the thread it targets.
+ timer->PostTimerEvent();
+ timer = nsnull;
+
+ lock.lock();
+ if (mShutdown)
+ break;
+
+ // Update now, as PostTimerEvent plus the locking may have taken a
+ // tick or two, and we may goto next below.
+ now = PR_IntervalNow();
+ }
+ }
+
+ if (mTimers.Count() > 0) {
+ timer = NS_STATIC_CAST(nsTimerImpl *, mTimers[0]);
+
+ PRIntervalTime timeout = timer->mTimeout + mTimeoutAdjustment;
+
+ // Don't wait at all (even for PR_INTERVAL_NO_WAIT) if the next timer
+ // is due now or overdue.
+ if (!TIMER_LESS_THAN(now, timeout))
+ goto next;
+ waitFor = timeout - now;
+ }
+
+#ifdef DEBUG_TIMERS
+ if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
+ if (waitFor == PR_INTERVAL_NO_TIMEOUT)
+ PR_LOG(gTimerLog, PR_LOG_DEBUG,
+ ("waiting for PR_INTERVAL_NO_TIMEOUT\n"));
+ else
+ PR_LOG(gTimerLog, PR_LOG_DEBUG,
+ ("waiting for %u\n", PR_IntervalToMilliseconds(waitFor)));
+ }
+#endif
+ }
+
+ mWaiting = PR_TRUE;
+ PR_WaitCondVar(mCondVar, waitFor);
+ mWaiting = PR_FALSE;
+ }
+
+ return NS_OK;
+}
+
+nsresult TimerThread::AddTimer(nsTimerImpl *aTimer)
+{
+ nsAutoLock lock(mLock);
+
+ // Add the timer to our list.
+ PRInt32 i = AddTimerInternal(aTimer);
+ if (i < 0)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ // Awaken the timer thread.
+ if (mCondVar && mWaiting && i == 0)
+ PR_NotifyCondVar(mCondVar);
+
+ return NS_OK;
+}
+
+nsresult TimerThread::TimerDelayChanged(nsTimerImpl *aTimer)
+{
+ nsAutoLock lock(mLock);
+
+ // Our caller has a strong ref to aTimer, so it can't go away here under
+ // ReleaseTimerInternal.
+ RemoveTimerInternal(aTimer);
+
+ PRInt32 i = AddTimerInternal(aTimer);
+ if (i < 0)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ // Awaken the timer thread.
+ if (mCondVar && mWaiting && i == 0)
+ PR_NotifyCondVar(mCondVar);
+
+ return NS_OK;
+}
+
+nsresult TimerThread::RemoveTimer(nsTimerImpl *aTimer)
+{
+ nsAutoLock lock(mLock);
+
+ // Remove the timer from our array. Tell callers that aTimer was not found
+ // by returning NS_ERROR_NOT_AVAILABLE. Unlike the TimerDelayChanged case
+ // immediately above, our caller may be passing a (now-)weak ref in via the
+ // aTimer param, specifically when nsTimerImpl::Release loses a race with
+ // TimerThread::Run, must wait for the mLock auto-lock here, and during the
+ // wait Run drops the only remaining ref to aTimer via RemoveTimerInternal.
+
+ if (!RemoveTimerInternal(aTimer))
+ return NS_ERROR_NOT_AVAILABLE;
+
+ // Awaken the timer thread.
+ if (mCondVar && mWaiting)
+ PR_NotifyCondVar(mCondVar);
+
+ return NS_OK;
+}
+
+// This function must be called from within a lock
+PRInt32 TimerThread::AddTimerInternal(nsTimerImpl *aTimer)
+{
+ PRIntervalTime now = PR_IntervalNow();
+ PRInt32 count = mTimers.Count();
+ PRInt32 i = 0;
+ for (; i < count; i++) {
+ nsTimerImpl *timer = NS_STATIC_CAST(nsTimerImpl *, mTimers[i]);
+
+ // Don't break till we have skipped any overdue timers. Do not include
+ // mTimeoutAdjustment here, because we are really trying to avoid calling
+ // TIMER_LESS_THAN(t, u), where the t is now + DELAY_INTERVAL_MAX, u is
+ // now - overdue, and DELAY_INTERVAL_MAX + overdue > DELAY_INTERVAL_LIMIT.
+ // In other words, we want to use now-based time, now adjusted time, even
+ // though "overdue" ultimately depends on adjusted time.
+
+ // XXX does this hold for TYPE_REPEATING_PRECISE? /be
+
+ if (TIMER_LESS_THAN(now, timer->mTimeout) &&
+ TIMER_LESS_THAN(aTimer->mTimeout, timer->mTimeout)) {
+ break;
+ }
+ }
+
+ if (!mTimers.InsertElementAt(aTimer, i))
+ return -1;
+
+ aTimer->mArmed = PR_TRUE;
+ NS_ADDREF(aTimer);
+ return i;
+}
+
+PRBool TimerThread::RemoveTimerInternal(nsTimerImpl *aTimer)
+{
+ if (!mTimers.RemoveElement(aTimer))
+ return PR_FALSE;
+
+ // Order is crucial here -- see nsTimerImpl::Release.
+ aTimer->mArmed = PR_FALSE;
+ NS_RELEASE(aTimer);
+ return PR_TRUE;
+}
+
+void TimerThread::DoBeforeSleep()
+{
+ mSleeping = PR_TRUE;
+}
+
+void TimerThread::DoAfterSleep()
+{
+ for (PRInt32 i = 0; i < mTimers.Count(); i ++) {
+ nsTimerImpl *timer = NS_STATIC_CAST(nsTimerImpl*, mTimers[i]);
+ // get and set the delay to cause its timeout to be recomputed
+ PRUint32 delay;
+ timer->GetDelay(&delay);
+ timer->SetDelay(delay);
+ }
+
+ // nuke the stored adjustments, so they get recalibrated
+ mTimeoutAdjustment = 0;
+ mDelayLineCounter = 0;
+ mSleeping = PR_FALSE;
+}
+
+
+/* void observe (in nsISupports aSubject, in string aTopic, in wstring aData); */
+NS_IMETHODIMP
+TimerThread::Observe(nsISupports* /* aSubject */, const char *aTopic, const PRUnichar* /* aData */)
+{
+ if (strcmp(aTopic, "sleep_notification") == 0)
+ DoBeforeSleep();
+ else if (strcmp(aTopic, "wake_notification") == 0)
+ DoAfterSleep();
+
+ return NS_OK;
+}
diff --git a/src/libs/xpcom18a4/xpcom/threads/TimerThread.h b/src/libs/xpcom18a4/xpcom/threads/TimerThread.h
new file mode 100644
index 00000000..fa23cfc9
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/TimerThread.h
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Stuart Parmenter <pavlov@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef TimerThread_h___
+#define TimerThread_h___
+
+#include "nsWeakReference.h"
+
+#include "nsIEventQueueService.h"
+#include "nsIObserver.h"
+#include "nsIRunnable.h"
+#include "nsIThread.h"
+
+#include "nsTimerImpl.h"
+
+#include "nsVoidArray.h"
+
+#include "prcvar.h"
+#include "prinrval.h"
+#include "prlock.h"
+
+class TimerThread : public nsSupportsWeakReference,
+ public nsIRunnable,
+ public nsIObserver
+{
+public:
+ TimerThread();
+ NS_HIDDEN_(nsresult) InitLocks();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIRUNNABLE
+ NS_DECL_NSIOBSERVER
+
+ NS_HIDDEN_(nsresult) Init();
+ NS_HIDDEN_(nsresult) Shutdown();
+
+ nsresult AddTimer(nsTimerImpl *aTimer);
+ nsresult TimerDelayChanged(nsTimerImpl *aTimer);
+ nsresult RemoveTimer(nsTimerImpl *aTimer);
+
+#define FILTER_DURATION 1e3 /* one second */
+#define FILTER_FEEDBACK_MAX 100 /* 1/10th of a second */
+
+ void UpdateFilter(PRUint32 aDelay, PRIntervalTime aTimeout,
+ PRIntervalTime aNow);
+
+ // For use by nsTimerImpl::Fire()
+ nsCOMPtr<nsIEventQueueService> mEventQueueService;
+
+ void DoBeforeSleep();
+ void DoAfterSleep();
+
+private:
+ ~TimerThread();
+
+ PRInt32 mInitInProgress;
+ PRBool mInitialized;
+
+ // These two internal helper methods must be called while mLock is held.
+ // AddTimerInternal returns the position where the timer was added in the
+ // list, or -1 if it failed.
+ PRInt32 AddTimerInternal(nsTimerImpl *aTimer);
+ PRBool RemoveTimerInternal(nsTimerImpl *aTimer);
+
+ nsCOMPtr<nsIThread> mThread;
+ PRLock *mLock;
+ PRCondVar *mCondVar;
+
+ PRPackedBool mShutdown;
+ PRPackedBool mWaiting;
+ PRPackedBool mSleeping;
+
+ nsVoidArray mTimers;
+
+#define DELAY_LINE_LENGTH_LOG2 5
+#define DELAY_LINE_LENGTH_MASK PR_BITMASK(DELAY_LINE_LENGTH_LOG2)
+#define DELAY_LINE_LENGTH PR_BIT(DELAY_LINE_LENGTH_LOG2)
+
+ PRInt32 mDelayLine[DELAY_LINE_LENGTH];
+ PRUint32 mDelayLineCounter;
+ PRUint32 mMinTimerPeriod; // milliseconds
+ PRInt32 mTimeoutAdjustment;
+};
+
+#endif /* TimerThread_h___ */
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.cpp b/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.cpp
new file mode 100644
index 00000000..df89408c
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.cpp
@@ -0,0 +1,435 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsAutoLock.h"
+
+#ifdef DEBUG
+
+#include "plhash.h"
+#include "prprf.h"
+#include "prlock.h"
+#include "prthread.h"
+#include "nsDebug.h"
+#include "nsVoidArray.h"
+
+#ifdef NS_TRACE_MALLOC_XXX
+# include <stdio.h>
+# include "nsTraceMalloc.h"
+#endif
+
+static PRUintn LockStackTPI = (PRUintn)-1;
+static PLHashTable* OrderTable = 0;
+static PRLock* OrderTableLock = 0;
+
+static const char* const LockTypeNames[] = {"Lock", "Monitor", "CMonitor"};
+
+struct nsNamedVector : public nsVoidArray {
+ const char* mName;
+
+#ifdef NS_TRACE_MALLOC_XXX
+ // Callsites for the inner locks/monitors stored in our base nsVoidArray.
+ // This array parallels our base nsVoidArray.
+ nsVoidArray mInnerSites;
+#endif
+
+ nsNamedVector(const char* name = 0, PRUint32 initialSize = 0)
+ : nsVoidArray(initialSize),
+ mName(name)
+ {
+ }
+};
+
+static void * PR_CALLBACK
+_hash_alloc_table(void *pool, PRSize size)
+{
+ return operator new(size);
+}
+
+static void PR_CALLBACK
+_hash_free_table(void *pool, void *item)
+{
+ operator delete(item);
+}
+
+static PLHashEntry * PR_CALLBACK
+_hash_alloc_entry(void *pool, const void *key)
+{
+ return new PLHashEntry;
+}
+
+/*
+ * Because monitors and locks may be associated with an nsAutoLockBase,
+ * without having had their associated nsNamedVector created explicitly in
+ * nsAutoMonitor::NewMonitor/DeleteMonitor, we need to provide a freeEntry
+ * PLHashTable hook, to avoid leaking nsNamedVectors which are replaced by
+ * nsAutoMonitor::NewMonitor.
+ *
+ * There is still a problem with the OrderTable containing orphaned
+ * nsNamedVector entries, for manually created locks wrapped by nsAutoLocks.
+ * (there should be no manually created monitors wrapped by nsAutoMonitors:
+ * you should use nsAutoMonitor::NewMonitor and nsAutoMonitor::DestroyMonitor
+ * instead of PR_NewMonitor and PR_DestroyMonitor). These lock vectors don't
+ * strictly leak, as they are killed on shutdown, but there are unnecessary
+ * named vectors in the hash table that outlive their associated locks.
+ *
+ * XXX so we should have nsLock, nsMonitor, etc. and strongly type their
+ * XXX nsAutoXXX counterparts to take only the non-auto types as inputs
+ */
+static void PR_CALLBACK
+_hash_free_entry(void *pool, PLHashEntry *entry, PRUintn flag)
+{
+ nsNamedVector* vec = (nsNamedVector*) entry->value;
+ if (vec) {
+ entry->value = 0;
+ delete vec;
+ }
+ if (flag == HT_FREE_ENTRY)
+ delete entry;
+}
+
+static const PLHashAllocOps _hash_alloc_ops = {
+ _hash_alloc_table, _hash_free_table,
+ _hash_alloc_entry, _hash_free_entry
+};
+
+PR_STATIC_CALLBACK(PRIntn)
+_purge_one(PLHashEntry* he, PRIntn cnt, void* arg)
+{
+ nsNamedVector* vec = (nsNamedVector*) he->value;
+
+ if (he->key == arg)
+ return HT_ENUMERATE_REMOVE;
+ vec->RemoveElement(arg);
+ return HT_ENUMERATE_NEXT;
+}
+
+PR_STATIC_CALLBACK(void)
+OnMonitorRecycle(void* addr)
+{
+ PR_Lock(OrderTableLock);
+ PL_HashTableEnumerateEntries(OrderTable, _purge_one, addr);
+ PR_Unlock(OrderTableLock);
+}
+
+PR_STATIC_CALLBACK(PLHashNumber)
+_hash_pointer(const void* key)
+{
+ return PLHashNumber(NS_PTR_TO_INT32(key)) >> 2;
+}
+
+// Must be single-threaded here, early in primordial thread.
+static void InitAutoLockStatics()
+{
+ (void) PR_NewThreadPrivateIndex(&LockStackTPI, 0);
+ OrderTable = PL_NewHashTable(64, _hash_pointer,
+ PL_CompareValues, PL_CompareValues,
+ &_hash_alloc_ops, 0);
+ if (OrderTable && !(OrderTableLock = PR_NewLock())) {
+ PL_HashTableDestroy(OrderTable);
+ OrderTable = 0;
+ }
+ PR_CSetOnMonitorRecycle(OnMonitorRecycle);
+}
+
+void _FreeAutoLockStatics()
+{
+ PLHashTable* table = OrderTable;
+ if (!table) return;
+
+ // Called at shutdown, so we don't need to lock.
+ PR_CSetOnMonitorRecycle(0);
+ PR_DestroyLock(OrderTableLock);
+ OrderTableLock = 0;
+ PL_HashTableDestroy(table);
+ OrderTable = 0;
+}
+
+static nsNamedVector* GetVector(PLHashTable* table, const void* key)
+{
+ PLHashNumber hash = _hash_pointer(key);
+ PLHashEntry** hep = PL_HashTableRawLookup(table, hash, key);
+ PLHashEntry* he = *hep;
+ if (he)
+ return (nsNamedVector*) he->value;
+ nsNamedVector* vec = new nsNamedVector();
+ if (vec)
+ PL_HashTableRawAdd(table, hep, hash, key, vec);
+ return vec;
+}
+
+// We maintain an acyclic graph in OrderTable, so recursion can't diverge.
+static PRBool Reachable(PLHashTable* table, const void* goal, const void* start)
+{
+ PR_ASSERT(goal);
+ PR_ASSERT(start);
+ nsNamedVector* vec = GetVector(table, start);
+ for (PRUint32 i = 0, n = vec->Count(); i < n; i++) {
+ void* addr = vec->ElementAt(i);
+ if (addr == goal || Reachable(table, goal, addr))
+ return PR_TRUE;
+ }
+ return PR_FALSE;
+}
+
+static PRBool WellOrdered(const void* addr1, const void* addr2,
+ const void *callsite2, PRUint32* index2p,
+ nsNamedVector** vec1p, nsNamedVector** vec2p)
+{
+ PRBool rv = PR_TRUE;
+ PLHashTable* table = OrderTable;
+ if (!table) return rv;
+ PR_Lock(OrderTableLock);
+
+ // Check whether we've already asserted (addr1 < addr2).
+ nsNamedVector* vec1 = GetVector(table, addr1);
+ if (vec1) {
+ PRUint32 i, n;
+
+ for (i = 0, n = vec1->Count(); i < n; i++)
+ if (vec1->ElementAt(i) == addr2)
+ break;
+
+ if (i == n) {
+ // Now check for (addr2 < addr1) and return false if so.
+ nsNamedVector* vec2 = GetVector(table, addr2);
+ if (vec2) {
+ for (i = 0, n = vec2->Count(); i < n; i++) {
+ void* addri = vec2->ElementAt(i);
+ PR_ASSERT(addri);
+ if (addri == addr1 || Reachable(table, addr1, addri)) {
+ *index2p = i;
+ *vec1p = vec1;
+ *vec2p = vec2;
+ rv = PR_FALSE;
+ break;
+ }
+ }
+
+ if (rv) {
+ // Assert (addr1 < addr2) into the order table.
+ // XXX fix plvector/nsVector to use const void*
+ vec1->AppendElement((void*) addr2);
+#ifdef NS_TRACE_MALLOC_XXX
+ vec1->mInnerSites.AppendElement((void*) callsite2);
+#endif
+ }
+ }
+ }
+ }
+
+ PR_Unlock(OrderTableLock);
+ return rv;
+}
+
+nsAutoLockBase::nsAutoLockBase(void* addr, nsAutoLockType type)
+{
+ if (LockStackTPI == PRUintn(-1))
+ InitAutoLockStatics();
+
+ nsAutoLockBase* stackTop =
+ (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI);
+ if (stackTop) {
+ if (stackTop->mAddr == addr) {
+ // Ignore reentry: it's legal for monitors, and NSPR will assert
+ // if you reenter a PRLock.
+ } else if (!addr) {
+ // Ignore null addresses: the caller promises not to use the
+ // lock at all, and NSPR will assert if you enter it.
+ } else {
+ const void* node =
+#ifdef NS_TRACE_MALLOC_XXX
+ NS_GetStackTrace(1)
+#else
+ nsnull
+#endif
+ ;
+ nsNamedVector* vec1;
+ nsNamedVector* vec2;
+ PRUint32 i2;
+
+ if (!WellOrdered(stackTop->mAddr, addr, node, &i2, &vec1, &vec2)) {
+ char buf[128];
+ PR_snprintf(buf, sizeof buf,
+ "Potential deadlock between %s%s@%p and %s%s@%p",
+ vec1->mName ? vec1->mName : "",
+ LockTypeNames[stackTop->mType],
+ stackTop->mAddr,
+ vec2->mName ? vec2->mName : "",
+ LockTypeNames[type],
+ addr);
+#ifdef NS_TRACE_MALLOC_XXX
+ fprintf(stderr, "\n*** %s\n\nCurrent stack:\n", buf);
+ NS_DumpStackTrace(node, stderr);
+
+ fputs("\nPrevious stack:\n", stderr);
+ NS_DumpStackTrace(vec2->mInnerSites.ElementAt(i2), stderr);
+ putc('\n', stderr);
+#endif
+ NS_ERROR(buf);
+ }
+ }
+ }
+
+ mAddr = addr;
+ mDown = stackTop;
+ mType = type;
+ if (mAddr)
+ (void) PR_SetThreadPrivate(LockStackTPI, this);
+}
+
+nsAutoLockBase::~nsAutoLockBase()
+{
+ if (mAddr)
+ (void) PR_SetThreadPrivate(LockStackTPI, mDown);
+}
+
+void nsAutoLockBase::Show()
+{
+ if (!mAddr)
+ return;
+ nsAutoLockBase* curr = (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI);
+ nsAutoLockBase* prev = nsnull;
+ while (curr != mDown) {
+ prev = curr;
+ curr = prev->mDown;
+ }
+ if (!prev)
+ PR_SetThreadPrivate(LockStackTPI, this);
+ else
+ prev->mDown = this;
+}
+
+void nsAutoLockBase::Hide()
+{
+ if (!mAddr)
+ return;
+ nsAutoLockBase* curr = (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI);
+ nsAutoLockBase* prev = nsnull;
+ while (curr != this) {
+ prev = curr;
+ curr = prev->mDown;
+ }
+ if (!prev)
+ PR_SetThreadPrivate(LockStackTPI, mDown);
+ else
+ prev->mDown = mDown;
+}
+
+#endif /* DEBUG */
+
+PRMonitor* nsAutoMonitor::NewMonitor(const char* name)
+{
+ PRMonitor* mon = PR_NewMonitor();
+#ifdef DEBUG
+ if (mon && OrderTable) {
+ nsNamedVector* value = new nsNamedVector(name);
+ if (value) {
+ PR_Lock(OrderTableLock);
+ PL_HashTableAdd(OrderTable, mon, value);
+ PR_Unlock(OrderTableLock);
+ }
+ }
+#endif
+ return mon;
+}
+
+void nsAutoMonitor::DestroyMonitor(PRMonitor* mon)
+{
+#ifdef DEBUG
+ if (OrderTable)
+ OnMonitorRecycle(mon);
+#endif
+ PR_DestroyMonitor(mon);
+}
+
+void nsAutoMonitor::Enter()
+{
+#ifdef DEBUG
+ if (!mAddr) {
+ NS_ERROR("It is not legal to enter a null monitor");
+ return;
+ }
+ nsAutoLockBase* stackTop =
+ (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI);
+ NS_ASSERTION(stackTop == mDown, "non-LIFO nsAutoMonitor::Enter");
+ mDown = stackTop;
+ (void) PR_SetThreadPrivate(LockStackTPI, this);
+#endif
+ PR_EnterMonitor(mMonitor);
+ mLockCount += 1;
+}
+
+void nsAutoMonitor::Exit()
+{
+#ifdef DEBUG
+ if (!mAddr) {
+ NS_ERROR("It is not legal to exit a null monitor");
+ return;
+ }
+ (void) PR_SetThreadPrivate(LockStackTPI, mDown);
+#endif
+ PRStatus status = PR_ExitMonitor(mMonitor);
+ NS_ASSERTION(status == PR_SUCCESS, "PR_ExitMonitor failed");
+ mLockCount -= 1;
+}
+
+// XXX we don't worry about cached monitors being destroyed behind our back.
+// XXX current NSPR (mozilla/nsprpub/pr/src/threads/prcmon.c) never destroys
+// XXX a cached monitor! potential resource pig in conjunction with necko...
+
+void nsAutoCMonitor::Enter()
+{
+#ifdef DEBUG
+ nsAutoLockBase* stackTop =
+ (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI);
+ NS_ASSERTION(stackTop == mDown, "non-LIFO nsAutoCMonitor::Enter");
+ mDown = stackTop;
+ (void) PR_SetThreadPrivate(LockStackTPI, this);
+#endif
+ PR_CEnterMonitor(mLockObject);
+ mLockCount += 1;
+}
+
+void nsAutoCMonitor::Exit()
+{
+#ifdef DEBUG
+ (void) PR_SetThreadPrivate(LockStackTPI, mDown);
+#endif
+ PRStatus status = PR_CExitMonitor(mLockObject);
+ NS_ASSERTION(status == PR_SUCCESS, "PR_CExitMonitor failed");
+ mLockCount -= 1;
+}
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h b/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h
new file mode 100644
index 00000000..a82d6ffc
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h
@@ -0,0 +1,383 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+/*
+ A stack-based lock object that makes using PRLock a bit more
+ convenient. It acquires the monitor when constructed, and releases
+ it when it goes out of scope.
+
+ For example,
+
+ class Foo {
+ private:
+ PRLock* mLock;
+
+ public:
+ Foo(void) {
+ mLock = PR_NewLock();
+ }
+
+ ~Foo(void) {
+ PR_DestroyLock(mLock);
+ }
+
+ void ThreadSafeMethod(void) {
+ // we're don't hold the lock yet...
+
+ nsAutoLock lock(mLock);
+ // ...but now we do.
+
+ // we even can do wacky stuff like return from arbitrary places w/o
+ // worrying about forgetting to release the lock
+ if (some_weird_condition)
+ return;
+
+ // otherwise do some other stuff
+ }
+
+ void ThreadSafeBlockScope(void) {
+ // we're not in the lock here...
+
+ {
+ nsAutoLock lock(mLock);
+ // but we are now, at least until the block scope closes
+ }
+
+ // ...now we're not in the lock anymore
+ }
+ };
+
+ A similar stack-based locking object is available for PRMonitor. The
+ major difference is that the PRMonitor must be created and destroyed
+ via the static methods on nsAutoMonitor.
+
+ For example:
+ Foo::Foo() {
+ mMon = nsAutoMonitor::NewMonitor("FooMonitor");
+ }
+ nsresult Foo::MyMethod(...) {
+ nsAutoMonitor mon(mMon);
+ ...
+ // go ahead and do deeply nested returns...
+ return NS_ERROR_FAILURE;
+ ...
+ // or call Wait or Notify...
+ mon.Wait();
+ ...
+ // cleanup is automatic
+ }
+ */
+
+#ifndef nsAutoLock_h__
+#define nsAutoLock_h__
+
+#include "nscore.h"
+#include "prlock.h"
+#include "prlog.h"
+
+/**
+ * nsAutoLockBase
+ * This is the base class for the stack-based locking objects.
+ * Clients of derived classes need not play with this superclass.
+ **/
+class NS_COM nsAutoLockBase {
+protected:
+ nsAutoLockBase() {}
+ enum nsAutoLockType {eAutoLock, eAutoMonitor, eAutoCMonitor};
+
+#ifdef DEBUG
+ nsAutoLockBase(void* addr, nsAutoLockType type);
+ ~nsAutoLockBase();
+
+ void Show();
+ void Hide();
+
+ void* mAddr;
+ nsAutoLockBase* mDown;
+ nsAutoLockType mType;
+#else
+ nsAutoLockBase(void* addr, nsAutoLockType type) {}
+ ~nsAutoLockBase() {}
+
+ void Show() {}
+ void Hide() {}
+#endif
+};
+
+/**
+ * nsAutoLock
+ * Stack-based locking object for PRLock.
+ **/
+class NS_COM nsAutoLock : public nsAutoLockBase {
+private:
+ PRLock* mLock;
+ PRBool mLocked;
+
+ // Not meant to be implemented. This makes it a compiler error to
+ // construct or assign an nsAutoLock object incorrectly.
+ nsAutoLock(void);
+ nsAutoLock(const nsAutoLock& /*aLock*/);
+ nsAutoLock& operator =(const nsAutoLock& /*aLock*/);
+
+ // Not meant to be implemented. This makes it a compiler error to
+ // attempt to create an nsAutoLock object on the heap.
+ static void* operator new(size_t /*size*/) CPP_THROW_NEW;
+ static void operator delete(void* /*memory*/);
+
+public:
+ /**
+ * Constructor
+ * The constructor aquires the given lock. The destructor
+ * releases the lock.
+ *
+ * @param aLock A valid PRLock* returned from the NSPR's
+ * PR_NewLock() function.
+ **/
+ nsAutoLock(PRLock* aLock)
+ : nsAutoLockBase(aLock, eAutoLock),
+ mLock(aLock),
+ mLocked(PR_TRUE) {
+ PR_ASSERT(mLock);
+
+ // This will assert deep in the bowels of NSPR if you attempt
+ // to re-enter the lock.
+ PR_Lock(mLock);
+ }
+
+ ~nsAutoLock(void) {
+ if (mLocked)
+ PR_Unlock(mLock);
+ }
+
+ /**
+ * lock
+ * Client may call this to reaquire the given lock. Take special
+ * note that attempting to aquire a locked lock will hang or crash.
+ **/
+ void lock() {
+ Show();
+ PR_ASSERT(!mLocked);
+ PR_Lock(mLock);
+ mLocked = PR_TRUE;
+ }
+
+
+ /**
+ * unlock
+ * Client may call this to release the given lock. Take special
+ * note unlocking an unlocked lock has undefined results.
+ **/
+ void unlock() {
+ PR_ASSERT(mLocked);
+ PR_Unlock(mLock);
+ mLocked = PR_FALSE;
+ Hide();
+ }
+};
+
+#include "prcmon.h"
+#include "nsError.h"
+#include "nsDebug.h"
+
+class NS_COM nsAutoMonitor : public nsAutoLockBase {
+public:
+
+ /**
+ * NewMonitor
+ * Allocates a new PRMonitor for use with nsAutoMonitor.
+ * @param name A (unique /be?) name which can reference this monitor
+ * @returns nsnull if failure
+ * A valid PRMonitor* is successful while must be destroyed
+ * by nsAutoMonitor::DestroyMonitor()
+ **/
+ static PRMonitor* NewMonitor(const char* name);
+ static void DestroyMonitor(PRMonitor* mon);
+
+
+ /**
+ * Constructor
+ * The constructor locks the given monitor. During destruction
+ * the monitor will be unlocked.
+ *
+ * @param mon A valid PRMonitor* returned from
+ * nsAutoMonitor::NewMonitor().
+ **/
+ nsAutoMonitor(PRMonitor* mon)
+ : nsAutoLockBase((void*)mon, eAutoMonitor),
+ mMonitor(mon), mLockCount(0)
+ {
+ NS_ASSERTION(mMonitor, "null monitor");
+ if (mMonitor) {
+ PR_EnterMonitor(mMonitor);
+ mLockCount = 1;
+ }
+ }
+
+ ~nsAutoMonitor() {
+ NS_ASSERTION(mMonitor, "null monitor");
+ if (mMonitor && mLockCount) {
+#ifdef DEBUG
+ PRStatus status =
+#endif
+ PR_ExitMonitor(mMonitor);
+ NS_ASSERTION(status == PR_SUCCESS, "PR_ExitMonitor failed");
+ }
+ }
+
+ /**
+ * Enter
+ * Client may call this to reenter the given monitor.
+ * @see prmon.h
+ **/
+ void Enter();
+
+ /**
+ * Exit
+ * Client may call this to exit the given monitor.
+ * @see prmon.h
+ **/
+ void Exit();
+
+ /**
+ * Wait
+ * @see prmon.h
+ **/
+ nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) {
+ return PR_Wait(mMonitor, interval) == PR_SUCCESS
+ ? NS_OK : NS_ERROR_FAILURE;
+ }
+
+ /**
+ * Notify
+ * @see prmon.h
+ **/
+ nsresult Notify() {
+ return PR_Notify(mMonitor) == PR_SUCCESS
+ ? NS_OK : NS_ERROR_FAILURE;
+ }
+
+ /**
+ * NotifyAll
+ * @see prmon.h
+ **/
+ nsresult NotifyAll() {
+ return PR_NotifyAll(mMonitor) == PR_SUCCESS
+ ? NS_OK : NS_ERROR_FAILURE;
+ }
+
+private:
+ PRMonitor* mMonitor;
+ PRInt32 mLockCount;
+
+ // Not meant to be implemented. This makes it a compiler error to
+ // construct or assign an nsAutoLock object incorrectly.
+ nsAutoMonitor(void);
+ nsAutoMonitor(const nsAutoMonitor& /*aMon*/);
+ nsAutoMonitor& operator =(const nsAutoMonitor& /*aMon*/);
+
+ // Not meant to be implemented. This makes it a compiler error to
+ // attempt to create an nsAutoLock object on the heap.
+ static void* operator new(size_t /*size*/) CPP_THROW_NEW;
+ static void operator delete(void* /*memory*/);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Once again, this time with a cache...
+// (Using this avoids the need to allocate a PRMonitor, which may be useful when
+// a large number of objects of the same class need associated monitors.)
+
+#include "prcmon.h"
+#include "nsError.h"
+
+class NS_COM nsAutoCMonitor : public nsAutoLockBase {
+public:
+ nsAutoCMonitor(void* lockObject)
+ : nsAutoLockBase(lockObject, eAutoCMonitor),
+ mLockObject(lockObject), mLockCount(0)
+ {
+ NS_ASSERTION(lockObject, "null lock object");
+ PR_CEnterMonitor(mLockObject);
+ mLockCount = 1;
+ }
+
+ ~nsAutoCMonitor() {
+ if (mLockCount) {
+#ifdef DEBUG
+ PRStatus status =
+#endif
+ PR_CExitMonitor(mLockObject);
+ NS_ASSERTION(status == PR_SUCCESS, "PR_CExitMonitor failed");
+ }
+ }
+
+ void Enter();
+ void Exit();
+
+ nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) {
+ return PR_CWait(mLockObject, interval) == PR_SUCCESS
+ ? NS_OK : NS_ERROR_FAILURE;
+ }
+
+ nsresult Notify() {
+ return PR_CNotify(mLockObject) == PR_SUCCESS
+ ? NS_OK : NS_ERROR_FAILURE;
+ }
+
+ nsresult NotifyAll() {
+ return PR_CNotifyAll(mLockObject) == PR_SUCCESS
+ ? NS_OK : NS_ERROR_FAILURE;
+ }
+
+private:
+ void* mLockObject;
+ PRInt32 mLockCount;
+
+ // Not meant to be implemented. This makes it a compiler error to
+ // construct or assign an nsAutoLock object incorrectly.
+ nsAutoCMonitor(void);
+ nsAutoCMonitor(const nsAutoCMonitor& /*aMon*/);
+ nsAutoCMonitor& operator =(const nsAutoCMonitor& /*aMon*/);
+
+ // Not meant to be implemented. This makes it a compiler error to
+ // attempt to create an nsAutoLock object on the heap.
+ static void* operator new(size_t /*size*/) CPP_THROW_NEW;
+ static void operator delete(void* /*memory*/);
+};
+
+#endif // nsAutoLock_h__
+
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.cpp b/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.cpp
new file mode 100644
index 00000000..139b24a6
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.cpp
@@ -0,0 +1,202 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla embedding code.
+ *
+ * The Initial Developers of the Original Code are
+ * Benjamin Smedberg <bsmedberg@covad.net> and
+ * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>.
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2003/2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsEnvironment.h"
+#include "prenv.h"
+#include "prprf.h"
+#include "nsAutoLock.h"
+#include "nsBaseHashtable.h"
+#include "nsHashKeys.h"
+#include "nsPromiseFlatString.h"
+#include "nsDependentString.h"
+#include "nsNativeCharsetUtils.h"
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(nsEnvironment, nsIEnvironment)
+
+NS_METHOD
+nsEnvironment::Create(nsISupports *aOuter, REFNSIID aIID,
+ void **aResult)
+{
+ nsresult rv;
+ *aResult = nsnull;
+
+ if (aOuter != nsnull) {
+ return NS_ERROR_NO_AGGREGATION;
+ }
+
+ nsEnvironment* obj = new nsEnvironment();
+ if (!obj) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ obj->mLock = PR_NewLock();
+ if (!obj->mLock) {
+ delete obj;
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ rv = obj->QueryInterface(aIID, aResult);
+ if (NS_FAILED(rv)) {
+ delete obj;
+ }
+ return rv;
+}
+
+nsEnvironment::~nsEnvironment()
+{
+ if (mLock)
+ PR_DestroyLock(mLock);
+}
+
+NS_IMETHODIMP
+nsEnvironment::Exists(const nsAString& aName, PRBool *aOutValue)
+{
+ nsCAutoString nativeName;
+ nsresult rv = NS_CopyUnicodeToNative(aName, nativeName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCAutoString nativeVal;
+#if defined(XP_UNIX)
+ /* For Unix/Linux platforms we follow the Unix definition:
+ * An environment variable exists when |getenv()| returns a non-NULL value.
+ * An environment variable does not exist when |getenv()| returns NULL.
+ */
+ const char *value = PR_GetEnv(nativeName.get());
+
+ *aOutValue = (value)?(PR_TRUE):(PR_FALSE);
+#else
+ /* For non-Unix/Linux platforms we have to fall back to a
+ * "portable" definition (which is incorrect for Unix/Linux!!!!)
+ * which simply checks whether the string returned by |Get()| is empty
+ * or not.
+ */
+ nsAutoString value;
+ Get(aName, value);
+ *aOutValue = (value.IsEmpty())?(PR_FALSE):(PR_TRUE);
+#endif /* XP_UNIX */
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEnvironment::Get(const nsAString& aName, nsAString& aOutValue)
+{
+ nsCAutoString nativeName;
+ nsresult rv = NS_CopyUnicodeToNative(aName, nativeName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCAutoString nativeVal;
+ const char *value = PR_GetEnv(nativeName.get());
+ if (value) {
+ rv = NS_CopyNativeToUnicode(nsDependentCString(value), aOutValue);
+ } else {
+ aOutValue.Truncate();
+ rv = NS_OK;
+ }
+
+ return rv;
+}
+
+/* Environment strings must have static duration; We're gonna leak all of this
+ * at shutdown: this is by design, caused how Unix/Linux implement environment
+ * vars.
+ */
+
+typedef nsBaseHashtableET<nsCStringHashKey,char*> EnvEntryType;
+typedef nsTHashtable<EnvEntryType> EnvHashType;
+
+static EnvHashType *gEnvHash = nsnull;
+
+static PRBool
+EnsureEnvHash()
+{
+ if (gEnvHash)
+ return PR_TRUE;
+
+ gEnvHash = new EnvHashType;
+ if (!gEnvHash)
+ return PR_FALSE;
+
+ if(gEnvHash->Init())
+ return PR_TRUE;
+
+ delete gEnvHash;
+ gEnvHash = nsnull;
+ return PR_FALSE;
+}
+
+NS_IMETHODIMP
+nsEnvironment::Set(const nsAString& aName, const nsAString& aValue)
+{
+ nsCAutoString nativeName;
+ nsCAutoString nativeVal;
+
+ nsresult rv = NS_CopyUnicodeToNative(aName, nativeName);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = NS_CopyUnicodeToNative(aValue, nativeVal);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoLock lock(mLock); // autolock unlocks automagically
+
+ if (!EnsureEnvHash()){
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ EnvEntryType* entry = gEnvHash->PutEntry(nativeName);
+ if (!entry) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ char* newData = PR_smprintf("%s=%s",
+ nativeName.get(),
+ nativeVal.get());
+ if (!newData) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ PR_SetEnv(newData);
+ if (entry->mData) {
+ PR_smprintf_free(entry->mData);
+ }
+ entry->mData = newData;
+ return NS_OK;
+}
+
+
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.h b/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.h
new file mode 100644
index 00000000..46e8d66a
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla embedding code.
+ *
+ * The Initial Developers of the Original Code are
+ * Benjamin Smedberg <bsmedberg@covad.net> and
+ * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>.
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2003/2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsEnvironment_h__
+#define nsEnvironment_h__
+
+#include "nsIEnvironment.h"
+#include "prlock.h"
+
+#define NS_ENVIRONMENT_CID \
+ { 0X3D68F92UL, 0X9513, 0X4E25, \
+ { 0X9B, 0XE9, 0X7C, 0XB2, 0X39, 0X87, 0X41, 0X72 } }
+#define NS_ENVIRONMENT_CONTRACTID "@mozilla.org/process/environment;1"
+
+class nsEnvironment : public nsIEnvironment
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIENVIRONMENT
+
+ static NS_METHOD Create(nsISupports *aOuter, REFNSIID aIID,
+ void **aResult);
+
+private:
+ nsEnvironment() { }
+ ~nsEnvironment();
+
+ PRLock *mLock;
+};
+
+#endif /* !nsEnvironment_h__ */
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.cpp b/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.cpp
new file mode 100644
index 00000000..7dc8f089
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.cpp
@@ -0,0 +1,632 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsCOMPtr.h"
+#include "nsEventQueue.h"
+#include "nsIEventQueueService.h"
+#include "nsIThread.h"
+
+#include "nsIServiceManager.h"
+#include "nsIObserverService.h"
+
+#include "nsString.h"
+
+#include "prlog.h"
+
+#ifdef NS_DEBUG
+#include "prprf.h"
+#endif
+
+#if defined(PR_LOGGING) && defined(DEBUG_danm)
+/* found these logs useful in conjunction with netlibStreamEvent logging
+ from netwerk. */
+PRLogModuleInfo* gEventQueueLog = 0;
+PRUint32 gEventQueueLogCount = 0;
+PRUint32 gEventQueueLogPPCount = 0;
+static int gEventQueueLogPPLevel = 0;
+static PLEventQueue *gEventQueueLogQueue = 0;
+static PRThread *gEventQueueLogThread = 0;
+#endif
+
+// in a real system, these would be members in a header class...
+static const char gActivatedNotification[] = "nsIEventQueueActivated";
+static const char gDestroyedNotification[] = "nsIEventQueueDestroyed";
+
+nsEventQueueImpl::nsEventQueueImpl()
+{
+ NS_ADDREF_THIS();
+ /* The slightly weird ownership model for eventqueues goes like this:
+
+ General:
+ There's an addref from the factory generally held by whoever asked for
+ the queue. The queue addrefs itself (right here) and releases itself
+ after someone calls StopAcceptingEvents() on the queue and when it is
+ dark and empty (in CheckForDeactivation()).
+
+ Chained queues:
+
+ Eldest queue:
+ The eldest queue in a chain is held on to by the EventQueueService
+ in a hash table, so it is possible that the eldest queue may not be
+ released until the EventQueueService is shutdown.
+ You may not call StopAcceptingEvents() on this queue until you have
+ done so on all younger queues.
+
+ General:
+ Each queue holds a reference to their immediate elder link and a weak
+ reference to their immediate younger link. Because you must shut down
+ queues from youngest to eldest, all the references will be removed.
+
+ It happens something like:
+ queue->StopAcceptingEvents()
+ {
+ CheckForDeactivation()
+ {
+ -- hopefully we are able to shutdown now --
+ Unlink()
+ {
+ -- remove the reference we hold to our elder queue --
+ -- NULL out our elder queues weak reference to us --
+ }
+ RELEASE ourself (to balance the ADDREF here in the constructor)
+ -- and we should go away. --
+ }
+ }
+
+
+ Notes:
+ A dark queue no longer accepts events. An empty queue simply has no events.
+ */
+
+#if defined(PR_LOGGING) && defined(DEBUG_danm)
+ PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
+ ("EventQueue: Created [queue=%lx]",(long)mEventQueue));
+ ++gEventQueueLogCount;
+#endif
+
+ mYoungerQueue = nsnull;
+ mEventQueue = nsnull;
+ mAcceptingEvents = PR_TRUE;
+ mCouldHaveEvents = PR_TRUE;
+}
+
+nsEventQueueImpl::~nsEventQueueImpl()
+{
+ Unlink();
+
+#if defined(PR_LOGGING) && defined(DEBUG_danm)
+ PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
+ ("EventQueue: Destroyed [queue=%lx]",(long)mEventQueue));
+ ++gEventQueueLogCount;
+#endif
+
+ if (mEventQueue) {
+ NotifyObservers(gDestroyedNotification);
+ PL_DestroyEventQueue(mEventQueue);
+ }
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::Init(PRBool aNative)
+{
+ PRThread *thread = PR_GetCurrentThread();
+ if (aNative)
+ mEventQueue = PL_CreateNativeEventQueue("Thread event queue...", thread);
+ else
+ mEventQueue = PL_CreateMonitoredEventQueue("Thread event queue...", thread);
+ NotifyObservers(gActivatedNotification);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::InitFromPRThread(PRThread* thread, PRBool aNative)
+{
+ if (thread == NS_CURRENT_THREAD)
+ {
+ thread = PR_GetCurrentThread();
+ }
+ else if (thread == NS_UI_THREAD)
+ {
+ nsCOMPtr<nsIThread> mainIThread;
+ nsresult rv;
+
+ // Get the primordial thread
+ rv = nsIThread::GetMainThread(getter_AddRefs(mainIThread));
+ if (NS_FAILED(rv)) return rv;
+
+ rv = mainIThread->GetPRThread(&thread);
+ if (NS_FAILED(rv)) return rv;
+ }
+
+ if (aNative)
+ mEventQueue = PL_CreateNativeEventQueue("Thread event queue...", thread);
+ else
+ mEventQueue = PL_CreateMonitoredEventQueue("Thread event queue...", thread);
+ NotifyObservers(gActivatedNotification);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::InitFromPLQueue(PLEventQueue* aQueue)
+{
+ mEventQueue = aQueue;
+ NotifyObservers(gActivatedNotification);
+ return NS_OK;
+}
+
+/* nsISupports interface implementation... */
+NS_IMPL_THREADSAFE_ISUPPORTS3(nsEventQueueImpl,
+ nsIEventQueue,
+ nsIEventTarget,
+ nsPIEventQueueChain)
+
+/* nsIEventQueue interface implementation... */
+
+NS_IMETHODIMP
+nsEventQueueImpl::StopAcceptingEvents()
+{
+ // this assertion is bogus. I should be able to shut down the eldest queue,
+ // as long as there are no younger children
+
+
+ NS_ASSERTION(mElderQueue || !mYoungerQueue, "attempted to disable eldest queue in chain");
+ mAcceptingEvents = PR_FALSE;
+ CheckForDeactivation();
+#if defined(PR_LOGGING) && defined(DEBUG_danm)
+ PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
+ ("EventQueue: StopAccepting [queue=%lx, accept=%d, could=%d]",
+ (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
+ ++gEventQueueLogCount;
+#endif
+ return NS_OK;
+}
+
+// utility funtion to send observers a notification
+void
+nsEventQueueImpl::NotifyObservers(const char *aTopic)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIObserverService> os = do_GetService("@mozilla.org/observer-service;1", &rv);
+ if (NS_SUCCEEDED(rv)) {
+ nsCOMPtr<nsIEventQueue> kungFuDeathGrip(this);
+ nsCOMPtr<nsISupports> us(do_QueryInterface(kungFuDeathGrip));
+ os->NotifyObservers(us, aTopic, NULL);
+ }
+}
+
+
+NS_IMETHODIMP
+nsEventQueueImpl::InitEvent(PLEvent* aEvent,
+ void* owner,
+ PLHandleEventProc handler,
+ PLDestroyEventProc destructor)
+{
+ PL_InitEvent(aEvent, owner, handler, destructor);
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsEventQueueImpl::PostEvent(PLEvent* aEvent)
+{
+ if (!mAcceptingEvents) {
+#if defined(PR_LOGGING) && defined(DEBUG_danm)
+ PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
+ ("EventQueue: Punt posted event [queue=%lx, accept=%d, could=%d]",
+ (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
+ ++gEventQueueLogCount;
+#endif
+ nsresult rv = NS_ERROR_FAILURE;
+ NS_ASSERTION(mElderQueue, "event dropped because event chain is dead");
+ if (mElderQueue) {
+ nsCOMPtr<nsIEventQueue> elder(do_QueryInterface(mElderQueue));
+ if (elder)
+ rv = elder->PostEvent(aEvent);
+ }
+ return rv;
+ }
+#if defined(PR_LOGGING) && defined(DEBUG_danm)
+ PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
+ ("EventQueue: Posting event [queue=%lx]", (long)mEventQueue));
+ ++gEventQueueLogCount;
+#endif
+ return PL_PostEvent(mEventQueue, aEvent) == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::PostSynchronousEvent(PLEvent* aEvent, void** aResult)
+{
+ if (!mAcceptingEvents) {
+#if defined(PR_LOGGING) && defined(DEBUG_danm)
+ PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
+ ("EventQueue: Punt posted synchronous event [queue=%lx, accept=%d, could=%d]",
+ (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
+ ++gEventQueueLogCount;
+#endif
+ nsresult rv = NS_ERROR_NO_INTERFACE;
+ NS_ASSERTION(mElderQueue, "event dropped because event chain is dead");
+ if (mElderQueue) {
+ nsCOMPtr<nsIEventQueue> elder(do_QueryInterface(mElderQueue));
+ if (elder)
+ rv = elder->PostSynchronousEvent(aEvent, aResult);
+ return rv;
+ }
+ return NS_ERROR_ABORT;
+ }
+
+#if defined(PR_LOGGING) && defined(DEBUG_danm)
+ PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
+ ("EventQueue: Posting synchronous event [queue=%lx]", (long)mEventQueue));
+ ++gEventQueueLogCount;
+#endif
+ void* result = PL_PostSynchronousEvent(mEventQueue, aEvent);
+ if (aResult)
+ *aResult = result;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::EnterMonitor()
+{
+ PL_ENTER_EVENT_QUEUE_MONITOR(mEventQueue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::ExitMonitor()
+{
+ PL_EXIT_EVENT_QUEUE_MONITOR(mEventQueue);
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsEventQueueImpl::RevokeEvents(void* owner)
+{
+ PL_RevokeEvents(mEventQueue, owner);
+ if (mElderQueue) {
+ nsCOMPtr<nsIEventQueue> elder(do_QueryInterface(mElderQueue));
+ if (elder)
+ elder->RevokeEvents(owner);
+ }
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsEventQueueImpl::GetPLEventQueue(PLEventQueue** aEventQueue)
+{
+ if (!mEventQueue)
+ return NS_ERROR_NULL_POINTER;
+
+ *aEventQueue = mEventQueue;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::IsOnCurrentThread(PRBool *aResult)
+{
+ *aResult = PL_IsQueueOnCurrentThread( mEventQueue );
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsEventQueueImpl::IsQueueNative(PRBool *aResult)
+{
+ *aResult = PL_IsQueueNative(mEventQueue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::PendingEvents(PRBool *aResult)
+{
+ *aResult = PL_EventAvailable(mEventQueue);
+ if (!*aResult && mElderQueue) {
+ nsCOMPtr<nsIEventQueue> elder(do_QueryInterface(mElderQueue));
+ if (elder)
+ return elder->EventAvailable(*aResult);
+ }
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsEventQueueImpl::ProcessPendingEvents()
+{
+ PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue);
+
+ NS_ASSERTION(correctThread, "attemping to process events on the wrong thread");
+
+ if (!correctThread)
+ return NS_ERROR_FAILURE;
+#if defined(PR_LOGGING) && defined(DEBUG_danm)
+ ++gEventQueueLogPPLevel;
+ if ((gEventQueueLogQueue != mEventQueue || gEventQueueLogThread != PR_GetCurrentThread() ||
+ gEventQueueLogCount != gEventQueueLogPPCount) && gEventQueueLogPPLevel == 1) {
+ PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
+ ("EventQueue: Process pending [queue=%lx, accept=%d, could=%d]",
+ (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
+ gEventQueueLogPPCount = ++gEventQueueLogCount;
+ gEventQueueLogQueue = mEventQueue;
+ gEventQueueLogThread = PR_GetCurrentThread();
+ }
+#endif
+ PL_ProcessPendingEvents(mEventQueue);
+
+ // if we're no longer accepting events and there are still events in the
+ // queue, then process remaining events.
+ if (!mAcceptingEvents && PL_EventAvailable(mEventQueue))
+ PL_ProcessPendingEvents(mEventQueue);
+
+ CheckForDeactivation();
+
+ if (mElderQueue) {
+ nsCOMPtr<nsIEventQueue> elder(do_QueryInterface(mElderQueue));
+ if (elder)
+ elder->ProcessPendingEvents();
+ }
+#if defined(PR_LOGGING) && defined(DEBUG_danm)
+ --gEventQueueLogPPLevel;
+#endif
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::EventLoop()
+{
+ PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue);
+
+ NS_ASSERTION(correctThread, "attemping to process events on the wrong thread");
+
+ if (!correctThread)
+ return NS_ERROR_FAILURE;
+
+ PL_EventLoop(mEventQueue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::EventAvailable(PRBool& aResult)
+{
+ aResult = PL_EventAvailable(mEventQueue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::GetEvent(PLEvent** aResult)
+{
+ *aResult = PL_GetEvent(mEventQueue);
+ CheckForDeactivation();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::HandleEvent(PLEvent* aEvent)
+{
+ PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue);
+ NS_ASSERTION(correctThread, "attemping to process events on the wrong thread");
+ if (!correctThread)
+ return NS_ERROR_FAILURE;
+
+#if defined(PR_LOGGING) && defined(DEBUG_danm)
+ PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
+ ("EventQueue: handle event [queue=%lx, accept=%d, could=%d]",
+ (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
+ ++gEventQueueLogCount;
+#endif
+ PL_HandleEvent(aEvent);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::WaitForEvent(PLEvent** aResult)
+{
+ PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue);
+ NS_ASSERTION(correctThread, "attemping to process events on the wrong thread");
+ if (!correctThread)
+ return NS_ERROR_FAILURE;
+
+#if defined(PR_LOGGING) && defined(DEBUG_danm)
+ PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
+ ("EventQueue: wait for event [queue=%lx, accept=%d, could=%d]",
+ (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
+ ++gEventQueueLogCount;
+#endif
+ *aResult = PL_WaitForEvent(mEventQueue);
+ CheckForDeactivation();
+ return NS_OK;
+}
+
+NS_IMETHODIMP_(PRInt32)
+nsEventQueueImpl::GetEventQueueSelectFD()
+{
+ return PL_GetEventQueueSelectFD(mEventQueue);
+}
+
+NS_METHOD
+nsEventQueueImpl::Create(nsISupports *aOuter,
+ REFNSIID aIID,
+ void **aResult)
+{
+ nsEventQueueImpl* evt = new nsEventQueueImpl();
+ if (evt == NULL)
+ return NS_ERROR_OUT_OF_MEMORY;
+ nsresult rv = evt->QueryInterface(aIID, aResult);
+ if (NS_FAILED(rv)) {
+ delete evt;
+ }
+ return rv;
+}
+
+// ---------------- nsPIEventQueueChain -----------------
+
+NS_IMETHODIMP
+nsEventQueueImpl::AppendQueue(nsIEventQueue *aQueue)
+{
+ nsresult rv;
+ nsCOMPtr<nsIEventQueue> end;
+ nsCOMPtr<nsPIEventQueueChain> queueChain(do_QueryInterface(aQueue));
+
+ if (!aQueue)
+ return NS_ERROR_NO_INTERFACE;
+
+/* this would be nice
+ NS_ASSERTION(aQueue->mYoungerQueue == NULL && aQueue->mElderQueue == NULL,
+ "event queue repeatedly appended to queue chain");
+*/
+ rv = NS_ERROR_NO_INTERFACE;
+
+#ifdef NS_DEBUG
+ int depth = 0;
+ nsEventQueueImpl *next = this;
+ while (next && depth < 100) {
+ next = NS_STATIC_CAST(nsEventQueueImpl *, next->mYoungerQueue);
+ ++depth;
+ }
+ if (depth > 5) {
+ char warning[80];
+ PR_snprintf(warning, sizeof(warning),
+ "event queue chain length is %d. this is almost certainly a leak.", depth);
+ NS_WARNING(warning);
+ }
+#endif
+
+ // (be careful doing this outside nsEventQueueService's mEventQMonitor)
+
+ GetYoungest(getter_AddRefs(end));
+ nsCOMPtr<nsPIEventQueueChain> endChain(do_QueryInterface(end));
+ if (endChain) {
+ endChain->SetYounger(queueChain);
+ queueChain->SetElder(endChain);
+ rv = NS_OK;
+ }
+ return rv;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::Unlink()
+{
+ nsCOMPtr<nsPIEventQueueChain> young = mYoungerQueue,
+ old = mElderQueue;
+
+#if defined(PR_LOGGING) && defined(DEBUG_danm)
+ PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
+ ("EventQueue: unlink [queue=%lx, younger=%lx, elder=%lx]",
+ (long)mEventQueue,(long)mYoungerQueue, (long)mElderQueue.get()));
+ ++gEventQueueLogCount;
+#endif
+
+ // this is probably OK, but shouldn't happen by design, so tell me if it does
+ NS_ASSERTION(!mYoungerQueue, "event queue chain broken in middle");
+
+ // break links early in case the Release cascades back onto us
+ mYoungerQueue = nsnull;
+ mElderQueue = nsnull;
+
+ if (young)
+ young->SetElder(old);
+ if (old) {
+ old->SetYounger(young);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::GetYoungest(nsIEventQueue **aQueue)
+{
+ if (mYoungerQueue)
+ return mYoungerQueue->GetYoungest(aQueue);
+
+ nsIEventQueue *answer = NS_STATIC_CAST(nsIEventQueue *, this);
+ NS_ADDREF(answer);
+ *aQueue = answer;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::GetYoungestActive(nsIEventQueue **aQueue)
+{
+ nsCOMPtr<nsIEventQueue> answer;
+
+ if (mYoungerQueue)
+ mYoungerQueue->GetYoungestActive(getter_AddRefs(answer));
+ if (!answer) {
+ if (mAcceptingEvents && mCouldHaveEvents)
+ answer = NS_STATIC_CAST(nsIEventQueue *, this);
+ }
+ *aQueue = answer;
+ NS_IF_ADDREF(*aQueue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::SetYounger(nsPIEventQueueChain *aQueue)
+{
+ mYoungerQueue = aQueue;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::SetElder(nsPIEventQueueChain *aQueue)
+{
+ mElderQueue = aQueue;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::GetYounger(nsIEventQueue **aQueue)
+{
+ if (!mYoungerQueue) {
+ *aQueue = nsnull;
+ return NS_OK;
+ }
+ return mYoungerQueue->QueryInterface(NS_GET_IID(nsIEventQueue), (void**)&aQueue);
+}
+
+NS_IMETHODIMP
+nsEventQueueImpl::GetElder(nsIEventQueue **aQueue)
+{
+ if (!mElderQueue) {
+ *aQueue = nsnull;
+ return NS_OK;
+ }
+ return mElderQueue->QueryInterface(NS_GET_IID(nsIEventQueue), (void**)&aQueue);
+}
+
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.h b/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.h
new file mode 100644
index 00000000..51f33e47
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.h
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Pierre Phaneuf <pp@ludusdesign.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "prmon.h"
+#include "nsIEventQueue.h"
+#include "nsPIEventQueueChain.h"
+
+class nsEventQueueImpl : public nsIEventQueue,
+ public nsPIEventQueueChain
+{
+public:
+ nsEventQueueImpl();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIEVENTTARGET
+ NS_DECL_NSIEVENTQUEUE
+
+ // Helpers
+ static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr);
+
+ static const nsCID& CID() { static nsCID cid = NS_EVENTQUEUE_CID; return cid; }
+
+ // nsPIEventQueueChain interface
+ NS_IMETHOD AppendQueue(nsIEventQueue *aQueue);
+ NS_IMETHOD Unlink();
+ NS_IMETHOD GetYoungest(nsIEventQueue **aQueue);
+ NS_IMETHOD GetYoungestActive(nsIEventQueue **aQueue);
+ NS_IMETHOD SetYounger(nsPIEventQueueChain *aQueue);
+ NS_IMETHOD GetYounger(nsIEventQueue **aQueue);
+ NS_IMETHOD SetElder(nsPIEventQueueChain *aQueue);
+ NS_IMETHOD GetElder(nsIEventQueue **aQueue);
+
+private:
+ ~nsEventQueueImpl();
+
+ PLEventQueue *mEventQueue;
+ PRBool mAcceptingEvents, // accept new events or pass them on?
+ mCouldHaveEvents; // accepting new ones, or still have old ones?
+ nsCOMPtr<nsPIEventQueueChain> mElderQueue; // younger can hold on to elder
+ nsPIEventQueueChain *mYoungerQueue; // but elder can't hold on to younger
+
+ void NotifyObservers(const char *aTopic);
+
+ void CheckForDeactivation() {
+ if (mCouldHaveEvents && !mAcceptingEvents && !PL_EventAvailable(mEventQueue)) {
+ if (PL_IsQueueOnCurrentThread(mEventQueue)) {
+ mCouldHaveEvents = PR_FALSE;
+ NS_RELEASE_THIS(); // balance ADDREF from the constructor
+ } else
+ NS_ERROR("CheckForDeactivation called from wrong thread!");
+ }
+ }
+};
+
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.cpp b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.cpp
new file mode 100644
index 00000000..4fbb65aa
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.cpp
@@ -0,0 +1,450 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Rick Potts <rpotts@netscape.com>
+ * Ramiro Estrugo <ramiro@netscape.com>
+ * Warren Harris <warren@netscape.com>
+ * Leaf Nunes <leaf@mozilla.org>
+ * David Matiskella <davidm@netscape.com>
+ * David Hyatt <hyatt@netscape.com>
+ * Seth Spitzer <sspitzer@netscape.com>
+ * Suresh Duddi <dp@netscape.com>
+ * Bruce Mitchener <bruce@cybersight.com>
+ * Scott Collins <scc@netscape.com>
+ * Daniel Matejka <danm@netscape.com>
+ * Doug Turner <dougt@netscape.com>
+ * Stuart Parmenter <pavlov@netscape.com>
+ * Mike Kaply <mkaply@us.ibm.com>
+ * Dan Mosedale <dmose@mozilla.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsEventQueueService.h"
+#include "prmon.h"
+#include "nsIComponentManager.h"
+#include "nsIThread.h"
+#include "nsPIEventQueueChain.h"
+
+#include "prlog.h"
+
+#if defined(PR_LOGGING) || defined(DEBUG_danm)
+extern PRLogModuleInfo* gEventQueueLog;
+extern PRUint32 gEventQueueLogCount;
+#endif
+
+static NS_DEFINE_CID(kEventQueueCID, NS_EVENTQUEUE_CID);
+
+nsEventQueueServiceImpl::nsEventQueueServiceImpl()
+{
+ mEventQMonitor = PR_NewMonitor();
+#if defined(PR_LOGGING) && defined(DEBUG_danm)
+ if (!gEventQueueLog)
+ gEventQueueLog = PR_NewLogModule("nseventqueue");
+#endif
+}
+
+PR_STATIC_CALLBACK(PLDHashOperator)
+hash_enum_remove_queues(const void *aThread_ptr,
+ nsCOMPtr<nsIEventQueue>& aEldestQueue,
+ void* closure)
+{
+ // 'aQueue' should be the eldest queue.
+ nsCOMPtr<nsPIEventQueueChain> pie(do_QueryInterface(aEldestQueue));
+ nsCOMPtr<nsIEventQueue> q;
+
+ // stop accepting events for youngest to oldest
+ pie->GetYoungest(getter_AddRefs(q));
+ while (q) {
+ q->StopAcceptingEvents();
+
+ nsCOMPtr<nsPIEventQueueChain> pq(do_QueryInterface(q));
+ pq->GetElder(getter_AddRefs(q));
+ }
+
+ return PL_DHASH_REMOVE;
+}
+
+nsEventQueueServiceImpl::~nsEventQueueServiceImpl()
+{
+ // XXX make it so we only enum over this once
+ mEventQTable.Enumerate(hash_enum_remove_queues, nsnull); // call StopAcceptingEvents on everything and clear out the hashtable
+
+ PR_DestroyMonitor(mEventQMonitor);
+}
+
+nsresult
+nsEventQueueServiceImpl::Init()
+{
+ NS_ENSURE_TRUE(mEventQMonitor, NS_ERROR_OUT_OF_MEMORY);
+
+ // This will only be called once on the main thread, so it's safe to
+ // not enter the monitor here.
+ if (!mEventQTable.Init()) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ // ensure that a main thread event queue exists!
+ nsresult rv;
+ nsCOMPtr<nsIThread> mainThread;
+ rv = nsIThread::GetMainThread(getter_AddRefs(mainThread));
+ if (NS_SUCCEEDED(rv)) {
+ PRThread *thr;
+ rv = mainThread->GetPRThread(&thr);
+ if (NS_SUCCEEDED(rv))
+ rv = CreateEventQueue(thr, PR_TRUE);
+ }
+ return rv;
+}
+
+/* nsISupports interface implementation... */
+NS_IMPL_THREADSAFE_ISUPPORTS1(nsEventQueueServiceImpl, nsIEventQueueService)
+
+/* nsIEventQueueService interface implementation... */
+
+NS_IMETHODIMP
+nsEventQueueServiceImpl::CreateThreadEventQueue()
+{
+ return CreateEventQueue(PR_GetCurrentThread(), PR_TRUE);
+}
+
+NS_IMETHODIMP
+nsEventQueueServiceImpl::CreateMonitoredThreadEventQueue()
+{
+ return CreateEventQueue(PR_GetCurrentThread(), PR_FALSE);
+}
+
+NS_IMETHODIMP
+nsEventQueueServiceImpl::CreateFromIThread(nsIThread *aThread, PRBool aNative,
+ nsIEventQueue **aResult)
+{
+ nsresult rv;
+ PRThread *prThread;
+
+ rv = aThread->GetPRThread(&prThread);
+ if (NS_SUCCEEDED(rv)) {
+ rv = CreateEventQueue(prThread, aNative); // addrefs
+ if (NS_SUCCEEDED(rv))
+ rv = GetThreadEventQueue(prThread, aResult); // addrefs
+ }
+ return rv;
+}
+
+// private method
+NS_IMETHODIMP
+nsEventQueueServiceImpl::MakeNewQueue(PRThread* thread,
+ PRBool aNative,
+ nsIEventQueue **aQueue)
+{
+ nsresult rv;
+ nsCOMPtr<nsIEventQueue> queue = do_CreateInstance(kEventQueueCID, &rv);
+
+ if (NS_SUCCEEDED(rv)) {
+ rv = queue->InitFromPRThread(thread, aNative);
+ }
+ *aQueue = queue;
+ NS_IF_ADDREF(*aQueue);
+ return rv;
+}
+
+// private method
+NS_IMETHODIMP
+nsEventQueueServiceImpl::CreateEventQueue(PRThread *aThread, PRBool aNative)
+{
+ nsresult rv = NS_OK;
+ /* Enter the lock that protects the EventQ hashtable... */
+ PR_EnterMonitor(mEventQMonitor);
+
+ /* create only one event queue chain per thread... */
+ if (!mEventQTable.GetWeak(aThread)) {
+ nsCOMPtr<nsIEventQueue> queue;
+
+ // we don't have one in the table
+ rv = MakeNewQueue(aThread, aNative, getter_AddRefs(queue)); // create new queue
+ mEventQTable.Put(aThread, queue); // add to the table (initial addref)
+ }
+
+ // Release the EventQ lock...
+ PR_ExitMonitor(mEventQMonitor);
+ return rv;
+}
+
+
+NS_IMETHODIMP
+nsEventQueueServiceImpl::DestroyThreadEventQueue(void)
+{
+ nsresult rv = NS_OK;
+
+ /* Enter the lock that protects the EventQ hashtable... */
+ PR_EnterMonitor(mEventQMonitor);
+
+ PRThread* currentThread = PR_GetCurrentThread();
+ nsIEventQueue* queue = mEventQTable.GetWeak(currentThread);
+ if (queue) {
+ queue->StopAcceptingEvents(); // tell the queue to stop accepting events
+ queue = nsnull; // Queue may die on the next line
+ mEventQTable.Remove(currentThread); // remove nsIEventQueue from hash table (releases)
+ }
+
+ // Release the EventQ lock...
+ PR_ExitMonitor(mEventQMonitor);
+ return rv;
+}
+
+NS_IMETHODIMP
+nsEventQueueServiceImpl::CreateFromPLEventQueue(PLEventQueue* aPLEventQueue, nsIEventQueue** aResult)
+{
+ // Create our thread queue using the component manager
+ nsresult rv;
+ nsCOMPtr<nsIEventQueue> queue = do_CreateInstance(kEventQueueCID, &rv);
+ if (NS_FAILED(rv)) return rv;
+
+ rv = queue->InitFromPLQueue(aPLEventQueue);
+ if (NS_FAILED(rv)) return rv;
+
+ *aResult = queue;
+ NS_IF_ADDREF(*aResult);
+ return NS_OK;
+}
+
+
+// Return the active event queue on our chain
+/* inline */
+nsresult nsEventQueueServiceImpl::GetYoungestEventQueue(nsIEventQueue *queue, nsIEventQueue **aResult)
+{
+ nsCOMPtr<nsIEventQueue> answer;
+
+ if (queue) {
+ nsCOMPtr<nsPIEventQueueChain> ourChain(do_QueryInterface(queue));
+ if (ourChain)
+ ourChain->GetYoungestActive(getter_AddRefs(answer));
+ else
+ answer = queue;
+ }
+
+ *aResult = answer;
+ NS_IF_ADDREF(*aResult);
+ return NS_OK;
+}
+
+
+// create new event queue, append it to the current thread's chain of event queues.
+// return it, addrefed.
+NS_IMETHODIMP
+nsEventQueueServiceImpl::PushThreadEventQueue(nsIEventQueue **aNewQueue)
+{
+ nsresult rv = NS_OK;
+ PRThread* currentThread = PR_GetCurrentThread();
+ PRBool native = PR_TRUE; // native by default as per old comment
+
+
+ NS_ASSERTION(aNewQueue, "PushThreadEventQueue called with null param");
+
+ /* Enter the lock that protects the EventQ hashtable... */
+ PR_EnterMonitor(mEventQMonitor);
+
+ nsIEventQueue* queue = mEventQTable.GetWeak(currentThread);
+
+ NS_ASSERTION(queue, "pushed event queue on top of nothing");
+
+ if (queue) { // find out what kind of queue our relatives are
+ nsCOMPtr<nsIEventQueue> youngQueue;
+ GetYoungestEventQueue(queue, getter_AddRefs(youngQueue));
+ if (youngQueue) {
+ youngQueue->IsQueueNative(&native);
+ }
+ }
+
+ nsIEventQueue* newQueue = nsnull;
+ MakeNewQueue(currentThread, native, &newQueue); // create new queue; addrefs
+
+ if (!queue) {
+ // shouldn't happen. as a fallback, we guess you wanted a native queue
+ mEventQTable.Put(currentThread, newQueue);
+ }
+
+ // append to the event queue chain
+ nsCOMPtr<nsPIEventQueueChain> ourChain(do_QueryInterface(queue)); // QI the queue in the hash table
+ if (ourChain)
+ ourChain->AppendQueue(newQueue); // append new queue to it
+
+ *aNewQueue = newQueue;
+
+#if defined(PR_LOGGING) && defined(DEBUG_danm)
+ PLEventQueue *equeue;
+ (*aNewQueue)->GetPLEventQueue(&equeue);
+ PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
+ ("EventQueue: Service push queue [queue=%lx]",(long)equeue));
+ ++gEventQueueLogCount;
+#endif
+
+ // Release the EventQ lock...
+ PR_ExitMonitor(mEventQMonitor);
+ return rv;
+}
+
+// disable and release the given queue (though the last one won't be released)
+NS_IMETHODIMP
+nsEventQueueServiceImpl::PopThreadEventQueue(nsIEventQueue *aQueue)
+{
+ PRThread* currentThread = PR_GetCurrentThread();
+
+ /* Enter the lock that protects the EventQ hashtable... */
+ PR_EnterMonitor(mEventQMonitor);
+
+ nsCOMPtr<nsIEventQueue> eldestQueue;
+ mEventQTable.Get(currentThread, getter_AddRefs(eldestQueue));
+
+ // If we are popping the eldest queue, remove its mEventQTable entry.
+ if (aQueue == eldestQueue)
+ mEventQTable.Remove(currentThread);
+
+ // Exit the monitor before processing pending events to avoid deadlock.
+ // Our reference from the eldestQueue nsCOMPtr will keep that object alive.
+ // Since it is thread-private, no one else can race with us here.
+ PR_ExitMonitor(mEventQMonitor);
+ if (!eldestQueue)
+ return NS_ERROR_FAILURE;
+
+#if defined(PR_LOGGING) && defined(DEBUG_danm)
+ PLEventQueue *equeue;
+ aQueue->GetPLEventQueue(&equeue);
+ PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
+ ("EventQueue: Service pop queue [queue=%lx]",(long)equeue));
+ ++gEventQueueLogCount;
+#endif
+ aQueue->StopAcceptingEvents();
+ aQueue->ProcessPendingEvents(); // make sure we don't orphan any events
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueServiceImpl::GetThreadEventQueue(PRThread* aThread, nsIEventQueue** aResult)
+{
+ /* Parameter validation... */
+ if (NULL == aResult) return NS_ERROR_NULL_POINTER;
+
+ PRThread* keyThread = aThread;
+
+ if (keyThread == NS_CURRENT_THREAD)
+ {
+ keyThread = PR_GetCurrentThread();
+ }
+ else if (keyThread == NS_UI_THREAD)
+ {
+ nsCOMPtr<nsIThread> mainIThread;
+
+ // Get the primordial thread
+ nsresult rv = nsIThread::GetMainThread(getter_AddRefs(mainIThread));
+ if (NS_FAILED(rv)) return rv;
+
+ rv = mainIThread->GetPRThread(&keyThread);
+ if (NS_FAILED(rv)) return rv;
+ }
+
+ /* Enter the lock that protects the EventQ hashtable... */
+ PR_EnterMonitor(mEventQMonitor);
+
+ nsCOMPtr<nsIEventQueue> queue;
+ mEventQTable.Get(keyThread, getter_AddRefs(queue));
+
+ PR_ExitMonitor(mEventQMonitor);
+
+ if (queue) {
+ GetYoungestEventQueue(queue, aResult); // get the youngest active queue
+ } else {
+ *aResult = nsnull;
+ }
+ // XXX: Need error code for requesting an event queue when none exists...
+ if (!*aResult) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsEventQueueServiceImpl::ResolveEventQueue(nsIEventQueue* queueOrConstant, nsIEventQueue* *resultQueue)
+{
+ if (queueOrConstant == NS_CURRENT_EVENTQ) {
+ return GetThreadEventQueue(NS_CURRENT_THREAD, resultQueue);
+ }
+ else if (queueOrConstant == NS_UI_THREAD_EVENTQ) {
+ return GetThreadEventQueue(NS_UI_THREAD, resultQueue);
+ }
+
+ *resultQueue = queueOrConstant;
+ NS_ADDREF(*resultQueue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsEventQueueServiceImpl::GetSpecialEventQueue(PRInt32 aQueue,
+ nsIEventQueue* *_retval)
+{
+ nsresult rv;
+
+ // barf if someone gave us a zero pointer
+ //
+ if (!_retval) {
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ // try and get the requested event queue, returning NS_ERROR_FAILURE if there
+ // is a problem. GetThreadEventQueue() does the AddRef() for us.
+ //
+ switch (aQueue) {
+ case CURRENT_THREAD_EVENT_QUEUE:
+ rv = GetThreadEventQueue(NS_CURRENT_THREAD, _retval);
+ if (NS_FAILED(rv)) {
+ return NS_ERROR_FAILURE;
+ }
+ break;
+
+ case UI_THREAD_EVENT_QUEUE:
+ rv = GetThreadEventQueue(NS_UI_THREAD, _retval);
+ if (NS_FAILED(rv)) {
+ return NS_ERROR_FAILURE;
+ }
+ break;
+
+ // somebody handed us a bogus constant
+ //
+ default:
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+
+ return NS_OK;
+}
+
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.h b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.h
new file mode 100644
index 00000000..6fddb941
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsEventQueueService_h__
+#define nsEventQueueService_h__
+
+#include "nsIEventQueueService.h"
+#include "nsInterfaceHashtable.h"
+#include "nsHashKeys.h"
+#include "nsIEventQueue.h"
+
+////////////////////////////////////////////////////////////////////////////////
+
+class nsEventQueueServiceImpl : public nsIEventQueueService
+{
+public:
+ nsEventQueueServiceImpl();
+
+ nsresult Init();
+
+ // nsISupports interface...
+ NS_DECL_ISUPPORTS
+
+ // nsIEventQueueService interface...
+ NS_DECL_NSIEVENTQUEUESERVICE
+
+private:
+ ~nsEventQueueServiceImpl();
+
+ /* Create a queue for the given thread if one does not exist.
+ Addref the descriptor in any case. parameter aNative is
+ ignored if the queue already exists. */
+ NS_IMETHOD CreateEventQueue(PRThread *aThread, PRBool aNative);
+ NS_IMETHOD MakeNewQueue(PRThread* thread, PRBool aNative, nsIEventQueue **aQueue);
+ inline nsresult GetYoungestEventQueue(nsIEventQueue *queue, nsIEventQueue **aResult);
+
+ nsInterfaceHashtable<nsVoidPtrHashKey, nsIEventQueue> mEventQTable;
+ PRMonitor *mEventQMonitor;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+#endif // nsEventQueueService_h__
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEventQueueUtils.h b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueUtils.h
new file mode 100644
index 00000000..5df2e406
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueUtils.h
@@ -0,0 +1,78 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsEventQueueUtils_h__
+#define nsEventQueueUtils_h__
+
+#include "nsIEventQueueService.h"
+#include "nsIServiceManager.h"
+#include "nsCOMPtr.h"
+
+inline nsresult
+NS_GetEventQueueService(nsIEventQueueService **result)
+{
+ static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
+ return CallGetService(kEventQueueServiceCID, result);
+}
+
+inline nsresult
+NS_GetCurrentEventQ(nsIEventQueue **result,
+ nsIEventQueueService *serv = nsnull)
+{
+ nsCOMPtr<nsIEventQueueService> eqs;
+ if (!serv) {
+ nsresult rv = NS_GetEventQueueService(getter_AddRefs(eqs));
+ if (NS_FAILED(rv)) return rv;
+ serv = eqs;
+ }
+ return serv->GetThreadEventQueue(NS_CURRENT_THREAD, result);
+}
+
+inline nsresult
+NS_GetMainEventQ(nsIEventQueue **result,
+ nsIEventQueueService *serv = nsnull)
+{
+ nsCOMPtr<nsIEventQueueService> eqs;
+ if (!serv) {
+ nsresult rv = NS_GetEventQueueService(getter_AddRefs(eqs));
+ if (NS_FAILED(rv)) return rv;
+ serv = eqs;
+ }
+ return serv->GetThreadEventQueue(NS_UI_THREAD, result);
+}
+
+#endif // !nsEventQueueUtils_h__
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIEnvironment.idl b/src/libs/xpcom18a4/xpcom/threads/nsIEnvironment.idl
new file mode 100644
index 00000000..95351346
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsIEnvironment.idl
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla embedding code.
+ *
+ * The Initial Developers of the Original Code are
+ * Benjamin Smedberg <bsmedberg@covad.net> and
+ * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>.
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2003/2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+/**
+ * Scriptable access to the current process environment.
+ *
+ */
+[scriptable, uuid(101d5941-d820-4e85-a266-9a3469940807)]
+interface nsIEnvironment : nsISupports
+{
+ /**
+ * Set the value of an environment variable.
+ *
+ * @param aName the variable name to set.
+ * @param aValue the value to set.
+ */
+ void set(in AString aName, in AString aValue);
+
+ /**
+ * Get the value of an environment variable.
+ *
+ * @param aName the variable name to retrieve.
+ * @return returns the value of the env variable. An empty string
+ * will be returned when the env variable does not exist or
+ * when the value itself is an empty string - please use
+ * |exists()| to probe whether the env variable exists
+ * or not.
+ */
+ AString get(in AString aName);
+
+ /**
+ * Check the existence of an environment variable.
+ * This method checks whether an environment variable is present in
+ * the environment or not.
+ *
+ * - For Unix/Linux platforms we follow the Unix definition:
+ * An environment variable exists when |getenv()| returns a non-NULL value.
+ * An environment variable does not exist when |getenv()| returns NULL.
+ * - For non-Unix/Linux platforms we have to fall back to a
+ * "portable" definition (which is incorrect for Unix/Linux!!!!)
+ * which simply checks whether the string returned by |Get()| is empty
+ * or not.
+ *
+ * @param aName the variable name to probe.
+ * @return if the variable has been set, the value returned is
+ * PR_TRUE. If the variable was not defined in the
+ * environment PR_FALSE will be returned.
+ */
+ boolean exists(in AString aName);
+};
+
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIEventQueue.idl b/src/libs/xpcom18a4/xpcom/threads/nsIEventQueue.idl
new file mode 100644
index 00000000..416c80a1
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsIEventQueue.idl
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * David Hyatt <hyatt@netscape.com>
+ * Suresh Duddi <dp@netscape.com>
+ * Doug Turner <dougt@netscape.com>
+ * Judson Valeski <valeski@netscape.com>
+ * Dan Matejka <danm@netscape.com>
+ * Ray Whitmer <rayw@netscape.com>
+ * Dan Mosedale <dmose@mozilla.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsIEventTarget.idl"
+
+%{C++
+#include "prthread.h"
+
+// {13D86C61-00A9-11d3-9F2A-00400553EEF0}
+#define NS_EVENTQUEUE_CID \
+{ 0x13d86c61, 0xa9, 0x11d3, { 0x9f, 0x2a, 0x0, 0x40, 0x5, 0x53, 0xee, 0xf0 } }
+
+#define NS_EVENTQUEUE_CONTRACTID "@mozilla.org/event-queue;1"
+#define NS_EVENTQUEUE_CLASSNAME "Event Queue"
+
+%}
+
+// some forward decls
+//
+[ptr] native PLEventQueuePtr(PLEventQueue);
+[ptr] native PRThreadPtr(PRThread);
+native PRStatus(PRStatus);
+[ref] native PRBoolRef(PRBool);
+native PLHandleEventProc(PLHandleEventProc);
+native PLDestroyEventProc(PLDestroyEventProc);
+
+[scriptable, uuid(176AFB41-00A4-11d3-9F2A-00400553EEF0)]
+interface nsIEventQueue : nsIEventTarget
+{
+ [noscript] void initEvent(in PLEventPtr aEvent,
+ in voidPtr owner,
+ in PLHandleEventProc handler,
+ in PLDestroyEventProc destructor);
+
+ [noscript] void postSynchronousEvent(in PLEventPtr aEvent,
+ out voidPtr aResult);
+
+ boolean pendingEvents();
+ void processPendingEvents();
+ void eventLoop();
+
+ [noscript] void eventAvailable(in PRBoolRef aResult);
+ [noscript] PLEventPtr getEvent();
+ [noscript] void handleEvent(in PLEventPtr aEvent);
+ [noscript] PLEventPtr waitForEvent();
+
+ [notxpcom] PRInt32 getEventQueueSelectFD();
+
+ void init(in boolean aNative);
+ [noscript] void initFromPRThread(in PRThreadPtr thread,
+ in boolean aNative);
+ [noscript] void initFromPLQueue(in PLEventQueuePtr aQueue);
+
+ void enterMonitor();
+ void exitMonitor();
+
+ [noscript] void revokeEvents(in voidPtr owner);
+ [noscript] PLEventQueuePtr getPLEventQueue();
+
+ boolean isQueueNative();
+
+ // effectively kill the queue. warning: the queue is allowed to delete
+ // itself any time after this.
+ void stopAcceptingEvents();
+};
+
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIEventQueueService.idl b/src/libs/xpcom18a4/xpcom/threads/nsIEventQueueService.idl
new file mode 100644
index 00000000..e9c93e86
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsIEventQueueService.idl
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Rick Potts <rpotts@netscape.com>
+ * David Matiskella <davidm@netscape.com>
+ * David Hyatt <hyatt@netscape.com>
+ * Suresh Duddi <dp@netscape.com>
+ * Scott Collins <scc@netscape.com>
+ * Dan Matejka <danm@netscape.com>
+ * Doug Turner <dougt@netscape.com>
+ * Ray Whitmer <rayw@netscape.com>
+ * Dan Mosedale <dmose@mozilla.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+#include "nsIEventQueue.idl"
+
+%{C++
+#include "prthread.h"
+#include "plevent.h"
+
+/* be761f00-a3b0-11d2-996c-0080c7cb1080 */
+#define NS_EVENTQUEUESERVICE_CID \
+{ 0xbe761f00, 0xa3b0, 0x11d2, \
+ {0x99, 0x6c, 0x00, 0x80, 0xc7, 0xcb, 0x10, 0x80} }
+
+#define NS_EVENTQUEUESERVICE_CONTRACTID "@mozilla.org/event-queue-service;1"
+#define NS_EVENTQUEUESERVICE_CLASSNAME "Event Queue Service"
+
+#define NS_CURRENT_THREAD ((PRThread*)0)
+#define NS_CURRENT_EVENTQ ((nsIEventQueue*)0)
+
+#define NS_UI_THREAD ((PRThread*)1)
+#define NS_UI_THREAD_EVENTQ ((nsIEventQueue*)1)
+
+%}
+
+/* a forward decl */
+interface nsIThread;
+
+[scriptable, uuid(a6cf90dc-15b3-11d2-932e-00805f8add32)]
+interface nsIEventQueueService : nsISupports
+{
+ /**
+ * Creates and holds a native event queue for the current thread.
+ * "Native" queues have an associated callback mechanism which is
+ * automatically triggered when an event is posted. See plevent.c for
+ * details.
+ * @return NS_OK on success, or a host of failure indications
+ */
+ void createThreadEventQueue();
+
+ /**
+ * Creates and hold a monitored event queue for the current thread.
+ * "Monitored" queues have no callback processing mechanism.
+ * @return NS_OK on success, or a host of failure indications
+ */
+ void createMonitoredThreadEventQueue();
+
+ /**
+ * Somewhat misnamed, this method releases the service's hold on the event
+ * queue(s) for this thread. Subsequent attempts to access this thread's
+ * queue (GetThreadEventQueue, for example) may fail, though the queue itself
+ * will be destroyed only after all references to it are released and the
+ * queue itself is no longer actively processing events.
+ * @return nonsense.
+ */
+ void destroyThreadEventQueue();
+
+ nsIEventQueue createFromIThread(in nsIThread aThread,
+ in boolean aNative);
+
+ [noscript] nsIEventQueue createFromPLEventQueue(in PLEventQueuePtr
+ aPLEventQueue);
+
+ // Add a new event queue for the current thread, making it the "current"
+ // queue. Return that queue, addrefed.
+ nsIEventQueue pushThreadEventQueue();
+
+ // release and disable the queue
+ void popThreadEventQueue(in nsIEventQueue aQueue);
+
+ [noscript] nsIEventQueue getThreadEventQueue(in PRThreadPtr aThread);
+
+ /**
+ * @deprecated in favor of getSpecialEventQueue, since that's
+ * scriptable and this isn't.
+ *
+ * Check for any "magic" event queue constants (NS_CURRENT_EVENTQ,
+ * NS_UI_THREAD_EVENTQ) and return the real event queue that they
+ * represent, AddRef()ed. Otherwise, return the event queue passed
+ * in, AddRef()ed. This is not scriptable because the arguments in
+ * question may be magic constants rather than real nsIEventQueues.
+ *
+ * @arg queueOrConstant either a real event queue or a magic
+ * constant to be resolved
+ *
+ * @return a real event queue, AddRef()ed
+ */
+ [noscript] nsIEventQueue resolveEventQueue(in nsIEventQueue queueOrConstant);
+
+ /**
+ * Returns the appropriate special event queue, AddRef()ed. Really
+ * just a scriptable version of ResolveEventQueue.
+ *
+ * @arg aQueue Either CURRENT_THREAD_EVENT_QUEUE or
+ * UI_THREAD_EVENT_QUEUE
+ * @return The requested nsIEventQueue, AddRef()ed
+ * @exception NS_ERROR_NULL_POINTER Zero pointer passed in for return value
+ * @exception NS_ERROR_ILLEGAL_VALUE Bogus constant passed in aQueue
+ * @exception NS_ERROR_FAILURE Error while calling
+ * GetThreadEventQueue()
+ */
+ nsIEventQueue getSpecialEventQueue(in long aQueue);
+
+ const long CURRENT_THREAD_EVENT_QUEUE = 0;
+ const long UI_THREAD_EVENT_QUEUE = 1;
+
+};
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIEventTarget.idl b/src/libs/xpcom18a4/xpcom/threads/nsIEventTarget.idl
new file mode 100644
index 00000000..3b19d9ca
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsIEventTarget.idl
@@ -0,0 +1,67 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by IBM Corporation are Copyright (C) 2003
+ * IBM Corporation. All Rights Reserved.
+ *
+ * Contributor(s):
+ * IBM Corp.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+%{C++
+#include "plevent.h"
+%}
+
+[ptr] native PLEventPtr(PLEvent);
+
+/**
+ * nsIEventTarget
+ *
+ * This interface is used to dispatch events to a particular thread. In many
+ * cases the event target also supports nsIEventQueue.
+ */
+[scriptable, uuid(ea99ad5b-cc67-4efb-97c9-2ef620a59f2a)]
+interface nsIEventTarget : nsISupports
+{
+ /**
+ * Method for posting an asynchronous event to the event target. If this
+ * method succeeds, then the event will be dispatched on the target thread.
+ *
+ * @param aEvent
+ * The event to dispatched.
+ */
+ [noscript] void postEvent(in PLEventPtr aEvent);
+
+ /**
+ * This method returns true if the event target is the current thread.
+ */
+ boolean isOnCurrentThread();
+};
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIProcess.idl b/src/libs/xpcom18a4/xpcom/threads/nsIProcess.idl
new file mode 100644
index 00000000..07769cb7
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsIProcess.idl
@@ -0,0 +1,32 @@
+#include "nsIFile.idl"
+#include "nsISupports.idl"
+
+[scriptable, uuid(9da0b650-d07e-4617-a18a-250035572ac8)]
+
+interface nsIProcess : nsISupports
+{
+ void init(in nsIFile executable);
+ void initWithPid(in unsigned long pid);
+
+ void kill();
+
+ /** XXX what charset? **/
+ /** Executes the file this object was initialized with
+ * @param blocking Whether to wait until the process terminates before returning or not
+ * @param args An array of arguments to pass to the process
+ * @param count The length of the args array
+ * @return the PID of the newly spawned process */
+ unsigned long run(in boolean blocking, [array, size_is(count)] in string args, in unsigned long count);
+
+ readonly attribute nsIFile location;
+ readonly attribute unsigned long pid;
+ readonly attribute string processName;
+ readonly attribute unsigned long processSignature;
+ readonly attribute long exitValue;
+};
+
+%{C++
+
+#define NS_PROCESS_CONTRACTID "@mozilla.org/process/util;1"
+#define NS_PROCESS_CLASSNAME "Process Specification"
+%}
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIRunnable.idl b/src/libs/xpcom18a4/xpcom/threads/nsIRunnable.idl
new file mode 100644
index 00000000..1cedda38
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsIRunnable.idl
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+[scriptable, uuid(4a2abaf0-6886-11d3-9382-00104ba0fd40)]
+interface nsIRunnable : nsISupports
+{
+ void run();
+};
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIThread.idl b/src/libs/xpcom18a4/xpcom/threads/nsIThread.idl
new file mode 100644
index 00000000..f28d6ec9
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsIThread.idl
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+%{C++
+#include "prthread.h"
+
+#define NS_THREAD_CID \
+{ /* 85CE5510-7808-11d3-A181-0050041CAF44 */ \
+ 0x85ce5510, \
+ 0x7808, \
+ 0x11d3, \
+ {0xa1, 0x81, 0x00, 0x50, 0x04, 0x1c, 0xaf, 0x44} \
+}
+
+#define NS_THREAD_CONTRACTID "@mozilla.org/thread;1"
+#define NS_THREAD_CLASSNAME "Thread"
+#if 0
+%}
+
+typedef PRUint32 PRThreadPriority;
+typedef PRUint32 PRThreadScope;
+typedef PRUint32 PRThreadState;
+
+%{C++
+#endif
+%}
+
+interface nsIRunnable;
+
+[ptr] native PRThread(PRThread);
+
+[scriptable, uuid(6be5e380-6886-11d3-9382-00104ba0fd40)]
+interface nsIThread : nsISupports
+{
+ // These must all match the values used in prthread.h
+ const PRUint32 PRIORITY_LOW = 0;
+ const PRUint32 PRIORITY_NORMAL = 1;
+ const PRUint32 PRIORITY_HIGH = 2;
+ const PRUint32 PRIORITY_URGENT = 3;
+
+ const PRUint32 SCOPE_LOCAL = 0;
+ const PRUint32 SCOPE_GLOBAL = 1;
+ const PRUint32 SCOPE_BOUND = 2;
+
+ const PRUint32 STATE_JOINABLE = 0;
+ const PRUint32 STATE_UNJOINABLE = 1;
+
+ void join();
+ void interrupt();
+
+ attribute PRThreadPriority priority;
+ readonly attribute PRThreadScope scope;
+ readonly attribute PRThreadState state;
+
+ [noscript] PRThread GetPRThread();
+
+ void init(in nsIRunnable aRunnable,
+ in PRUint32 aStackSize,
+ in PRThreadPriority aPriority,
+ in PRThreadScope aScope,
+ in PRThreadState aState);
+
+ /*
+ * Get the currently running thread (really a static method sort of thing).
+ */
+ readonly attribute nsIThread currentThread;
+
+ /*
+ * Sleep to at least this many milliseconds (only works on currrent thread).
+ */
+ void sleep(in PRUint32 msec);
+
+%{C++
+ // returns the nsIThread for the current thread:
+ static NS_COM nsresult GetCurrent(nsIThread* *result);
+
+ // returns the nsIThread for an arbitrary PRThread:
+ static NS_COM nsresult GetIThread(PRThread* prthread, nsIThread* *result);
+
+ // initializes the "main" thread (really, just saves the current thread
+ // at time of calling. meant to be called once at app startup, in lieu
+ // of proper static initializers, to save the primordial thread
+ // for later recall.)
+ static NS_COM nsresult SetMainThread();
+
+ // return the "main" thread
+ static NS_COM nsresult GetMainThread(nsIThread **result);
+
+ static NS_COM PRBool IsMainThread();
+%}
+};
+
+%{C++
+extern NS_COM nsresult
+NS_NewThread(nsIThread* *result,
+ nsIRunnable* runnable,
+ PRUint32 stackSize = 0,
+ PRThreadState state = PR_UNJOINABLE_THREAD,
+ PRThreadPriority priority = PR_PRIORITY_NORMAL,
+ PRThreadScope scope = PR_GLOBAL_THREAD);
+
+extern NS_COM nsresult
+NS_NewThread(nsIThread* *result,
+ PRUint32 stackSize = 0,
+ PRThreadState state = PR_UNJOINABLE_THREAD,
+ PRThreadPriority priority = PR_PRIORITY_NORMAL,
+ PRThreadScope scope = PR_GLOBAL_THREAD);
+%}
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsITimer.idl b/src/libs/xpcom18a4/xpcom/threads/nsITimer.idl
new file mode 100644
index 00000000..855d538d
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsITimer.idl
@@ -0,0 +1,191 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIObserver;
+
+%{C++
+/**
+ * The signature of the timer callback function passed to initWithCallback. This
+ * is the function that will get called when the timer expires if the timer is
+ * initialized via initWithCallback.
+ *
+ * @param aTimer the timer which has expired
+ * @param aClosure opaque parameter passed to initWithCallback
+ *
+ * Implementers should return the following:
+ *
+ * @return NS_OK
+ *
+ */
+class nsITimer;
+typedef void (*nsTimerCallbackFunc) (nsITimer *aTimer, void *aClosure);
+%}
+
+native nsTimerCallbackFunc(nsTimerCallbackFunc);
+
+/**
+ * The callback interface for timers.
+ */
+interface nsITimer;
+
+[scriptable, uuid(a796816d-7d47-4348-9ab8-c7aeb3216a7d)]
+interface nsITimerCallback : nsISupports
+{
+ /**
+ * @param aTimer the timer which has expired
+ */
+ void notify(in nsITimer timer);
+};
+
+
+/**
+ * nsITimer instances must be initialized by calling one of the "init" methods
+ * documented below. You may also re-initialize an existing instance with new
+ * delay to avoid the overhead of destroying and creating a timer. It is not
+ * necessary to cancel the timer in that case.
+ */
+[scriptable, uuid(29ee628e-a3ea-471f-965d-dc9f11d1c183)]
+interface nsITimer : nsISupports
+{
+ /* Timer types */
+
+ /**
+ * Type of a timer that fires once only.
+ */
+ const short TYPE_ONE_SHOT = 0;
+
+ /**
+ * After firing, a TYPE_REPEATING_SLACK timer is stopped and not restarted
+ * until its callback completes. Specified timer period will be at least
+ * the time between when processing for last firing the callback completes
+ * and when the next firing occurs.
+ *
+ * This is the preferable repeating type for most situations.
+ */
+ const short TYPE_REPEATING_SLACK = 1;
+
+ /**
+ * An TYPE_REPEATING_PRECISE repeating timer aims to have constant period
+ * between firings. The processing time for each timer callback should not
+ * influence the timer period. However, if the processing for the last
+ * timer firing could not be completed until just before the next firing
+ * occurs, then you could have two timer notification routines being
+ * executed in quick succession.
+ */
+ const short TYPE_REPEATING_PRECISE = 2;
+
+ /**
+ * Initialize a timer that will fire after the said delay.
+ * A user must keep a reference to this timer till it is
+ * is no longer needed or has been cancelled.
+ *
+ * @param aObserver the callback object that observes the
+ * ``timer-callback'' topic with the subject being
+ * the timer itself when the timer fires:
+ *
+ * observe(nsISupports aSubject, => nsITimer
+ * string aTopic, => ``timer-callback''
+ * wstring data => null
+ *
+ * @param aDelay delay in milliseconds for timer to fire
+ * @param aType timer type per TYPE* consts defined above
+ */
+ void init(in nsIObserver aObserver, in unsigned long aDelay,
+ in unsigned long aType);
+
+
+ /**
+ * 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 aDelay The millisecond interval
+ * @param aType Timer type per TYPE* consts defined above
+ */
+ [noscript] void initWithFuncCallback(in nsTimerCallbackFunc aCallback,
+ in voidPtr aClosure,
+ in unsigned long aDelay,
+ in unsigned long aType);
+
+ /**
+ * 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 nsITimerCallback interface to call when timer expires
+ * @param aDelay The millisecond interval
+ * @param aType Timer type per TYPE* consts defined above
+ */
+ void initWithCallback(in nsITimerCallback aCallback,
+ in unsigned long aDelay,
+ in unsigned long aType);
+
+ /**
+ * Cancel the timer. This method works on all types, not just on repeating
+ * timers -- you might want to cancel a TYPE_ONE_SHOT timer, and even reuse
+ * it by re-initializing it (to avoid object destruction and creation costs
+ * by conserving one timer instance).
+ */
+ void cancel();
+
+ /**
+ * The millisecond delay of the timeout
+ */
+ attribute unsigned long delay;
+
+ /**
+ * The timer type : one shot or repeating
+ */
+ attribute unsigned long type;
+
+ /**
+ * The opaque pointer pass to initWithCallback.
+ */
+ [noscript] readonly attribute voidPtr closure;
+};
+
+%{C++
+#define NS_TIMER_CONTRACTID "@mozilla.org/timer;1"
+#define NS_TIMER_CALLBACK_TOPIC "timer-callback"
+%}
+
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsITimerInternal.idl b/src/libs/xpcom18a4/xpcom/threads/nsITimerInternal.idl
new file mode 100644
index 00000000..c334ae19
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsITimerInternal.idl
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+
+[scriptable, uuid(6dd8f185-ceb8-4878-8e38-2d13edc2d079)]
+interface nsITimerInternal : nsISupports
+{
+ attribute boolean idle;
+};
+
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsITimerManager.idl b/src/libs/xpcom18a4/xpcom/threads/nsITimerManager.idl
new file mode 100644
index 00000000..f391d313
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsITimerManager.idl
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Stuart Parmenter <pavlov@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+[scriptable, uuid(8fce8c6a-1dd2-11b2-8352-8cdd2b965efc)]
+interface nsITimerManager : nsISupports
+{
+ /**
+ * A flag that turns on the use of idle timers on the main thread.
+ * this should only be called once.
+ *
+ * By default, idle timers are off.
+ *
+ * One this is set to TRUE, you are expected to call hasIdleTimers/fireNextIdleTimer
+ * when you have time in your main loop.
+ */
+ attribute boolean useIdleTimers;
+
+ boolean hasIdleTimers();
+
+ // Fire next idle timers waiting on the current thread
+ void fireNextIdleTimer();
+};
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsPIEventQueueChain.h b/src/libs/xpcom18a4/xpcom/threads/nsPIEventQueueChain.h
new file mode 100644
index 00000000..8d3c0933
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsPIEventQueueChain.h
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsPIEventQueueChain_h__
+#define nsPIEventQueueChain_h__
+
+#include "nsISupports.h"
+
+// {8f310040-82a7-11d3-95bc-0060083a0bcf}
+#define NS_IEVENTQUEUECHAIN_IID \
+{ 0x8f310040, 0x82a7, 0x11d3, { 0x95, 0xbc, 0x0, 0x60, 0x8, 0x3a, 0xb, 0xcf } }
+
+class nsIEventQueue;
+
+class nsPIEventQueueChain : public nsISupports
+{
+public:
+ NS_DEFINE_STATIC_IID_ACCESSOR(NS_IEVENTQUEUECHAIN_IID);
+
+ /**
+ * Add the given queue as the new youngest member of our chain.
+ * It will not be addrefed.
+ * @param aQueue the queue. must not be null.
+ * @return error indication
+ */
+ NS_IMETHOD AppendQueue(nsIEventQueue *aQueue) = 0;
+
+ /**
+ * Remove this element from the chain.
+ * @return NS_OK
+ */
+ NS_IMETHOD Unlink() = 0;
+
+ /**
+ * Fetch (and addref) the youngest member of the chain.
+ * @param *aQueue the youngest queue. aQueue must not be null.
+ * @return error indication
+ */
+ NS_IMETHOD GetYoungest(nsIEventQueue **aQueue) = 0;
+
+ /**
+ * Fetch (and addref) the youngest member of the chain which is
+ * still accepting events, or at least still contains events in need
+ * of processing.
+ * @param *aQueue the youngest such queue. aQueue must not be null.
+ * *aQueue will be returned null, if no such queue is found.
+ * @return error indication -- can be NS_OK even if *aQueue is 0
+ */
+ NS_IMETHOD GetYoungestActive(nsIEventQueue **aQueue) = 0;
+
+ NS_IMETHOD SetYounger(nsPIEventQueueChain *aQueue) = 0;
+ NS_IMETHOD GetYounger(nsIEventQueue **aQueue) = 0;
+
+ NS_IMETHOD SetElder(nsPIEventQueueChain *aQueue) = 0;
+ NS_IMETHOD GetElder(nsIEventQueue **aQueue) = 0;
+};
+
+#endif /* nsPIEventQueueChain_h___ */
+
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsProcess.h b/src/libs/xpcom18a4/xpcom/threads/nsProcess.h
new file mode 100644
index 00000000..f061fe1c
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsProcess.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Don Bragg <dbragg@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _nsPROCESSWIN_H_
+#define _nsPROCESSWIN_H_
+
+#include "nsIProcess.h"
+#include "nsIFile.h"
+#include "nsString.h"
+#include "prproces.h"
+
+#define NS_PROCESS_CID \
+{0x7b4eeb20, 0xd781, 0x11d4, \
+ {0x8A, 0x83, 0x00, 0x10, 0xa4, 0xe0, 0xc9, 0xca}}
+
+class nsProcess : public nsIProcess
+{
+public:
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIPROCESS
+
+ nsProcess();
+
+private:
+ ~nsProcess() {}
+
+ nsCOMPtr<nsIFile> mExecutable;
+ PRInt32 mExitValue;
+ nsCString mTargetPath;
+ PRProcess *mProcess;
+
+};
+
+#endif
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsProcessCommon.cpp b/src/libs/xpcom18a4/xpcom/threads/nsProcessCommon.cpp
new file mode 100644
index 00000000..07087c2f
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsProcessCommon.cpp
@@ -0,0 +1,363 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Don Bragg <dbragg@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*****************************************************************************
+ *
+ * nsProcess is used to execute new processes and specify if you want to
+ * wait (blocking) or continue (non-blocking).
+ *
+ *****************************************************************************
+ */
+
+#include "nsCOMPtr.h"
+#include "nsMemory.h"
+#include "nsProcess.h"
+#include "prtypes.h"
+#include "prio.h"
+#include "prenv.h"
+#include "nsCRT.h"
+
+#include <stdlib.h>
+
+#if defined( XP_WIN )
+#include "prmem.h"
+#include "nsString.h"
+#include "nsLiteralString.h"
+#include "nsReadableUtils.h"
+#include <windows.h>
+#endif
+
+//-------------------------------------------------------------------//
+// nsIProcess implementation
+//-------------------------------------------------------------------//
+NS_IMPL_ISUPPORTS1(nsProcess, nsIProcess)
+
+//Constructor
+nsProcess::nsProcess():mExitValue(-1),
+ mProcess(nsnull)
+{
+}
+
+NS_IMETHODIMP
+nsProcess::Init(nsIFile* executable)
+{
+ PRBool isFile;
+
+ //First make sure the file exists
+ nsresult rv = executable->IsFile(&isFile);
+ if (NS_FAILED(rv)) return rv;
+ if (!isFile)
+ return NS_ERROR_FAILURE;
+
+ //Store the nsIFile in mExecutable
+ mExecutable = executable;
+ //Get the path because it is needed by the NSPR process creation
+#ifdef XP_WIN
+ rv = mExecutable->GetNativeTarget(mTargetPath);
+ if (NS_FAILED(rv) || mTargetPath.IsEmpty() )
+#endif
+ rv = mExecutable->GetNativePath(mTargetPath);
+
+ return rv;
+}
+
+
+#if defined( XP_WIN )
+static int assembleCmdLine(char *const *argv, char **cmdLine)
+{
+ char *const *arg;
+ char *p, *q;
+ int cmdLineSize;
+ int numBackslashes;
+ int i;
+ int argNeedQuotes;
+
+ /*
+ * Find out how large the command line buffer should be.
+ */
+ cmdLineSize = 0;
+ for (arg = argv; *arg; arg++) {
+ /*
+ * \ and " need to be escaped by a \. In the worst case,
+ * every character is a \ or ", so the string of length
+ * may double. If we quote an argument, that needs two ".
+ * Finally, we need a space between arguments, and
+ * a null byte at the end of command line.
+ */
+ cmdLineSize += 2 * strlen(*arg) /* \ and " need to be escaped */
+ + 2 /* we quote every argument */
+ + 1; /* space in between, or final null */
+ }
+ p = *cmdLine = (char *) PR_MALLOC(cmdLineSize);
+ if (p == NULL) {
+ return -1;
+ }
+
+ for (arg = argv; *arg; arg++) {
+ /* Add a space to separates the arguments */
+ if (arg != argv) {
+ *p++ = ' ';
+ }
+ q = *arg;
+ numBackslashes = 0;
+ argNeedQuotes = 0;
+
+ /* If the argument contains white space, it needs to be quoted. */
+ if (strpbrk(*arg, " \f\n\r\t\v")) {
+ argNeedQuotes = 1;
+ }
+
+ if (argNeedQuotes) {
+ *p++ = '"';
+ }
+ while (*q) {
+ if (*q == '\\') {
+ numBackslashes++;
+ q++;
+ } else if (*q == '"') {
+ if (numBackslashes) {
+ /*
+ * Double the backslashes since they are followed
+ * by a quote
+ */
+ for (i = 0; i < 2 * numBackslashes; i++) {
+ *p++ = '\\';
+ }
+ numBackslashes = 0;
+ }
+ /* To escape the quote */
+ *p++ = '\\';
+ *p++ = *q++;
+ } else {
+ if (numBackslashes) {
+ /*
+ * Backslashes are not followed by a quote, so
+ * don't need to double the backslashes.
+ */
+ for (i = 0; i < numBackslashes; i++) {
+ *p++ = '\\';
+ }
+ numBackslashes = 0;
+ }
+ *p++ = *q++;
+ }
+ }
+
+ /* Now we are at the end of this argument */
+ if (numBackslashes) {
+ /*
+ * Double the backslashes if we have a quote string
+ * delimiter at the end.
+ */
+ if (argNeedQuotes) {
+ numBackslashes *= 2;
+ }
+ for (i = 0; i < numBackslashes; i++) {
+ *p++ = '\\';
+ }
+ }
+ if (argNeedQuotes) {
+ *p++ = '"';
+ }
+ }
+
+ *p = '\0';
+ return 0;
+}
+#endif
+
+// XXXldb |args| has the wrong const-ness
+NS_IMETHODIMP
+nsProcess::Run(PRBool blocking, const char **args, PRUint32 count, PRUint32 *pid)
+{
+ nsresult rv = NS_OK;
+
+ // make sure that when we allocate we have 1 greater than the
+ // count since we need to null terminate the list for the argv to
+ // pass into PR_CreateProcess
+ char **my_argv = NULL;
+#ifdef VBOX
+ my_argv = (char **)nsMemory::Alloc(sizeof(char *) * (count + 2) );
+#else
+ my_argv = (char **)malloc(sizeof(char *) * (count + 2) );
+#endif
+ if (!my_argv) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ // copy the args
+ PRUint32 i;
+ for (i=0; i < count; i++) {
+ my_argv[i+1] = NS_CONST_CAST(char*, args[i]);
+ }
+ // we need to set argv[0] to the program name.
+ my_argv[0] = mTargetPath.BeginWriting();
+ // null terminate the array
+ my_argv[count+1] = NULL;
+
+ #if defined(XP_WIN)
+ STARTUPINFO startupInfo;
+ PROCESS_INFORMATION procInfo;
+ BOOL retVal;
+ char *cmdLine;
+
+ if (assembleCmdLine(my_argv, &cmdLine) == -1) {
+ nsMemory::Free(my_argv);
+ return NS_ERROR_FILE_EXECUTION_FAILED;
+ }
+
+ ZeroMemory(&startupInfo, sizeof(startupInfo));
+ startupInfo.cb = sizeof(startupInfo);
+
+ retVal = CreateProcess(NULL,
+ // NS_CONST_CAST(char*, mTargetPath.get()),
+ cmdLine,
+ NULL, /* security attributes for the new
+ * process */
+ NULL, /* security attributes for the primary
+ * thread in the new process */
+ FALSE, /* inherit handles */
+ 0, /* creation flags */
+ NULL, /* env */
+ NULL, /* current drive and directory */
+ &startupInfo,
+ &procInfo
+ );
+ PR_FREEIF( cmdLine );
+ if (blocking) {
+
+ // if success, wait for process termination. the early returns and such
+ // are a bit ugly but preserving the logic of the nspr code I copied to
+ // minimize our risk abit.
+
+ if ( retVal == TRUE ) {
+ DWORD dwRetVal;
+ unsigned long exitCode;
+
+ dwRetVal = WaitForSingleObject(procInfo.hProcess, INFINITE);
+ if (dwRetVal == WAIT_FAILED) {
+ nsMemory::Free(my_argv);
+ return PR_FAILURE;
+ }
+ if (GetExitCodeProcess(procInfo.hProcess, &exitCode) == FALSE) {
+ mExitValue = exitCode;
+ nsMemory::Free(my_argv);
+ return PR_FAILURE;
+ }
+ mExitValue = exitCode;
+ CloseHandle(procInfo.hProcess);
+ }
+ else
+ rv = PR_FAILURE;
+ }
+ else {
+
+ // map return value into success code
+
+ if ( retVal == TRUE )
+ rv = PR_SUCCESS;
+ else
+ rv = PR_FAILURE;
+ }
+
+#else
+ if ( blocking ) {
+ mProcess = PR_CreateProcess(mTargetPath.get(), my_argv, NULL, NULL);
+ if (mProcess)
+ rv = PR_WaitProcess(mProcess, &mExitValue);
+ }
+ else {
+ rv = PR_CreateProcessDetached(mTargetPath.get(), my_argv, NULL, NULL);
+ }
+#endif
+
+ // free up our argv
+ nsMemory::Free(my_argv);
+
+ if (rv != PR_SUCCESS)
+ return NS_ERROR_FILE_EXECUTION_FAILED;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsProcess::InitWithPid(PRUint32 pid)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsProcess::GetLocation(nsIFile** aLocation)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsProcess::GetPid(PRUint32 *aPid)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsProcess::GetProcessName(char** aProcessName)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsProcess::GetProcessSignature(PRUint32 *aProcessSignature)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsProcess::Kill()
+{
+ nsresult rv = NS_OK;
+ if (mProcess)
+ rv = PR_KillProcess(mProcess);
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsProcess::GetExitValue(PRInt32 *aExitValue)
+{
+ *aExitValue = mExitValue;
+
+ return NS_OK;
+}
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsProcessMac.cpp b/src/libs/xpcom18a4/xpcom/threads/nsProcessMac.cpp
new file mode 100644
index 00000000..d6411f47
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsProcessMac.cpp
@@ -0,0 +1,188 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Don Bragg <dbragg@netscape.com>
+ * Samir Gehani <sgehani@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*****************************************************************************
+ *
+ * nsProcess is used to execute new processes and specify if you want to
+ * wait (blocking) or continue (non-blocking).
+ *
+ *****************************************************************************
+ */
+
+#include "nsCOMPtr.h"
+#include "nsMemory.h"
+
+#include "nsProcess.h"
+
+#include "prtypes.h"
+#include "prio.h"
+#include "prenv.h"
+#include "nsCRT.h"
+#include "prthread.h"
+
+#include <stdlib.h>
+#include <Processes.h>
+
+#include "nsILocalFileMac.h"
+
+//-------------------------------------------------------------------//
+// nsIProcess implementation
+//-------------------------------------------------------------------//
+NS_IMPL_ISUPPORTS1(nsProcess, nsIProcess)
+
+//Constructor
+nsProcess::nsProcess()
+:mExitValue(-1),
+ mProcess(nsnull)
+{
+}
+
+NS_IMETHODIMP
+nsProcess::Init(nsIFile* executable)
+{
+ PRBool isFile;
+
+ //First make sure the file exists
+ nsresult rv = executable->IsFile(&isFile);
+ if (NS_FAILED(rv)) return rv;
+
+ if (!isFile)
+ return NS_ERROR_FAILURE;
+
+ mExecutable = executable;
+
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsProcess::Run(PRBool blocking, const char **args, PRUint32 count, PRUint32 *pid)
+{
+ OSErr err = noErr;
+ LaunchParamBlockRec launchPB;
+ FSSpec resolvedSpec;
+ Boolean bDone = false;
+ ProcessInfoRec info;
+
+ nsCOMPtr<nsILocalFileMac> macExecutable = do_QueryInterface(mExecutable);
+ macExecutable->GetFSSpec(&resolvedSpec);
+
+ launchPB.launchAppSpec = &resolvedSpec;
+ launchPB.launchAppParameters = NULL;
+ launchPB.launchBlockID = extendedBlock;
+ launchPB.launchEPBLength = extendedBlockLen;
+ launchPB.launchFileFlags = NULL;
+ launchPB.launchControlFlags = launchContinue + launchNoFileFlags + launchUseMinimum;
+ if (!blocking)
+ launchPB.launchControlFlags += launchDontSwitch;
+
+ err = LaunchApplication(&launchPB);
+ if (err != noErr)
+ return NS_ERROR_FAILURE;
+
+ // NOTE: blocking mode assumes you are running on a thread
+ // other than the UI thread that has teh main event loop
+ if (blocking)
+ {
+ do
+ {
+ info.processInfoLength = sizeof(ProcessInfoRec);
+ info.processName = nil;
+ info.processAppSpec = nil;
+ err = GetProcessInformation(&launchPB.launchProcessSN, &info);
+
+ if (err == noErr)
+ {
+ // still running so sleep some more (200 msecs)
+ PR_Sleep(200);
+ }
+ else
+ {
+ // no longer in process manager's internal list: so assume done
+ bDone = true;
+ }
+ }
+ while (!bDone);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsProcess::InitWithPid(PRUint32 pid)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsProcess::GetLocation(nsIFile** aLocation)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsProcess::GetPid(PRUint32 *aPid)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsProcess::GetProcessName(char** aProcessName)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsProcess::GetProcessSignature(PRUint32 *aProcessSignature)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsProcess::Kill()
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsProcess::GetExitValue(PRInt32 *aExitValue)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsThread.cpp b/src/libs/xpcom18a4/xpcom/threads/nsThread.cpp
new file mode 100644
index 00000000..b4cc15f4
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsThread.cpp
@@ -0,0 +1,457 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsThread.h"
+#include "prmem.h"
+#include "prlog.h"
+#include "nsAutoLock.h"
+
+PRUintn nsThread::kIThreadSelfIndex = 0;
+static nsIThread *gMainThread = 0;
+
+#if defined(PR_LOGGING)
+//
+// Log module for nsIThread logging...
+//
+// To enable logging (see prlog.h for full details):
+//
+// set NSPR_LOG_MODULES=nsIThread:5
+// set NSPR_LOG_FILE=nspr.log
+//
+// this enables PR_LOG_DEBUG level information and places all output in
+// the file nspr.log
+//
+// gSocketLog is defined in nsSocketTransport.cpp
+//
+PRLogModuleInfo* nsIThreadLog = nsnull;
+
+#endif /* PR_LOGGING */
+
+////////////////////////////////////////////////////////////////////////////////
+
+nsThread::nsThread()
+ : mThread(nsnull), mDead(PR_FALSE), mStartLock(nsnull)
+{
+#if defined(PR_LOGGING)
+ //
+ // Initialize the global PRLogModule for nsIThread logging
+ // if necessary...
+ //
+ if (nsIThreadLog == nsnull) {
+ nsIThreadLog = PR_NewLogModule("nsIThread");
+ }
+#endif /* PR_LOGGING */
+
+ // enforce matching of constants to enums in prthread.h
+ NS_ASSERTION(int(nsIThread::PRIORITY_LOW) == int(PR_PRIORITY_LOW) &&
+ int(nsIThread::PRIORITY_NORMAL) == int(PRIORITY_NORMAL) &&
+ int(nsIThread::PRIORITY_HIGH) == int(PRIORITY_HIGH) &&
+ int(nsIThread::PRIORITY_URGENT) == int(PRIORITY_URGENT) &&
+ int(nsIThread::SCOPE_LOCAL) == int(PR_LOCAL_THREAD) &&
+ int(nsIThread::SCOPE_GLOBAL) == int(PR_GLOBAL_THREAD) &&
+ int(nsIThread::STATE_JOINABLE) == int(PR_JOINABLE_THREAD) &&
+ int(nsIThread::STATE_UNJOINABLE) == int(PR_UNJOINABLE_THREAD),
+ "Bad constant in nsIThread!");
+}
+
+nsThread::~nsThread()
+{
+ if (mStartLock)
+ PR_DestroyLock(mStartLock);
+
+ PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
+ ("nsIThread %p destroyed\n", this));
+
+ // This code used to free the nsIThreadLog loginfo stuff
+ // Don't do that; loginfo structures are owned by nspr
+ // and would be freed if we ever called PR_Cleanup()
+ // see bug 142072
+}
+
+void
+nsThread::Main(void* arg)
+{
+ nsThread* self = (nsThread*)arg;
+
+ self->WaitUntilReadyToStartMain();
+
+ nsresult rv = NS_OK;
+ rv = self->RegisterThreadSelf();
+ NS_ASSERTION(rv == NS_OK, "failed to set thread self");
+
+ PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
+ ("nsIThread %p start run %p\n", self, self->mRunnable.get()));
+ rv = self->mRunnable->Run();
+ NS_ASSERTION(NS_SUCCEEDED(rv), "runnable failed");
+
+#ifdef DEBUG
+ // Because a thread can die after gMainThread dies and takes nsIThreadLog with it,
+ // we need to check for it being null so that we don't crash on shutdown.
+ if (nsIThreadLog) {
+ PRThreadState state;
+ rv = self->GetState(&state);
+ PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
+ ("nsIThread %p end run %p\n", self, self->mRunnable.get()));
+ }
+#endif
+
+ // explicitly drop the runnable now in case there are circular references
+ // between it and the thread object
+ self->mRunnable = nsnull;
+}
+
+void
+nsThread::Exit(void* arg)
+{
+ nsThread* self = (nsThread*)arg;
+
+ if (self->mDead) {
+ NS_ERROR("attempt to Exit() thread twice");
+ return;
+ }
+
+ self->mDead = PR_TRUE;
+
+#if defined(PR_LOGGING)
+ if (nsIThreadLog) {
+ PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
+ ("nsIThread %p exited\n", self));
+ }
+#endif
+ NS_RELEASE(self);
+}
+
+NS_METHOD
+nsThread::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
+{
+ nsThread* thread = new nsThread();
+ if (!thread) return NS_ERROR_OUT_OF_MEMORY;
+ nsresult rv = thread->QueryInterface(aIID, aResult);
+ if (NS_FAILED(rv)) delete thread;
+ return rv;
+}
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(nsThread, nsIThread)
+
+NS_IMETHODIMP
+nsThread::Join()
+{
+ // don't check for mDead here because nspr calls Exit (cleaning up
+ // thread-local storage) before they let us join with the thread
+
+ PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
+ ("nsIThread %p start join\n", this));
+ if (!mThread)
+ return NS_ERROR_NOT_INITIALIZED;
+ PRStatus status = PR_JoinThread(mThread);
+ // XXX can't use NS_RELEASE here because the macro wants to set
+ // this to null (bad c++)
+ PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
+ ("nsIThread %p end join\n", this));
+ if (status == PR_SUCCESS) {
+ NS_RELEASE_THIS(); // most likely the final release of this thread
+ return NS_OK;
+ }
+ else
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsThread::GetPriority(PRThreadPriority *result)
+{
+ if (mDead)
+ return NS_ERROR_FAILURE;
+ if (!mThread)
+ return NS_ERROR_NOT_INITIALIZED;
+ *result = PR_GetThreadPriority(mThread);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsThread::SetPriority(PRThreadPriority value)
+{
+ if (mDead)
+ return NS_ERROR_FAILURE;
+ if (!mThread)
+ return NS_ERROR_NOT_INITIALIZED;
+ PR_SetThreadPriority(mThread, value);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsThread::Interrupt()
+{
+ if (mDead)
+ return NS_ERROR_FAILURE;
+ if (!mThread)
+ return NS_ERROR_NOT_INITIALIZED;
+ PRStatus status = PR_Interrupt(mThread);
+ return status == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsThread::GetScope(PRThreadScope *result)
+{
+ if (mDead)
+ return NS_ERROR_FAILURE;
+ if (!mThread)
+ return NS_ERROR_NOT_INITIALIZED;
+ *result = PR_GetThreadScope(mThread);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsThread::GetState(PRThreadState *result)
+{
+ if (mDead)
+ return NS_ERROR_FAILURE;
+ if (!mThread)
+ return NS_ERROR_NOT_INITIALIZED;
+ *result = PR_GetThreadState(mThread);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsThread::GetPRThread(PRThread* *result)
+{
+ if (mDead) {
+ *result = nsnull;
+ return NS_ERROR_FAILURE;
+ }
+ *result = mThread;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsThread::Init(nsIRunnable* runnable,
+ PRUint32 stackSize,
+ PRThreadPriority priority,
+ PRThreadScope scope,
+ PRThreadState state)
+{
+ NS_ENSURE_ARG_POINTER(runnable);
+ mRunnable = runnable;
+
+ NS_ADDREF_THIS(); // released in nsThread::Exit
+ if (state == PR_JOINABLE_THREAD)
+ NS_ADDREF_THIS(); // released in nsThread::Join
+ mStartLock = PR_NewLock();
+ if (mStartLock == nsnull)
+ return NS_ERROR_OUT_OF_MEMORY;
+ PR_Lock(mStartLock);
+ mThread = PR_CreateThread(PR_USER_THREAD, Main, this,
+ priority, scope, state, stackSize);
+ PR_Unlock(mStartLock);
+ PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
+ ("nsIThread %p created\n", this));
+
+ if (mThread == nsnull)
+ return NS_ERROR_OUT_OF_MEMORY;
+ return NS_OK;
+}
+
+/* readonly attribute nsIThread currentThread; */
+NS_IMETHODIMP
+nsThread::GetCurrentThread(nsIThread * *aCurrentThread)
+{
+ return GetIThread(PR_GetCurrentThread(), aCurrentThread);
+}
+
+/* void sleep (in PRUint32 msec); */
+NS_IMETHODIMP
+nsThread::Sleep(PRUint32 msec)
+{
+ if (PR_GetCurrentThread() != mThread)
+ return NS_ERROR_FAILURE;
+
+ if (PR_Sleep(PR_MillisecondsToInterval(msec)) != PR_SUCCESS)
+ return NS_ERROR_FAILURE;
+
+ return NS_OK;
+}
+
+NS_COM nsresult
+NS_NewThread(nsIThread* *result,
+ nsIRunnable* runnable,
+ PRUint32 stackSize,
+ PRThreadState state,
+ PRThreadPriority priority,
+ PRThreadScope scope)
+{
+ nsresult rv;
+ nsThread* thread = new nsThread();
+ if (thread == nsnull)
+ return NS_ERROR_OUT_OF_MEMORY;
+ NS_ADDREF(thread);
+
+ rv = thread->Init(runnable, stackSize, priority, scope, state);
+ if (NS_FAILED(rv)) {
+ NS_RELEASE(thread);
+ return rv;
+ }
+
+ *result = thread;
+ return NS_OK;
+}
+
+NS_COM nsresult
+NS_NewThread(nsIThread* *result,
+ PRUint32 stackSize,
+ PRThreadState state,
+ PRThreadPriority priority,
+ PRThreadScope scope)
+{
+ nsThread* thread = new nsThread();
+ if (thread == nsnull)
+ return NS_ERROR_OUT_OF_MEMORY;
+ NS_ADDREF(thread);
+ *result = thread;
+ return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+nsresult
+nsThread::RegisterThreadSelf()
+{
+ PRStatus status;
+
+ if (kIThreadSelfIndex == 0) {
+ status = PR_NewThreadPrivateIndex(&kIThreadSelfIndex, Exit);
+ if (status != PR_SUCCESS) return NS_ERROR_FAILURE;
+ }
+
+ status = PR_SetThreadPrivate(kIThreadSelfIndex, this);
+ if (status != PR_SUCCESS) return NS_ERROR_FAILURE;
+
+ return NS_OK;
+}
+
+void
+nsThread::WaitUntilReadyToStartMain()
+{
+ PR_Lock(mStartLock);
+ PR_Unlock(mStartLock);
+ PR_DestroyLock(mStartLock);
+ mStartLock = nsnull;
+}
+
+NS_COM nsresult
+nsIThread::GetCurrent(nsIThread* *result)
+{
+ return GetIThread(PR_GetCurrentThread(), result);
+}
+
+NS_COM nsresult
+nsIThread::GetIThread(PRThread* prthread, nsIThread* *result)
+{
+ PRStatus status;
+ nsThread* thread;
+
+ if (nsThread::kIThreadSelfIndex == 0) {
+ status = PR_NewThreadPrivateIndex(&nsThread::kIThreadSelfIndex, nsThread::Exit);
+ if (status != PR_SUCCESS) return NS_ERROR_FAILURE;
+ }
+
+ thread = (nsThread*)PR_GetThreadPrivate(nsThread::kIThreadSelfIndex);
+ if (thread == nsnull) {
+ // if the current thread doesn't have an nsIThread associated
+ // with it, make one
+ thread = new nsThread();
+ if (thread == nsnull)
+ return NS_ERROR_OUT_OF_MEMORY;
+ NS_ADDREF(thread); // released by Exit
+ thread->SetPRThread(prthread);
+ nsresult rv = thread->RegisterThreadSelf();
+ if (NS_FAILED(rv)) return rv;
+ }
+ NS_ADDREF(thread);
+ *result = thread;
+ return NS_OK;
+}
+
+NS_COM nsresult
+nsIThread::SetMainThread()
+{
+ // strictly speaking, it could be set twice. but practically speaking,
+ // it's almost certainly an error if it is
+ if (gMainThread != 0) {
+ NS_ERROR("Setting main thread twice?");
+ return NS_ERROR_FAILURE;
+ }
+ return GetCurrent(&gMainThread);
+}
+
+NS_COM nsresult
+nsIThread::GetMainThread(nsIThread **result)
+{
+ NS_ASSERTION(result, "bad result pointer");
+ if (gMainThread == 0)
+ return NS_ERROR_FAILURE;
+ *result = gMainThread;
+ NS_ADDREF(gMainThread);
+ return NS_OK;
+}
+
+NS_COM PRBool
+nsIThread::IsMainThread()
+{
+ if (gMainThread == 0)
+ return PR_TRUE;
+
+ PRThread *theMainThread;
+ gMainThread->GetPRThread(&theMainThread);
+ return theMainThread == PR_GetCurrentThread();
+}
+
+void
+nsThread::Shutdown()
+{
+ if (gMainThread) {
+ // XXX nspr doesn't seem to be calling the main thread's destructor
+ // callback, so let's help it out:
+ nsThread::Exit(NS_STATIC_CAST(nsThread*, gMainThread));
+ nsrefcnt cnt;
+ NS_RELEASE2(gMainThread, cnt);
+ NS_WARN_IF_FALSE(cnt == 0, "Main thread being held past XPCOM shutdown.");
+ gMainThread = nsnull;
+
+ kIThreadSelfIndex = 0;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsThread.h b/src/libs/xpcom18a4/xpcom/threads/nsThread.h
new file mode 100644
index 00000000..e75086a7
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsThread.h
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK *****
+ * This Original Code has been modified by IBM Corporation.
+ * Modifications made by IBM described herein are
+ * Copyright (c) International Business Machines
+ * Corporation, 2000
+ *
+ * Modifications to Mozilla code or documentation
+ * identified per MPL Section 3.3
+ *
+ * Date Modified by Description of modification
+ * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2
+ */
+
+#ifndef nsThread_h__
+#define nsThread_h__
+
+#include "nsIRunnable.h"
+#include "nsIThread.h"
+#include "nsCOMPtr.h"
+
+class nsThread : public nsIThread
+{
+public:
+ NS_DECL_ISUPPORTS
+
+ // nsIThread methods:
+ NS_DECL_NSITHREAD
+
+ // nsThread methods:
+ nsThread();
+
+ nsresult RegisterThreadSelf();
+ void SetPRThread(PRThread* thread) { mThread = thread; }
+ void WaitUntilReadyToStartMain();
+
+ static void PR_CALLBACK Main(void* arg);
+ static void PR_CALLBACK Exit(void* arg);
+ static void PR_CALLBACK Shutdown();
+
+ static PRUintn kIThreadSelfIndex;
+
+ static NS_METHOD
+ Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr);
+
+private:
+ ~nsThread();
+
+protected:
+ PRThread* mThread;
+ nsCOMPtr<nsIRunnable> mRunnable;
+ PRBool mDead;
+ PRLock* mStartLock;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+#endif // nsThread_h__
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.cpp b/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.cpp
new file mode 100644
index 00000000..dc19452f
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.cpp
@@ -0,0 +1,642 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Stuart Parmenter <pavlov@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsTimerImpl.h"
+#include "TimerThread.h"
+#include "nsAutoLock.h"
+
+#include "nsVoidArray.h"
+
+#include "nsIEventQueue.h"
+
+#include "prmem.h"
+
+static PRInt32 gGenerator = 0;
+static TimerThread* gThread = nsnull;
+static PRBool gFireOnIdle = PR_FALSE;
+static nsTimerManager* gManager = nsnull;
+
+#ifdef DEBUG_TIMERS
+#include <math.h>
+
+double nsTimerImpl::sDeltaSumSquared = 0;
+double nsTimerImpl::sDeltaSum = 0;
+double nsTimerImpl::sDeltaNum = 0;
+
+static void
+myNS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues,
+ double *meanResult, double *stdDevResult)
+{
+ double mean = 0.0, var = 0.0, stdDev = 0.0;
+ if (n > 0.0 && sumOfValues >= 0) {
+ mean = sumOfValues / n;
+ double temp = (n * sumOfSquaredValues) - (sumOfValues * sumOfValues);
+ if (temp < 0.0 || n <= 1)
+ var = 0.0;
+ else
+ var = temp / (n * (n - 1));
+ // for some reason, Windows says sqrt(0.0) is "-1.#J" (?!) so do this:
+ stdDev = var != 0.0 ? sqrt(var) : 0.0;
+ }
+ *meanResult = mean;
+ *stdDevResult = stdDev;
+}
+#endif
+
+NS_IMPL_THREADSAFE_QUERY_INTERFACE2(nsTimerImpl, nsITimer, nsITimerInternal)
+NS_IMPL_THREADSAFE_ADDREF(nsTimerImpl)
+
+NS_IMETHODIMP_(nsrefcnt) nsTimerImpl::Release(void)
+{
+ nsrefcnt count;
+
+ NS_PRECONDITION(0 != mRefCnt, "dup release");
+ count = PR_AtomicDecrement((PRInt32 *)&mRefCnt);
+ NS_LOG_RELEASE(this, count, "nsTimerImpl");
+ if (count == 0) {
+ mRefCnt = 1; /* stabilize */
+
+ /* enable this to find non-threadsafe destructors: */
+ /* NS_ASSERT_OWNINGTHREAD(nsTimerImpl); */
+ NS_DELETEXPCOM(this);
+ return 0;
+ }
+
+ // If only one reference remains, and mArmed is set, then the ref must be
+ // from the TimerThread::mTimers array, so we Cancel this timer to remove
+ // the mTimers element, and return 0 if Cancel in fact disarmed the timer.
+ //
+ // We use an inlined version of nsTimerImpl::Cancel here to check for the
+ // NS_ERROR_NOT_AVAILABLE code returned by gThread->RemoveTimer when this
+ // timer is not found in the mTimers array -- i.e., when the timer was not
+ // in fact armed once we acquired TimerThread::mLock, in spite of mArmed
+ // being true here. That can happen if the armed timer is being fired by
+ // TimerThread::Run as we race and test mArmed just before it is cleared by
+ // the timer thread. If the RemoveTimer call below doesn't find this timer
+ // in the mTimers array, then the last ref to this timer is held manually
+ // and temporarily by the TimerThread, so we should fall through to the
+ // final return and return 1, not 0.
+ //
+ // The original version of this thread-based timer code kept weak refs from
+ // TimerThread::mTimers, removing this timer's weak ref in the destructor,
+ // but that leads to double-destructions in the race described above, and
+ // adding mArmed doesn't help, because destructors can't be deferred, once
+ // begun. But by combining reference-counting and a specialized Release
+ // method with "is this timer still in the mTimers array once we acquire
+ // the TimerThread's lock" testing, we defer destruction until we're sure
+ // that only one thread has its hot little hands on this timer.
+ //
+ // Note that both approaches preclude a timer creator, and everyone else
+ // except the TimerThread who might have a strong ref, from dropping all
+ // their strong refs without implicitly canceling the timer. Timers need
+ // non-mTimers-element strong refs to stay alive.
+
+ if (count == 1 && mArmed) {
+ mCanceled = PR_TRUE;
+
+ if (NS_SUCCEEDED(gThread->RemoveTimer(this)))
+ return 0;
+ }
+
+ return count;
+}
+
+nsTimerImpl::nsTimerImpl() :
+ mClosure(nsnull),
+ mCallbackType(CALLBACK_TYPE_UNKNOWN),
+ mIdle(PR_TRUE),
+ mFiring(PR_FALSE),
+ mArmed(PR_FALSE),
+ mCanceled(PR_FALSE),
+ mGeneration(0),
+ mDelay(0),
+ mTimeout(0)
+{
+ // XXXbsmedberg: shouldn't this be in Init()?
+ nsIThread::GetCurrent(getter_AddRefs(mCallingThread));
+
+ mCallback.c = nsnull;
+
+#ifdef DEBUG_TIMERS
+ mStart = 0;
+ mStart2 = 0;
+#endif
+}
+
+nsTimerImpl::~nsTimerImpl()
+{
+ ReleaseCallback();
+}
+
+//static
+nsresult
+nsTimerImpl::Startup()
+{
+ nsresult rv;
+
+ gThread = new TimerThread();
+ if (!gThread) return NS_ERROR_OUT_OF_MEMORY;
+
+ NS_ADDREF(gThread);
+ rv = gThread->InitLocks();
+
+ if (NS_FAILED(rv)) {
+ NS_RELEASE(gThread);
+ }
+
+ return rv;
+}
+
+void nsTimerImpl::Shutdown()
+{
+#ifdef DEBUG_TIMERS
+ if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
+ double mean = 0, stddev = 0;
+ myNS_MeanAndStdDev(sDeltaNum, sDeltaSum, sDeltaSumSquared, &mean, &stddev);
+
+ PR_LOG(gTimerLog, PR_LOG_DEBUG, ("sDeltaNum = %f, sDeltaSum = %f, sDeltaSumSquared = %f\n", sDeltaNum, sDeltaSum, sDeltaSumSquared));
+ PR_LOG(gTimerLog, PR_LOG_DEBUG, ("mean: %fms, stddev: %fms\n", mean, stddev));
+ }
+#endif
+
+ if (!gThread)
+ return;
+
+ gThread->Shutdown();
+ NS_RELEASE(gThread);
+
+ gFireOnIdle = PR_FALSE;
+}
+
+
+nsresult nsTimerImpl::InitCommon(PRUint32 aType, PRUint32 aDelay)
+{
+ nsresult rv;
+
+ NS_ENSURE_TRUE(gThread, NS_ERROR_NOT_INITIALIZED);
+
+ rv = gThread->Init();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ /**
+ * In case of re-Init, both with and without a preceding Cancel, clear the
+ * mCanceled flag and assign a new mGeneration. But first, remove any armed
+ * timer from the timer thread's list.
+ *
+ * If we are racing with the timer thread to remove this timer and we lose,
+ * the RemoveTimer call made here will fail to find this timer in the timer
+ * thread's list, and will return false harmlessly. We test mArmed here to
+ * avoid the small overhead in RemoveTimer of locking the timer thread and
+ * checking its list for this timer. It's safe to test mArmed even though
+ * it might be cleared on another thread in the next cycle (or even already
+ * be cleared by another CPU whose store hasn't reached our CPU's cache),
+ * because RemoveTimer is idempotent.
+ */
+ if (mArmed)
+ gThread->RemoveTimer(this);
+ mCanceled = PR_FALSE;
+ mGeneration = PR_AtomicIncrement(&gGenerator);
+
+ mType = (PRUint8)aType;
+ SetDelayInternal(aDelay);
+
+ return gThread->AddTimer(this);
+}
+
+NS_IMETHODIMP nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc,
+ void *aClosure,
+ PRUint32 aDelay,
+ PRUint32 aType)
+{
+ ReleaseCallback();
+ mCallbackType = CALLBACK_TYPE_FUNC;
+ mCallback.c = aFunc;
+ mClosure = aClosure;
+
+ return InitCommon(aType, aDelay);
+}
+
+NS_IMETHODIMP nsTimerImpl::InitWithCallback(nsITimerCallback *aCallback,
+ PRUint32 aDelay,
+ PRUint32 aType)
+{
+ ReleaseCallback();
+ mCallbackType = CALLBACK_TYPE_INTERFACE;
+ mCallback.i = aCallback;
+ NS_ADDREF(mCallback.i);
+
+ return InitCommon(aType, aDelay);
+}
+
+NS_IMETHODIMP nsTimerImpl::Init(nsIObserver *aObserver,
+ PRUint32 aDelay,
+ PRUint32 aType)
+{
+ ReleaseCallback();
+ mCallbackType = CALLBACK_TYPE_OBSERVER;
+ mCallback.o = aObserver;
+ NS_ADDREF(mCallback.o);
+
+ return InitCommon(aType, aDelay);
+}
+
+NS_IMETHODIMP nsTimerImpl::Cancel()
+{
+ mCanceled = PR_TRUE;
+
+ if (gThread)
+ gThread->RemoveTimer(this);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsTimerImpl::SetDelay(PRUint32 aDelay)
+{
+ // If we're already repeating precisely, update mTimeout now so that the
+ // new delay takes effect in the future.
+ if (mTimeout != 0 && mType == TYPE_REPEATING_PRECISE)
+ mTimeout = PR_IntervalNow();
+
+ SetDelayInternal(aDelay);
+
+ if (!mFiring && gThread)
+ gThread->TimerDelayChanged(this);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsTimerImpl::GetDelay(PRUint32* aDelay)
+{
+ *aDelay = mDelay;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsTimerImpl::SetType(PRUint32 aType)
+{
+ mType = (PRUint8)aType;
+ // XXX if this is called, we should change the actual type.. this could effect
+ // repeating timers. we need to ensure in Fire() that if mType has changed
+ // during the callback that we don't end up with the timer in the queue twice.
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsTimerImpl::GetType(PRUint32* aType)
+{
+ *aType = mType;
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP nsTimerImpl::GetClosure(void** aClosure)
+{
+ *aClosure = mClosure;
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP nsTimerImpl::GetIdle(PRBool *aIdle)
+{
+ *aIdle = mIdle;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsTimerImpl::SetIdle(PRBool aIdle)
+{
+ mIdle = aIdle;
+ return NS_OK;
+}
+
+void nsTimerImpl::Fire()
+{
+ if (mCanceled)
+ return;
+
+ PRIntervalTime now = PR_IntervalNow();
+#ifdef DEBUG_TIMERS
+ if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
+ PRIntervalTime a = now - mStart; // actual delay in intervals
+ PRUint32 b = PR_MillisecondsToInterval(mDelay); // expected delay in intervals
+ PRUint32 d = PR_IntervalToMilliseconds((a > b) ? a - b : b - a); // delta in ms
+ sDeltaSum += d;
+ sDeltaSumSquared += double(d) * double(d);
+ sDeltaNum++;
+
+ PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] expected delay time %4dms\n", this, mDelay));
+ PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] actual delay time %4dms\n", this, PR_IntervalToMilliseconds(a)));
+ PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] (mType is %d) -------\n", this, mType));
+ PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] delta %4dms\n", this, (a > b) ? (PRInt32)d : -(PRInt32)d));
+
+ mStart = mStart2;
+ mStart2 = 0;
+ }
+#endif
+
+ PRIntervalTime timeout = mTimeout;
+ if (mType == TYPE_REPEATING_PRECISE) {
+ // Precise repeating timers advance mTimeout by mDelay without fail before
+ // calling Fire().
+ timeout -= PR_MillisecondsToInterval(mDelay);
+ }
+ gThread->UpdateFilter(mDelay, timeout, now);
+
+ mFiring = PR_TRUE;
+
+ switch (mCallbackType) {
+ case CALLBACK_TYPE_FUNC:
+ mCallback.c(this, mClosure);
+ break;
+ case CALLBACK_TYPE_INTERFACE:
+ mCallback.i->Notify(this);
+ break;
+ case CALLBACK_TYPE_OBSERVER:
+ mCallback.o->Observe(NS_STATIC_CAST(nsITimer*,this),
+ NS_TIMER_CALLBACK_TOPIC,
+ nsnull);
+ break;
+ default:;
+ }
+
+ mFiring = PR_FALSE;
+
+#ifdef DEBUG_TIMERS
+ if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
+ PR_LOG(gTimerLog, PR_LOG_DEBUG,
+ ("[this=%p] Took %dms to fire timer callback\n",
+ this, PR_IntervalToMilliseconds(PR_IntervalNow() - now)));
+ }
+#endif
+
+ if (mType == TYPE_REPEATING_SLACK) {
+ SetDelayInternal(mDelay); // force mTimeout to be recomputed.
+ if (gThread)
+ gThread->AddTimer(this);
+ }
+}
+
+
+struct TimerEventType : public PLEvent {
+ PRInt32 mGeneration;
+#ifdef DEBUG_TIMERS
+ PRIntervalTime mInitTime;
+#endif
+};
+
+
+void* handleTimerEvent(TimerEventType* event)
+{
+ nsTimerImpl* timer = NS_STATIC_CAST(nsTimerImpl*, event->owner);
+ if (event->mGeneration != timer->GetGeneration())
+ return nsnull;
+
+#ifdef DEBUG_TIMERS
+ if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
+ PRIntervalTime now = PR_IntervalNow();
+ PR_LOG(gTimerLog, PR_LOG_DEBUG,
+ ("[this=%p] time between PostTimerEvent() and Fire(): %dms\n",
+ event->owner, PR_IntervalToMilliseconds(now - event->mInitTime)));
+ }
+#endif
+
+ if (gFireOnIdle) {
+ PRBool idle = PR_FALSE;
+ timer->GetIdle(&idle);
+ if (idle) {
+ NS_ASSERTION(gManager, "Global Thread Manager is null!");
+ if (gManager)
+ gManager->AddIdleTimer(timer);
+ return nsnull;
+ }
+ }
+
+ timer->Fire();
+
+ return nsnull;
+}
+
+void destroyTimerEvent(TimerEventType* event)
+{
+ nsTimerImpl *timer = NS_STATIC_CAST(nsTimerImpl*, event->owner);
+ NS_RELEASE(timer);
+ PR_DELETE(event);
+}
+
+
+void nsTimerImpl::PostTimerEvent()
+{
+ // XXX we may want to reuse the PLEvent in the case of repeating timers.
+ TimerEventType* event;
+
+ // construct
+ event = PR_NEW(TimerEventType);
+ if (!event)
+ return;
+
+ // initialize
+ PL_InitEvent((PLEvent*)event, this,
+ (PLHandleEventProc)handleTimerEvent,
+ (PLDestroyEventProc)destroyTimerEvent);
+
+ // Since TimerThread addref'd 'this' for us, we don't need to addref here.
+ // We will release in destroyMyEvent. We do need to copy the generation
+ // number from this timer into the event, so we can avoid firing a timer
+ // that was re-initialized after being canceled.
+ event->mGeneration = mGeneration;
+
+#ifdef DEBUG_TIMERS
+ if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
+ event->mInitTime = PR_IntervalNow();
+ }
+#endif
+
+ // If this is a repeating precise timer, we need to calculate the time for
+ // the next timer to fire before we make the callback.
+ if (mType == TYPE_REPEATING_PRECISE) {
+ SetDelayInternal(mDelay);
+ if (gThread)
+ gThread->AddTimer(this);
+ }
+
+ PRThread *thread;
+ nsresult rv = mCallingThread->GetPRThread(&thread);
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Dropping timer event because thread is dead");
+ return;
+ }
+
+ nsCOMPtr<nsIEventQueue> queue;
+ if (gThread)
+ gThread->mEventQueueService->GetThreadEventQueue(thread, getter_AddRefs(queue));
+ if (queue)
+ queue->PostEvent(event);
+}
+
+void nsTimerImpl::SetDelayInternal(PRUint32 aDelay)
+{
+ PRIntervalTime delayInterval = PR_MillisecondsToInterval(aDelay);
+ if (delayInterval > DELAY_INTERVAL_MAX) {
+ delayInterval = DELAY_INTERVAL_MAX;
+ aDelay = PR_IntervalToMilliseconds(delayInterval);
+ }
+
+ mDelay = aDelay;
+
+ PRIntervalTime now = PR_IntervalNow();
+ if (mTimeout == 0 || mType != TYPE_REPEATING_PRECISE)
+ mTimeout = now;
+
+ mTimeout += delayInterval;
+
+#ifdef DEBUG_TIMERS
+ if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
+ if (mStart == 0)
+ mStart = now;
+ else
+ mStart2 = now;
+ }
+#endif
+}
+
+/**
+ * Timer Manager code
+ */
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(nsTimerManager, nsITimerManager)
+
+nsTimerManager::nsTimerManager()
+{
+ mLock = PR_NewLock();
+ gManager = this;
+}
+
+nsTimerManager::~nsTimerManager()
+{
+ gManager = nsnull;
+ PR_DestroyLock(mLock);
+
+ nsTimerImpl *theTimer;
+ PRInt32 count = mIdleTimers.Count();
+
+ for (PRInt32 i = 0; i < count; i++) {
+ theTimer = NS_STATIC_CAST(nsTimerImpl*, mIdleTimers[i]);
+ NS_IF_RELEASE(theTimer);
+ }
+}
+
+NS_IMETHODIMP nsTimerManager::SetUseIdleTimers(PRBool aUseIdleTimers)
+{
+ if (aUseIdleTimers == PR_FALSE && gFireOnIdle == PR_TRUE)
+ return NS_ERROR_FAILURE;
+
+ gFireOnIdle = aUseIdleTimers;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsTimerManager::GetUseIdleTimers(PRBool *aUseIdleTimers)
+{
+ *aUseIdleTimers = gFireOnIdle;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsTimerManager::HasIdleTimers(PRBool *aHasTimers)
+{
+ nsAutoLock lock (mLock);
+ PRUint32 count = mIdleTimers.Count();
+ *aHasTimers = (count != 0);
+ return NS_OK;
+}
+
+nsresult nsTimerManager::AddIdleTimer(nsITimer* timer)
+{
+ if (!timer)
+ return NS_ERROR_FAILURE;
+ nsAutoLock lock(mLock);
+ mIdleTimers.AppendElement(timer);
+ NS_ADDREF(timer);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsTimerManager::FireNextIdleTimer()
+{
+ if (!gFireOnIdle || !nsIThread::IsMainThread()) {
+ return NS_OK;
+ }
+
+ nsTimerImpl *theTimer = nsnull;
+
+ {
+ nsAutoLock lock (mLock);
+ PRUint32 count = mIdleTimers.Count();
+
+ if (count == 0)
+ return NS_OK;
+
+ theTimer = NS_STATIC_CAST(nsTimerImpl*, mIdleTimers[0]);
+ mIdleTimers.RemoveElement(theTimer);
+ }
+
+ theTimer->Fire();
+
+ NS_RELEASE(theTimer);
+
+ return NS_OK;
+}
+
+
+// NOT FOR PUBLIC CONSUMPTION!
+nsresult
+NS_NewTimer(nsITimer* *aResult, nsTimerCallbackFunc aCallback, void *aClosure,
+ PRUint32 aDelay, PRUint32 aType)
+{
+ nsTimerImpl* timer = new nsTimerImpl();
+ if (timer == nsnull)
+ return NS_ERROR_OUT_OF_MEMORY;
+ NS_ADDREF(timer);
+
+ nsresult rv = timer->InitWithFuncCallback(aCallback, aClosure,
+ aDelay, aType);
+ if (NS_FAILED(rv)) {
+ NS_RELEASE(timer);
+ return rv;
+ }
+
+ *aResult = timer;
+ return NS_OK;
+}
diff --git a/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.h b/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.h
new file mode 100644
index 00000000..98596f4e
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.h
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Stuart Parmenter <pavlov@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsTimerImpl_h___
+#define nsTimerImpl_h___
+
+//#define FORCE_PR_LOG /* Allow logging in the release build */
+
+#include "nsITimer.h"
+#include "nsVoidArray.h"
+#include "nsIThread.h"
+#include "nsITimerInternal.h"
+#include "nsIObserver.h"
+
+#include "nsCOMPtr.h"
+
+#include "prlog.h"
+
+#if defined(PR_LOGGING)
+static PRLogModuleInfo *gTimerLog = PR_NewLogModule("nsTimerImpl");
+#define DEBUG_TIMERS 1
+#else
+#undef DEBUG_TIMERS
+#endif
+
+#define NS_TIMER_CLASSNAME "Timer"
+#define NS_TIMER_CID \
+{ /* 5ff24248-1dd2-11b2-8427-fbab44f29bc8 */ \
+ 0x5ff24248, \
+ 0x1dd2, \
+ 0x11b2, \
+ {0x84, 0x27, 0xfb, 0xab, 0x44, 0xf2, 0x9b, 0xc8} \
+}
+
+enum {
+ CALLBACK_TYPE_UNKNOWN = 0,
+ CALLBACK_TYPE_INTERFACE = 1,
+ CALLBACK_TYPE_FUNC = 2,
+ CALLBACK_TYPE_OBSERVER = 3
+};
+
+// Two timer deadlines must differ by less than half the PRIntervalTime domain.
+#define DELAY_INTERVAL_LIMIT PR_BIT(8 * sizeof(PRIntervalTime) - 1)
+
+// Maximum possible delay (XXX rework to use ms rather than interval ticks).
+#define DELAY_INTERVAL_MAX (DELAY_INTERVAL_LIMIT - 1)
+
+// Is interval-time t less than u, even if t has wrapped PRIntervalTime?
+#define TIMER_LESS_THAN(t, u) ((t) - (u) > DELAY_INTERVAL_LIMIT)
+
+class nsTimerImpl : public nsITimer, public nsITimerInternal
+{
+public:
+
+ nsTimerImpl();
+
+ static NS_HIDDEN_(nsresult) Startup();
+ static NS_HIDDEN_(void) Shutdown();
+
+ friend class TimerThread;
+
+ void Fire();
+ void PostTimerEvent();
+ void SetDelayInternal(PRUint32 aDelay);
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSITIMER
+ NS_DECL_NSITIMERINTERNAL
+
+ PRInt32 GetGeneration() { return mGeneration; }
+
+private:
+ ~nsTimerImpl();
+
+ nsresult InitCommon(PRUint32 aType, PRUint32 aDelay);
+
+ void ReleaseCallback()
+ {
+ if (mCallbackType == CALLBACK_TYPE_INTERFACE)
+ NS_RELEASE(mCallback.i);
+ else if (mCallbackType == CALLBACK_TYPE_OBSERVER)
+ NS_RELEASE(mCallback.o);
+ }
+
+ nsCOMPtr<nsIThread> mCallingThread;
+
+ void * mClosure;
+
+ union {
+ nsTimerCallbackFunc c;
+ nsITimerCallback * i;
+ nsIObserver * o;
+ } mCallback;
+
+ // These members are set by Init (called from NS_NewTimer) and never reset.
+ PRUint8 mCallbackType;
+ PRPackedBool mIdle;
+
+ // These members are set by the initiating thread, when the timer's type is
+ // changed and during the period where it fires on that thread.
+ PRUint8 mType;
+ PRPackedBool mFiring;
+
+
+ // Use a PRBool (int) here to isolate loads and stores of these two members
+ // done on various threads under the protection of TimerThread::mLock, from
+ // loads and stores done on the initiating/type-changing/timer-firing thread
+ // to the above PRUint8/PRPackedBool members.
+ PRBool mArmed;
+ PRBool mCanceled;
+
+ // The generation number of this timer, re-generated each time the timer is
+ // initialized so one-shot timers can be canceled and re-initialized by the
+ // arming thread without any bad race conditions.
+ PRInt32 mGeneration;
+
+ PRUint32 mDelay;
+ PRIntervalTime mTimeout;
+
+#ifdef DEBUG_TIMERS
+ PRIntervalTime mStart, mStart2;
+ static double sDeltaSum;
+ static double sDeltaSumSquared;
+ static double sDeltaNum;
+#endif
+
+};
+
+#define NS_TIMERMANAGER_CONTRACTID "@mozilla.org/timer/manager;1"
+#define NS_TIMERMANAGER_CLASSNAME "Timer Manager"
+#define NS_TIMERMANAGER_CID \
+{ /* 4fe206fa-1dd2-11b2-8a0a-88bacbecc7d2 */ \
+ 0x4fe206fa, \
+ 0x1dd2, \
+ 0x11b2, \
+ {0x8a, 0x0a, 0x88, 0xba, 0xcb, 0xec, 0xc7, 0xd2} \
+}
+
+#include "nsITimerManager.h"
+
+class nsTimerManager : nsITimerManager
+{
+public:
+ nsTimerManager();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSITIMERMANAGER
+
+ nsresult AddIdleTimer(nsITimer* timer);
+private:
+ ~nsTimerManager();
+
+ PRLock *mLock;
+ nsVoidArray mIdleTimers;
+};
+
+
+#endif /* nsTimerImpl_h___ */
diff --git a/src/libs/xpcom18a4/xpcom/threads/plevent.c b/src/libs/xpcom18a4/xpcom/threads/plevent.c
new file mode 100644
index 00000000..c5e9040f
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/plevent.c
@@ -0,0 +1,1774 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
+#if defined(XP_OS2)
+#define INCL_DOS
+#define INCL_DOSERRORS
+#define INCL_WIN
+#include <os2.h>
+#define DefWindowProc WinDefWindowProc
+#endif /* XP_OS2 */
+
+#include "nspr.h"
+#include "plevent.h"
+
+#if !defined(WIN32)
+#include <errno.h>
+#include <stddef.h>
+#if !defined(XP_OS2)
+#include <unistd.h>
+#endif /* !XP_OS2 */
+#endif /* !Win32 */
+
+#if defined(XP_UNIX)
+/* for fcntl */
+#include <sys/types.h>
+#include <fcntl.h>
+#endif
+
+#if defined(XP_BEOS)
+#include <kernel/OS.h>
+#endif
+
+#if defined(XP_MACOSX)
+#if defined(MOZ_WIDGET_COCOA)
+#include <CoreFoundation/CoreFoundation.h>
+#define MAC_USE_CFRUNLOOPSOURCE
+#elif defined(TARGET_CARBON)
+/* #include <CarbonEvents.h> */
+/* #define MAC_USE_CARBON_EVENT */
+#include <CoreFoundation/CoreFoundation.h>
+#define MAC_USE_CFRUNLOOPSOURCE
+#endif
+#endif
+
+#include "private/pprthred.h"
+
+#if defined(VMS)
+/*
+** On OpenVMS, XtAppAddInput doesn't want a regular fd, instead it
+** wants an event flag. So, we don't create and use a pipe for
+** notification of when an event queue has something ready, instead
+** we use an event flag. Shouldn't be a problem if we only have
+** a few event queues.
+*/
+#include <lib$routines.h>
+#include <starlet.h>
+#include <stsdef.h>
+#endif /* VMS */
+
+#if defined(_WIN32)
+/* Comment out the following USE_TIMER define to prevent
+ * WIN32 from using a WIN32 native timer for PLEvent notification.
+ * With USE_TIMER defined we will use a timer when pending input
+ * or paint events are starved, otherwise it will use a posted
+ * WM_APP msg for PLEvent notification.
+ */
+#define USE_TIMER
+
+/* Threshold defined in milliseconds for determining when the input
+ * and paint events have been held in the WIN32 msg queue too long
+ */
+#define INPUT_STARVATION_LIMIT 50
+/* The paint starvation limit is set to the smallest value which
+ * does not cause performance degradation while running page load tests
+ */
+#define PAINT_STARVATION_LIMIT 750
+/* The WIN9X paint starvation limit is larger because it was
+ * determined that the following value was required to prevent performance
+ * degradation on page load tests for WIN98/95 only.
+ */
+#define WIN9X_PAINT_STARVATION_LIMIT 3000
+
+#define TIMER_ID 0
+/* If _md_PerformanceSetting <=0 then no event starvation otherwise events will be starved */
+static PRInt32 _md_PerformanceSetting = 0;
+static PRUint32 _md_StarvationDelay = 0;
+static PRUint32 _md_SwitchTime = 0;
+#endif
+
+static PRLogModuleInfo *event_lm = NULL;
+
+/*******************************************************************************
+ * Private Stuff
+ ******************************************************************************/
+
+/*
+** EventQueueType -- Defines notification type for an event queue
+**
+*/
+typedef enum {
+ EventQueueIsNative = 1,
+ EventQueueIsMonitored = 2
+} EventQueueType;
+
+
+struct PLEventQueue {
+ const char* name;
+ PRCList queue;
+ PRMonitor* monitor;
+ PRThread* handlerThread;
+ EventQueueType type;
+ PRPackedBool processingEvents;
+ PRPackedBool notified;
+#if defined(_WIN32)
+ PRPackedBool timerSet;
+#endif
+
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
+#if defined(VMS)
+ int efn;
+#else
+ PRInt32 eventPipe[2];
+#endif
+ PLGetEventIDFunc idFunc;
+ void* idFuncClosure;
+#elif defined(_WIN32) || defined(XP_OS2)
+ HWND eventReceiverWindow;
+ PRBool removeMsg;
+#elif defined(XP_BEOS)
+ port_id eventport;
+#elif defined(XP_MACOSX)
+#if defined(MAC_USE_CFRUNLOOPSOURCE)
+ CFRunLoopSourceRef mRunLoopSource;
+ CFRunLoopRef mMainRunLoop;
+ CFStringRef mRunLoopModeStr; /* vbox */
+#elif defined(MAC_USE_CARBON_EVENT)
+ EventHandlerUPP eventHandlerUPP;
+ EventHandlerRef eventHandlerRef;
+#endif
+#endif
+};
+
+#define PR_EVENT_PTR(_qp) \
+ ((PLEvent*) ((char*) (_qp) - offsetof(PLEvent, link)))
+
+static PRStatus _pl_SetupNativeNotifier(PLEventQueue* self);
+static void _pl_CleanupNativeNotifier(PLEventQueue* self);
+static PRStatus _pl_NativeNotify(PLEventQueue* self);
+static PRStatus _pl_AcknowledgeNativeNotify(PLEventQueue* self);
+static void _md_CreateEventQueue( PLEventQueue *eventQueue );
+static PRInt32 _pl_GetEventCount(PLEventQueue* self);
+
+
+#if defined(_WIN32) || defined(XP_OS2)
+#if defined(XP_OS2)
+ULONG _pr_PostEventMsgId;
+#else
+UINT _pr_PostEventMsgId;
+#endif /* OS2 */
+static char *_pr_eventWindowClass = "XPCOM:EventWindow";
+#endif /* Win32, OS2 */
+
+#if defined(_WIN32)
+
+static LPCTSTR _md_GetEventQueuePropName() {
+ static ATOM atom = 0;
+ if (!atom) {
+ atom = GlobalAddAtom("XPCOM_EventQueue");
+ }
+ return MAKEINTATOM(atom);
+}
+#endif
+
+#if defined(MAC_USE_CARBON_EVENT)
+enum {
+ kEventClassPL = FOUR_CHAR_CODE('PLEC'),
+
+ kEventProcessPLEvents = 1,
+
+ kEventParamPLEventQueue = FOUR_CHAR_CODE('OWNQ')
+};
+
+static pascal Boolean _md_CarbonEventComparator(EventRef inEvent, void *inCompareData);
+#endif
+
+/*******************************************************************************
+ * Event Queue Operations
+ ******************************************************************************/
+
+/*
+** _pl_CreateEventQueue() -- Create the event queue
+**
+**
+*/
+static PLEventQueue * _pl_CreateEventQueue(const char *name,
+ PRThread *handlerThread,
+ EventQueueType qtype)
+{
+ PRStatus err;
+ PLEventQueue* self = NULL;
+ PRMonitor* mon = NULL;
+
+ if (event_lm == NULL)
+ event_lm = PR_NewLogModule("event");
+
+ self = PR_NEWZAP(PLEventQueue);
+ if (self == NULL) return NULL;
+
+ mon = PR_NewNamedMonitor(name);
+ if (mon == NULL) goto error;
+
+ self->name = name;
+ self->monitor = mon;
+ self->handlerThread = handlerThread;
+ self->processingEvents = PR_FALSE;
+ self->type = qtype;
+#if defined(_WIN32)
+ self->timerSet = PR_FALSE;
+#endif
+#if defined(_WIN32) || defined(XP_OS2)
+ self->removeMsg = PR_TRUE;
+#endif
+
+ self->notified = PR_FALSE;
+
+ PR_INIT_CLIST(&self->queue);
+ if ( qtype == EventQueueIsNative ) {
+ err = _pl_SetupNativeNotifier(self);
+ if (err) goto error;
+ _md_CreateEventQueue( self );
+ }
+ return self;
+
+ error:
+ if (mon != NULL)
+ PR_DestroyMonitor(mon);
+ PR_DELETE(self);
+ return NULL;
+}
+
+PR_IMPLEMENT(PLEventQueue*)
+PL_CreateEventQueue(const char* name, PRThread* handlerThread)
+{
+ return( _pl_CreateEventQueue( name, handlerThread, EventQueueIsNative ));
+}
+
+PR_EXTERN(PLEventQueue *)
+PL_CreateNativeEventQueue(const char *name, PRThread *handlerThread)
+{
+ return( _pl_CreateEventQueue( name, handlerThread, EventQueueIsNative ));
+}
+
+PR_EXTERN(PLEventQueue *)
+PL_CreateMonitoredEventQueue(const char *name, PRThread *handlerThread)
+{
+ return( _pl_CreateEventQueue( name, handlerThread, EventQueueIsMonitored ));
+}
+
+PR_IMPLEMENT(PRMonitor*)
+PL_GetEventQueueMonitor(PLEventQueue* self)
+{
+ return self->monitor;
+}
+
+static void PR_CALLBACK
+_pl_destroyEvent(PLEvent* event, void* data, PLEventQueue* queue)
+{
+ PL_DequeueEvent(event, queue);
+ PL_DestroyEvent(event);
+}
+
+PR_IMPLEMENT(void)
+PL_DestroyEventQueue(PLEventQueue* self)
+{
+ PR_EnterMonitor(self->monitor);
+
+ /* destroy undelivered events */
+ PL_MapEvents(self, _pl_destroyEvent, NULL);
+
+ if ( self->type == EventQueueIsNative )
+ _pl_CleanupNativeNotifier(self);
+
+ /* destroying the monitor also destroys the name */
+ PR_ExitMonitor(self->monitor);
+ PR_DestroyMonitor(self->monitor);
+ PR_DELETE(self);
+
+}
+
+PR_IMPLEMENT(PRStatus)
+PL_PostEvent(PLEventQueue* self, PLEvent* event)
+{
+ PRStatus err = PR_SUCCESS;
+ PRMonitor* mon;
+
+ if (self == NULL)
+ return PR_FAILURE;
+
+ mon = self->monitor;
+ PR_EnterMonitor(mon);
+
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
+ if (self->idFunc && event)
+ event->id = self->idFunc(self->idFuncClosure);
+#endif
+
+ /* insert event into thread's event queue: */
+ if (event != NULL) {
+ PR_APPEND_LINK(&event->link, &self->queue);
+ }
+
+ if (self->type == EventQueueIsNative && !self->notified) {
+ err = _pl_NativeNotify(self);
+
+ if (err != PR_SUCCESS)
+ goto error;
+
+ self->notified = PR_TRUE;
+ }
+
+ /*
+ * This may fall on deaf ears if we're really notifying the native
+ * thread, and no one has called PL_WaitForEvent (or PL_EventLoop):
+ */
+ err = PR_Notify(mon);
+
+error:
+ PR_ExitMonitor(mon);
+ return err;
+}
+
+PR_IMPLEMENT(void*)
+PL_PostSynchronousEvent(PLEventQueue* self, PLEvent* event)
+{
+ void* result;
+
+ if (self == NULL)
+ return NULL;
+
+ PR_ASSERT(event != NULL);
+
+ if (PR_GetCurrentThread() == self->handlerThread) {
+ /* Handle the case where the thread requesting the event handling
+ * is also the thread that's supposed to do the handling. */
+ result = event->handler(event);
+ }
+ else {
+ int i, entryCount;
+
+ event->lock = PR_NewLock();
+ if (!event->lock) {
+ return NULL;
+ }
+ event->condVar = PR_NewCondVar(event->lock);
+ if(!event->condVar) {
+ PR_DestroyLock(event->lock);
+ event->lock = NULL;
+ return NULL;
+ }
+
+ PR_Lock(event->lock);
+
+ entryCount = PR_GetMonitorEntryCount(self->monitor);
+
+ event->synchronousResult = (void*)PR_TRUE;
+
+ PL_PostEvent(self, event);
+
+ /* We need temporarily to give up our event queue monitor if
+ we're holding it, otherwise, the thread we're going to wait
+ for notification from won't be able to enter it to process
+ the event. */
+ if (entryCount) {
+ for (i = 0; i < entryCount; i++)
+ PR_ExitMonitor(self->monitor);
+ }
+
+ event->handled = PR_FALSE;
+
+ while (!event->handled) {
+ /* wait for event to be handled or destroyed */
+ PR_WaitCondVar(event->condVar, PR_INTERVAL_NO_TIMEOUT);
+ }
+
+ if (entryCount) {
+ for (i = 0; i < entryCount; i++)
+ PR_EnterMonitor(self->monitor);
+ }
+
+ result = event->synchronousResult;
+ event->synchronousResult = NULL;
+ PR_Unlock(event->lock);
+ }
+
+ /* For synchronous events, they're destroyed here on the caller's
+ thread before the result is returned. See PL_HandleEvent. */
+ PL_DestroyEvent(event);
+
+ return result;
+}
+
+PR_IMPLEMENT(PLEvent*)
+PL_GetEvent(PLEventQueue* self)
+{
+ PLEvent* event = NULL;
+ PRStatus err = PR_SUCCESS;
+
+ if (self == NULL)
+ return NULL;
+
+ PR_EnterMonitor(self->monitor);
+
+ if (!PR_CLIST_IS_EMPTY(&self->queue)) {
+ if ( self->type == EventQueueIsNative &&
+ self->notified &&
+ !self->processingEvents &&
+ 0 == _pl_GetEventCount(self) )
+ {
+ err = _pl_AcknowledgeNativeNotify(self);
+ self->notified = PR_FALSE;
+ }
+ if (err)
+ goto done;
+
+ /* then grab the event and return it: */
+ event = PR_EVENT_PTR(self->queue.next);
+ PR_REMOVE_AND_INIT_LINK(&event->link);
+ }
+
+ done:
+ PR_ExitMonitor(self->monitor);
+ return event;
+}
+
+PR_IMPLEMENT(PRBool)
+PL_EventAvailable(PLEventQueue* self)
+{
+ PRBool result = PR_FALSE;
+
+ if (self == NULL)
+ return PR_FALSE;
+
+ PR_EnterMonitor(self->monitor);
+
+ if (!PR_CLIST_IS_EMPTY(&self->queue))
+ result = PR_TRUE;
+
+ PR_ExitMonitor(self->monitor);
+ return result;
+}
+
+PR_IMPLEMENT(void)
+PL_MapEvents(PLEventQueue* self, PLEventFunProc fun, void* data)
+{
+ PRCList* qp;
+
+ if (self == NULL)
+ return;
+
+ PR_EnterMonitor(self->monitor);
+ qp = self->queue.next;
+ while (qp != &self->queue) {
+ PLEvent* event = PR_EVENT_PTR(qp);
+ qp = qp->next;
+ (*fun)(event, data, self);
+ }
+ PR_ExitMonitor(self->monitor);
+}
+
+static void PR_CALLBACK
+_pl_DestroyEventForOwner(PLEvent* event, void* owner, PLEventQueue* queue)
+{
+ PR_ASSERT(PR_GetMonitorEntryCount(queue->monitor) > 0);
+ if (event->owner == owner) {
+ PR_LOG(event_lm, PR_LOG_DEBUG,
+ ("$$$ \tdestroying event %0x for owner %0x", event, owner));
+ PL_DequeueEvent(event, queue);
+
+ if (event->synchronousResult == (void*)PR_TRUE) {
+ PR_Lock(event->lock);
+ event->synchronousResult = NULL;
+ event->handled = PR_TRUE;
+ PR_NotifyCondVar(event->condVar);
+ PR_Unlock(event->lock);
+ }
+ else {
+ PL_DestroyEvent(event);
+ }
+ }
+ else {
+ PR_LOG(event_lm, PR_LOG_DEBUG,
+ ("$$$ \tskipping event %0x for owner %0x", event, owner));
+ }
+}
+
+PR_IMPLEMENT(void)
+PL_RevokeEvents(PLEventQueue* self, void* owner)
+{
+ if (self == NULL)
+ return;
+
+ PR_LOG(event_lm, PR_LOG_DEBUG,
+ ("$$$ revoking events for owner %0x", owner));
+
+ /*
+ ** First we enter the monitor so that no one else can post any events
+ ** to the queue:
+ */
+ PR_EnterMonitor(self->monitor);
+ PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ owner %0x, entered monitor", owner));
+
+ /*
+ ** Discard any pending events for this owner:
+ */
+ PL_MapEvents(self, _pl_DestroyEventForOwner, owner);
+
+#ifdef DEBUG
+ {
+ PRCList* qp = self->queue.next;
+ while (qp != &self->queue) {
+ PLEvent* event = PR_EVENT_PTR(qp);
+ qp = qp->next;
+ PR_ASSERT(event->owner != owner);
+ }
+ }
+#endif /* DEBUG */
+
+ PR_ExitMonitor(self->monitor);
+
+ PR_LOG(event_lm, PR_LOG_DEBUG,
+ ("$$$ revoking events for owner %0x", owner));
+}
+
+static PRInt32
+_pl_GetEventCount(PLEventQueue* self)
+{
+ PRCList* node;
+ PRInt32 count = 0;
+
+ PR_EnterMonitor(self->monitor);
+ node = PR_LIST_HEAD(&self->queue);
+ while (node != &self->queue) {
+ count++;
+ node = PR_NEXT_LINK(node);
+ }
+ PR_ExitMonitor(self->monitor);
+
+ return count;
+}
+
+PR_IMPLEMENT(void)
+PL_ProcessPendingEvents(PLEventQueue* self)
+{
+ PRInt32 count;
+
+ if (self == NULL)
+ return;
+
+
+ PR_EnterMonitor(self->monitor);
+
+ if (self->processingEvents) {
+ _pl_AcknowledgeNativeNotify(self);
+ self->notified = PR_FALSE;
+ PR_ExitMonitor(self->monitor);
+ return;
+ }
+ self->processingEvents = PR_TRUE;
+
+ /* Only process the events that are already in the queue, and
+ * not any new events that get added. Do this by counting the
+ * number of events currently in the queue
+ */
+ count = _pl_GetEventCount(self);
+ PR_ExitMonitor(self->monitor);
+
+ while (count-- > 0) {
+ PLEvent* event = PL_GetEvent(self);
+ if (event == NULL)
+ break;
+
+ PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ processing event"));
+ PL_HandleEvent(event);
+ PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ done processing event"));
+ }
+
+ PR_EnterMonitor(self->monitor);
+
+ if (self->type == EventQueueIsNative) {
+ count = _pl_GetEventCount(self);
+
+ if (count <= 0) {
+ _pl_AcknowledgeNativeNotify(self);
+ self->notified = PR_FALSE;
+ }
+ else {
+ _pl_NativeNotify(self);
+ self->notified = PR_TRUE;
+ }
+
+ }
+ self->processingEvents = PR_FALSE;
+
+ PR_ExitMonitor(self->monitor);
+}
+
+/*******************************************************************************
+ * Event Operations
+ ******************************************************************************/
+
+PR_IMPLEMENT(void)
+PL_InitEvent(PLEvent* self, void* owner,
+ PLHandleEventProc handler,
+ PLDestroyEventProc destructor)
+{
+#ifdef PL_POST_TIMINGS
+ self->postTime = PR_IntervalNow();
+#endif
+ PR_INIT_CLIST(&self->link);
+ self->handler = handler;
+ self->destructor = destructor;
+ self->owner = owner;
+ self->synchronousResult = NULL;
+ self->handled = PR_FALSE;
+ self->lock = NULL;
+ self->condVar = NULL;
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
+ self->id = 0;
+#endif
+}
+
+PR_IMPLEMENT(void*)
+PL_GetEventOwner(PLEvent* self)
+{
+ return self->owner;
+}
+
+PR_IMPLEMENT(void)
+PL_HandleEvent(PLEvent* self)
+{
+ void* result;
+ if (self == NULL)
+ return;
+
+ /* This event better not be on an event queue anymore. */
+ PR_ASSERT(PR_CLIST_IS_EMPTY(&self->link));
+
+ result = self->handler(self);
+ if (NULL != self->synchronousResult) {
+ PR_Lock(self->lock);
+ self->synchronousResult = result;
+ self->handled = PR_TRUE;
+ PR_NotifyCondVar(self->condVar);
+ PR_Unlock(self->lock);
+ }
+ else {
+ /* For asynchronous events, they're destroyed by the event-handler
+ thread. See PR_PostSynchronousEvent. */
+ PL_DestroyEvent(self);
+ }
+}
+#ifdef PL_POST_TIMINGS
+static long s_eventCount = 0;
+static long s_totalTime = 0;
+#endif
+
+PR_IMPLEMENT(void)
+PL_DestroyEvent(PLEvent* self)
+{
+ if (self == NULL)
+ return;
+
+ /* This event better not be on an event queue anymore. */
+ PR_ASSERT(PR_CLIST_IS_EMPTY(&self->link));
+
+ if(self->condVar)
+ PR_DestroyCondVar(self->condVar);
+ if(self->lock)
+ PR_DestroyLock(self->lock);
+
+#ifdef PL_POST_TIMINGS
+ s_totalTime += PR_IntervalNow() - self->postTime;
+ s_eventCount++;
+ printf("$$$ running avg (%d) \n", PR_IntervalToMilliseconds(s_totalTime/s_eventCount));
+#endif
+
+ self->destructor(self);
+}
+
+PR_IMPLEMENT(void)
+PL_DequeueEvent(PLEvent* self, PLEventQueue* queue)
+{
+ if (self == NULL)
+ return;
+
+ /* Only the owner is allowed to dequeue events because once the
+ client has put it in the queue, they have no idea whether it's
+ been processed and destroyed or not. */
+
+ PR_ASSERT(queue->handlerThread == PR_GetCurrentThread());
+
+ PR_EnterMonitor(queue->monitor);
+
+ PR_ASSERT(!PR_CLIST_IS_EMPTY(&self->link));
+
+#if 0
+ /* I do not think that we need to do this anymore.
+ if we do not acknowledge and this is the only
+ only event in the queue, any calls to process
+ the eventQ will be effective noop.
+ */
+ if (queue->type == EventQueueIsNative)
+ _pl_AcknowledgeNativeNotify(queue);
+#endif
+
+ PR_REMOVE_AND_INIT_LINK(&self->link);
+
+ PR_ExitMonitor(queue->monitor);
+}
+
+PR_IMPLEMENT(void)
+PL_FavorPerformanceHint(PRBool favorPerformanceOverEventStarvation,
+ PRUint32 starvationDelay)
+{
+#if defined(_WIN32)
+
+ _md_StarvationDelay = starvationDelay;
+
+ if (favorPerformanceOverEventStarvation) {
+ _md_PerformanceSetting++;
+ return;
+ }
+
+ _md_PerformanceSetting--;
+
+ if (_md_PerformanceSetting == 0) {
+ /* Switched from allowing event starvation to no event starvation so grab
+ the current time to determine when to actually switch to using timers
+ instead of posted WM_APP messages. */
+ _md_SwitchTime = PR_IntervalToMilliseconds(PR_IntervalNow());
+ }
+
+#endif
+}
+
+/*******************************************************************************
+ * Pure Event Queues
+ *
+ * For when you're only processing PLEvents and there is no native
+ * select, thread messages, or AppleEvents.
+ ******************************************************************************/
+
+PR_IMPLEMENT(PLEvent*)
+PL_WaitForEvent(PLEventQueue* self)
+{
+ PLEvent* event;
+ PRMonitor* mon;
+
+ if (self == NULL)
+ return NULL;
+
+ mon = self->monitor;
+ PR_EnterMonitor(mon);
+
+ while ((event = PL_GetEvent(self)) == NULL) {
+ PRStatus err;
+ PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ waiting for event"));
+ err = PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
+ if ((err == PR_FAILURE)
+ && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) break;
+ }
+
+ PR_ExitMonitor(mon);
+ return event;
+}
+
+PR_IMPLEMENT(void)
+PL_EventLoop(PLEventQueue* self)
+{
+ if (self == NULL)
+ return;
+
+ while (PR_TRUE) {
+ PLEvent* event = PL_WaitForEvent(self);
+ if (event == NULL) {
+ /* This can only happen if the current thread is interrupted */
+ return;
+ }
+
+ PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ processing event"));
+ PL_HandleEvent(event);
+ PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ done processing event"));
+ }
+}
+
+/*******************************************************************************
+ * Native Event Queues
+ *
+ * For when you need to call select, or WaitNextEvent, and yet also want
+ * to handle PLEvents.
+ ******************************************************************************/
+
+static PRStatus
+_pl_SetupNativeNotifier(PLEventQueue* self)
+{
+#if defined(VMS)
+ unsigned int status;
+ self->idFunc = 0;
+ self->idFuncClosure = 0;
+ status = LIB$GET_EF(&self->efn);
+ if (!$VMS_STATUS_SUCCESS(status))
+ return PR_FAILURE;
+ PR_LOG(event_lm, PR_LOG_DEBUG,
+ ("$$$ Allocated event flag %d", self->efn));
+ return PR_SUCCESS;
+#elif defined(XP_UNIX) && !defined(XP_MACOSX)
+ int err;
+ int flags;
+
+ self->idFunc = 0;
+ self->idFuncClosure = 0;
+
+ err = pipe(self->eventPipe);
+ if (err != 0) {
+ return PR_FAILURE;
+ }
+#ifdef VBOX
+ fcntl(self->eventPipe[0], F_SETFD, FD_CLOEXEC);
+ fcntl(self->eventPipe[1], F_SETFD, FD_CLOEXEC);
+#endif
+
+ /* make the pipe nonblocking */
+ flags = fcntl(self->eventPipe[0], F_GETFL, 0);
+ if (flags == -1) {
+ goto failed;
+ }
+ err = fcntl(self->eventPipe[0], F_SETFL, flags | O_NONBLOCK);
+ if (err == -1) {
+ goto failed;
+ }
+ flags = fcntl(self->eventPipe[1], F_GETFL, 0);
+ if (flags == -1) {
+ goto failed;
+ }
+ err = fcntl(self->eventPipe[1], F_SETFL, flags | O_NONBLOCK);
+ if (err == -1) {
+ goto failed;
+ }
+ return PR_SUCCESS;
+
+failed:
+ close(self->eventPipe[0]);
+ close(self->eventPipe[1]);
+ return PR_FAILURE;
+#elif defined(XP_BEOS)
+ /* hook up to the nsToolkit queue, however the appshell
+ * isn't necessairly started, so we might have to create
+ * the queue ourselves
+ */
+ char portname[64];
+ char semname[64];
+ PR_snprintf(portname, sizeof(portname), "event%lx",
+ (long unsigned) self->handlerThread);
+ PR_snprintf(semname, sizeof(semname), "sync%lx",
+ (long unsigned) self->handlerThread);
+
+ if((self->eventport = find_port(portname)) < 0)
+ {
+ /* create port
+ */
+ self->eventport = create_port(500, portname);
+
+ /* We don't use the sem, but it has to be there
+ */
+ create_sem(0, semname);
+ }
+
+ return PR_SUCCESS;
+#else
+ return PR_SUCCESS;
+#endif
+}
+
+static void
+_pl_CleanupNativeNotifier(PLEventQueue* self)
+{
+#if defined(VMS)
+ {
+ unsigned int status;
+ PR_LOG(event_lm, PR_LOG_DEBUG,
+ ("$$$ Freeing event flag %d", self->efn));
+ status = LIB$FREE_EF(&self->efn);
+ }
+#elif defined(XP_UNIX) && !defined(XP_MACOSX)
+ close(self->eventPipe[0]);
+ close(self->eventPipe[1]);
+#elif defined(_WIN32)
+ if (self->timerSet) {
+ KillTimer(self->eventReceiverWindow, TIMER_ID);
+ self->timerSet = PR_FALSE;
+ }
+ RemoveProp(self->eventReceiverWindow, _md_GetEventQueuePropName());
+
+ /* DestroyWindow doesn't do anything when called from a non ui thread. Since
+ * self->eventReceiverWindow was created on the ui thread, it must be destroyed
+ * on the ui thread.
+ */
+ SendMessage(self->eventReceiverWindow, WM_CLOSE, 0, 0);
+
+#elif defined(XP_OS2)
+ WinDestroyWindow(self->eventReceiverWindow);
+#elif defined(MAC_USE_CFRUNLOOPSOURCE)
+
+ CFRunLoopRemoveSource(self->mMainRunLoop, self->mRunLoopSource, kCFRunLoopCommonModes);
+ CFRunLoopRemoveSource(self->mMainRunLoop, self->mRunLoopSource, self->mRunLoopModeStr); /* vbox */
+ CFRelease(self->mRunLoopSource);
+ CFRelease(self->mMainRunLoop);
+ CFRelease(self->mRunLoopModeStr); /* vbox */
+
+#elif defined(MAC_USE_CARBON_EVENT)
+ EventComparatorUPP comparator = NewEventComparatorUPP(_md_CarbonEventComparator);
+ PR_ASSERT(comparator != NULL);
+ if (comparator) {
+ FlushSpecificEventsFromQueue(GetMainEventQueue(), comparator, self);
+ DisposeEventComparatorUPP(comparator);
+ }
+ DisposeEventHandlerUPP(self->eventHandlerUPP);
+ RemoveEventHandler(self->eventHandlerRef);
+#endif
+}
+
+#if defined(_WIN32)
+
+static PRBool _md_WasInputPending = PR_FALSE;
+static PRUint32 _md_InputTime = 0;
+static PRBool _md_WasPaintPending = PR_FALSE;
+static PRUint32 _md_PaintTime = 0;
+/* last mouse location */
+static POINT _md_LastMousePos;
+
+/*******************************************************************************
+ * Timer callback function. Timers are used on WIN32 instead of APP events
+ * when there are pending UI events because APP events can cause the GUI to lockup
+ * because posted messages are processed before other messages.
+ ******************************************************************************/
+
+static void CALLBACK _md_TimerProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime )
+{
+ PREventQueue* queue = (PREventQueue *) GetProp(hwnd, _md_GetEventQueuePropName());
+ PR_ASSERT(queue != NULL);
+
+ KillTimer(hwnd, TIMER_ID);
+ queue->timerSet = PR_FALSE;
+ queue->removeMsg = PR_FALSE;
+ PL_ProcessPendingEvents( queue );
+ queue->removeMsg = PR_TRUE;
+}
+
+static PRBool _md_IsWIN9X = PR_FALSE;
+static PRBool _md_IsOSSet = PR_FALSE;
+
+static void _md_DetermineOSType()
+{
+ OSVERSIONINFO os;
+ os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&os);
+ if (VER_PLATFORM_WIN32_WINDOWS == os.dwPlatformId) {
+ _md_IsWIN9X = PR_TRUE;
+ }
+}
+
+static PRUint32 _md_GetPaintStarvationLimit()
+{
+ if (! _md_IsOSSet) {
+ _md_DetermineOSType();
+ _md_IsOSSet = PR_TRUE;
+ }
+
+ if (_md_IsWIN9X) {
+ return WIN9X_PAINT_STARVATION_LIMIT;
+ }
+
+ return PAINT_STARVATION_LIMIT;
+}
+
+
+/*
+ * Determine if an event is being starved (i.e the starvation limit has
+ * been exceeded.
+ * Note: this function uses the current setting and updates the contents
+ * of the wasPending and lastTime arguments
+ *
+ * ispending: PR_TRUE if the event is currently pending
+ * starvationLimit: Threshold defined in milliseconds for determining when
+ * the event has been held in the queue too long
+ * wasPending: PR_TRUE if the last time _md_EventIsStarved was called
+ * the event was pending. This value is updated within
+ * this function.
+ * lastTime: Holds the last time the event was in the queue.
+ * This value is updated within this function
+ * returns: PR_TRUE if the event is starved, PR_FALSE otherwise
+ */
+
+static PRBool _md_EventIsStarved(PRBool isPending, PRUint32 starvationLimit,
+ PRBool *wasPending, PRUint32 *lastTime,
+ PRUint32 currentTime)
+{
+ if (*wasPending && isPending) {
+ /*
+ * It was pending previously and the event is still
+ * pending so check to see if the elapsed time is
+ * over the limit which indicates the event was starved
+ */
+ if ((currentTime - *lastTime) > starvationLimit) {
+ return PR_TRUE; /* pending and over the limit */
+ }
+
+ return PR_FALSE; /* pending but within the limit */
+ }
+
+ if (isPending) {
+ /*
+ * was_pending must be false so record the current time
+ * so the elapsed time can be computed the next time this
+ * function is called
+ */
+ *lastTime = currentTime;
+ *wasPending = PR_TRUE;
+ return PR_FALSE;
+ }
+
+ /* Event is no longer pending */
+ *wasPending = PR_FALSE;
+ return PR_FALSE;
+}
+
+/* Determines if the there is a pending Mouse or input event */
+
+static PRBool _md_IsInputPending(WORD qstatus)
+{
+ /* Return immediately there aren't any pending input or paints. */
+ if (qstatus == 0) {
+ return PR_FALSE;
+ }
+
+ /* Is there anything other than a QS_MOUSEMOVE pending? */
+ if ((qstatus & QS_MOUSEBUTTON) ||
+ (qstatus & QS_KEY) ||
+ (qstatus & QS_HOTKEY)) {
+ return PR_TRUE;
+ }
+
+ /*
+ * Mouse moves need extra processing to determine if the mouse
+ * pointer actually changed location because Windows automatically
+ * generates WM_MOVEMOVE events when a new window is created which
+ * we need to filter out.
+ */
+ if (qstatus & QS_MOUSEMOVE) {
+ POINT cursorPos;
+ GetCursorPos(&cursorPos);
+ if ((_md_LastMousePos.x == cursorPos.x) &&
+ (_md_LastMousePos.y == cursorPos.y)) {
+ return PR_FALSE; /* This is a fake mouse move */
+ }
+
+ /* Real mouse move */
+ _md_LastMousePos.x = cursorPos.x;
+ _md_LastMousePos.y = cursorPos.y;
+ return PR_TRUE;
+ }
+
+ return PR_FALSE;
+}
+
+static PRStatus
+_pl_NativeNotify(PLEventQueue* self)
+{
+#ifdef USE_TIMER
+ WORD qstatus;
+
+ PRUint32 now = PR_IntervalToMilliseconds(PR_IntervalNow());
+
+ /* Since calls to set the _md_PerformanceSetting can be nested
+ * only performance setting values <= 0 will potentially trigger
+ * the use of a timer.
+ */
+ if ((_md_PerformanceSetting <= 0) &&
+ ((now - _md_SwitchTime) > _md_StarvationDelay)) {
+ SetTimer(self->eventReceiverWindow, TIMER_ID, 0 ,_md_TimerProc);
+ self->timerSet = PR_TRUE;
+ _md_WasInputPending = PR_FALSE;
+ _md_WasPaintPending = PR_FALSE;
+ return PR_SUCCESS;
+ }
+
+ qstatus = HIWORD(GetQueueStatus(QS_INPUT | QS_PAINT));
+
+ /* Check for starved input */
+ if (_md_EventIsStarved( _md_IsInputPending(qstatus),
+ INPUT_STARVATION_LIMIT,
+ &_md_WasInputPending,
+ &_md_InputTime,
+ now )) {
+ /*
+ * Use a timer for notification. Timers have the lowest priority.
+ * They are not processed until all other events have been processed.
+ * This allows any starved paints and input to be processed.
+ */
+ SetTimer(self->eventReceiverWindow, TIMER_ID, 0 ,_md_TimerProc);
+ self->timerSet = PR_TRUE;
+
+ /*
+ * Clear any pending paint. _md_WasInputPending was cleared in
+ * _md_EventIsStarved.
+ */
+ _md_WasPaintPending = PR_FALSE;
+ return PR_SUCCESS;
+ }
+
+ if (_md_EventIsStarved( (qstatus & QS_PAINT),
+ _md_GetPaintStarvationLimit(),
+ &_md_WasPaintPending,
+ &_md_PaintTime,
+ now) ) {
+ /*
+ * Use a timer for notification. Timers have the lowest priority.
+ * They are not processed until all other events have been processed.
+ * This allows any starved paints and input to be processed
+ */
+ SetTimer(self->eventReceiverWindow, TIMER_ID, 0 ,_md_TimerProc);
+ self->timerSet = PR_TRUE;
+
+ /*
+ * Clear any pending input. _md_WasPaintPending was cleared in
+ * _md_EventIsStarved.
+ */
+ _md_WasInputPending = PR_FALSE;
+ return PR_SUCCESS;
+ }
+
+ /*
+ * Nothing is being starved so post a message instead of using a timer.
+ * Posted messages are processed before other messages so they have the
+ * highest priority.
+ */
+#endif
+ PostMessage( self->eventReceiverWindow, _pr_PostEventMsgId,
+ (WPARAM)0, (LPARAM)self );
+
+ return PR_SUCCESS;
+}/* --- end _pl_NativeNotify() --- */
+#endif
+
+
+#if defined(XP_OS2)
+static PRStatus
+_pl_NativeNotify(PLEventQueue* self)
+{
+ BOOL rc = WinPostMsg( self->eventReceiverWindow, _pr_PostEventMsgId,
+ 0, MPFROMP(self));
+ return (rc == TRUE) ? PR_SUCCESS : PR_FAILURE;
+}/* --- end _pl_NativeNotify() --- */
+#endif /* XP_OS2 */
+
+#if defined(VMS)
+/* Just set the event flag */
+static PRStatus
+_pl_NativeNotify(PLEventQueue* self)
+{
+ unsigned int status;
+ PR_LOG(event_lm, PR_LOG_DEBUG,
+ ("_pl_NativeNotify: self=%p efn=%d",
+ self, self->efn));
+ status = SYS$SETEF(self->efn);
+ return ($VMS_STATUS_SUCCESS(status)) ? PR_SUCCESS : PR_FAILURE;
+}/* --- end _pl_NativeNotify() --- */
+#elif defined(XP_UNIX) && !defined(XP_MACOSX)
+
+static PRStatus
+_pl_NativeNotify(PLEventQueue* self)
+{
+#define NOTIFY_TOKEN 0xFA
+ PRInt32 count;
+ unsigned char buf[] = { NOTIFY_TOKEN };
+
+# ifdef VBOX
+ /* Don't write two chars, because we'll only acknowledge one and that'll
+ cause trouble for anyone selecting/polling on the read descriptor. */
+ if (self->notified)
+ return PR_SUCCESS;
+# endif
+
+ PR_LOG(event_lm, PR_LOG_DEBUG,
+ ("_pl_NativeNotify: self=%p",
+ self));
+ count = write(self->eventPipe[1], buf, 1);
+ if (count == 1)
+ return PR_SUCCESS;
+ if (count == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
+ return PR_SUCCESS;
+ return PR_FAILURE;
+}/* --- end _pl_NativeNotify() --- */
+#endif /* defined(XP_UNIX) && !defined(XP_MACOSX) */
+
+#if defined(XP_BEOS)
+struct ThreadInterfaceData
+{
+ void *data;
+ int32 sync;
+};
+
+static PRStatus
+_pl_NativeNotify(PLEventQueue* self)
+{
+ struct ThreadInterfaceData id;
+ id.data = self;
+ id.sync = false;
+ write_port(self->eventport, 'natv', &id, sizeof(id));
+
+ return PR_SUCCESS; /* Is this correct? */
+}
+#endif /* XP_BEOS */
+
+#if defined(XP_MACOSX)
+static PRStatus
+_pl_NativeNotify(PLEventQueue* self)
+{
+#if defined(MAC_USE_CFRUNLOOPSOURCE)
+ CFRunLoopSourceSignal(self->mRunLoopSource);
+ CFRunLoopWakeUp(self->mMainRunLoop);
+#elif defined(MAC_USE_CARBON_EVENT)
+ OSErr err;
+ EventRef newEvent;
+ if (CreateEvent(NULL, kEventClassPL, kEventProcessPLEvents,
+ 0, kEventAttributeNone, &newEvent) != noErr)
+ return PR_FAILURE;
+ err = SetEventParameter(newEvent, kEventParamPLEventQueue,
+ typeUInt32, sizeof(PREventQueue*), &self);
+ if (err == noErr) {
+ err = PostEventToQueue(GetMainEventQueue(), newEvent, kEventPriorityLow);
+ ReleaseEvent(newEvent);
+ }
+ if (err != noErr)
+ return PR_FAILURE;
+#endif
+ return PR_SUCCESS;
+}
+#endif /* defined(XP_MACOSX) */
+
+static PRStatus
+_pl_AcknowledgeNativeNotify(PLEventQueue* self)
+{
+#if defined(_WIN32) || defined(XP_OS2)
+#ifdef XP_OS2
+ QMSG aMsg;
+#else
+ MSG aMsg;
+#endif
+ /*
+ * only remove msg when we've been called directly by
+ * PL_ProcessPendingEvents, not when we've been called by
+ * the window proc because the window proc will remove the
+ * msg for us.
+ */
+ if (self->removeMsg) {
+ PR_LOG(event_lm, PR_LOG_DEBUG,
+ ("_pl_AcknowledgeNativeNotify: self=%p", self));
+#ifdef XP_OS2
+ WinPeekMsg((HAB)0, &aMsg, self->eventReceiverWindow,
+ _pr_PostEventMsgId, _pr_PostEventMsgId, PM_REMOVE);
+#else
+ PeekMessage(&aMsg, self->eventReceiverWindow,
+ _pr_PostEventMsgId, _pr_PostEventMsgId, PM_REMOVE);
+ if (self->timerSet) {
+ KillTimer(self->eventReceiverWindow, TIMER_ID);
+ self->timerSet = PR_FALSE;
+ }
+#endif
+ }
+ return PR_SUCCESS;
+#elif defined(VMS)
+ PR_LOG(event_lm, PR_LOG_DEBUG,
+ ("_pl_AcknowledgeNativeNotify: self=%p efn=%d",
+ self, self->efn));
+ /*
+ ** If this is the last entry, then clear the event flag. Also make sure
+ ** the flag is cleared on any spurious wakeups.
+ */
+ sys$clref(self->efn);
+ return PR_SUCCESS;
+#elif defined(XP_UNIX) && !defined(XP_MACOSX)
+
+ PRInt32 count;
+ unsigned char c;
+ PR_LOG(event_lm, PR_LOG_DEBUG,
+ ("_pl_AcknowledgeNativeNotify: self=%p",
+ self));
+ /* consume the byte NativeNotify put in our pipe: */
+ count = read(self->eventPipe[0], &c, 1);
+ if ((count == 1) && (c == NOTIFY_TOKEN))
+ return PR_SUCCESS;
+ if ((count == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
+ return PR_SUCCESS;
+ return PR_FAILURE;
+#elif defined(MAC_USE_CFRUNLOOPSOURCE) /* vbox */
+ /* vbox */
+ CFRunLoopRunInMode(self->mRunLoopModeStr, 0.0, 1); /* vbox */
+ return PR_SUCCESS; /* vbox */
+#else
+
+ /* nothing to do on the other platforms */
+ return PR_SUCCESS;
+#endif
+}
+
+PR_IMPLEMENT(PRInt32)
+PL_GetEventQueueSelectFD(PLEventQueue* self)
+{
+ if (self == NULL)
+ return -1;
+
+#if defined(VMS)
+ return -(self->efn);
+#elif defined(XP_UNIX) && !defined(XP_MACOSX)
+ return self->eventPipe[0];
+#else
+ return -1; /* other platforms don't handle this (yet) */
+#endif
+}
+
+PR_IMPLEMENT(PRBool)
+PL_IsQueueOnCurrentThread( PLEventQueue *queue )
+{
+ PRThread *me = PR_GetCurrentThread();
+ return me == queue->handlerThread;
+}
+
+PR_EXTERN(PRBool)
+PL_IsQueueNative(PLEventQueue *queue)
+{
+ return queue->type == EventQueueIsNative ? PR_TRUE : PR_FALSE;
+}
+
+#if defined(_WIN32)
+/*
+** Global Instance handle...
+** In Win32 this is the module handle of the DLL.
+**
+*/
+static HINSTANCE _pr_hInstance;
+#endif
+
+
+#if defined(_WIN32)
+
+/*
+** Initialization routine for the DLL...
+*/
+
+BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
+{
+ switch (dwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ _pr_hInstance = hDLL;
+ break;
+
+ case DLL_THREAD_ATTACH:
+ break;
+
+ case DLL_THREAD_DETACH:
+ break;
+
+ case DLL_PROCESS_DETACH:
+ _pr_hInstance = NULL;
+ break;
+ }
+
+ return TRUE;
+}
+#endif
+
+
+#if defined(_WIN32) || defined(XP_OS2)
+#ifdef XP_OS2
+MRESULT EXPENTRY
+_md_EventReceiverProc(HWND hwnd, ULONG uMsg, MPARAM wParam, MPARAM lParam)
+#else
+LRESULT CALLBACK
+_md_EventReceiverProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+#endif
+{
+ if (_pr_PostEventMsgId == uMsg )
+ {
+ PREventQueue *queue = (PREventQueue *)lParam;
+ queue->removeMsg = PR_FALSE;
+ PL_ProcessPendingEvents(queue);
+ queue->removeMsg = PR_TRUE;
+#ifdef XP_OS2
+ return MRFROMLONG(TRUE);
+#else
+ return TRUE;
+#endif
+ }
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+}
+
+static PRBool isInitialized;
+static PRCallOnceType once;
+static PRLock *initLock;
+
+/*
+** InitWinEventLib() -- Create the Windows initialization lock
+**
+*/
+static PRStatus InitEventLib( void )
+{
+ PR_ASSERT( initLock == NULL );
+
+ initLock = PR_NewLock();
+ return initLock ? PR_SUCCESS : PR_FAILURE;
+}
+
+#endif /* Win32, OS2 */
+
+#if defined(_WIN32)
+
+/*
+** _md_CreateEventQueue() -- ModelDependent initializer
+*/
+static void _md_CreateEventQueue( PLEventQueue *eventQueue )
+{
+ WNDCLASS wc;
+
+ /*
+ ** If this is the first call to PL_InitializeEventsLib(),
+ ** make the call to InitWinEventLib() to create the initLock.
+ **
+ ** Then lock the initializer lock to insure that
+ ** we have exclusive control over the initialization sequence.
+ **
+ */
+
+
+ /* Register the windows message for XPCOM Event notification */
+ _pr_PostEventMsgId = RegisterWindowMessage("XPCOM_PostEvent");
+
+ /* Register the class for the event receiver window */
+ if (!GetClassInfo(_pr_hInstance, _pr_eventWindowClass, &wc)) {
+ wc.style = 0;
+ wc.lpfnWndProc = _md_EventReceiverProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = _pr_hInstance;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = (HBRUSH) NULL;
+ wc.lpszMenuName = (LPCSTR) NULL;
+ wc.lpszClassName = _pr_eventWindowClass;
+ RegisterClass(&wc);
+ }
+
+ /* Create the event receiver window */
+ eventQueue->eventReceiverWindow = CreateWindow(_pr_eventWindowClass,
+ "XPCOM:EventReceiver",
+ 0, 0, 0, 10, 10,
+ NULL, NULL, _pr_hInstance,
+ NULL);
+ PR_ASSERT(eventQueue->eventReceiverWindow);
+ /* Set a property which can be used to retrieve the event queue
+ * within the _md_TimerProc callback
+ */
+ SetProp(eventQueue->eventReceiverWindow,
+ _md_GetEventQueuePropName(), (HANDLE)eventQueue);
+
+ return;
+} /* end _md_CreateEventQueue() */
+#endif /* Winxx */
+
+#if defined(XP_OS2)
+/*
+** _md_CreateEventQueue() -- ModelDependent initializer
+*/
+static void _md_CreateEventQueue( PLEventQueue *eventQueue )
+{
+ /* Must have HMQ for this & can't assume we already have appshell */
+ if( FALSE == WinQueryQueueInfo( HMQ_CURRENT, NULL, 0))
+ {
+ PPIB ppib;
+ PTIB ptib;
+ HAB hab;
+ HMQ hmq;
+
+ /* Set our app to be a PM app before attempting Win calls */
+ DosGetInfoBlocks(&ptib, &ppib);
+ ppib->pib_ultype = 3;
+
+ hab = WinInitialize(0);
+ hmq = WinCreateMsgQueue(hab, 0);
+ PR_ASSERT(hmq);
+ }
+
+ if( !_pr_PostEventMsgId)
+ {
+ WinRegisterClass( 0 /* hab_current */,
+ _pr_eventWindowClass,
+ _md_EventReceiverProc,
+ 0, 0);
+
+ _pr_PostEventMsgId = WinAddAtom( WinQuerySystemAtomTable(),
+ "XPCOM_PostEvent");
+ }
+
+ eventQueue->eventReceiverWindow = WinCreateWindow( HWND_DESKTOP,
+ _pr_eventWindowClass,
+ "", 0,
+ 0, 0, 0, 0,
+ HWND_DESKTOP,
+ HWND_TOP,
+ 0,
+ NULL,
+ NULL);
+ PR_ASSERT(eventQueue->eventReceiverWindow);
+
+ return;
+} /* end _md_CreateEventQueue() */
+#endif /* XP_OS2 */
+
+#if (defined(XP_UNIX) && !defined(XP_MACOSX)) || defined(XP_BEOS)
+/*
+** _md_CreateEventQueue() -- ModelDependent initializer
+*/
+static void _md_CreateEventQueue( PLEventQueue *eventQueue )
+{
+ /* there's really nothing special to do here,
+ ** the guts of the unix stuff is in the setupnativenotify
+ ** and related functions.
+ */
+ return;
+} /* end _md_CreateEventQueue() */
+#endif /* (defined(XP_UNIX) && !defined(XP_MACOSX)) || defined(XP_BEOS) */
+
+#if defined(MAC_USE_CFRUNLOOPSOURCE)
+static void _md_EventReceiverProc(void *info)
+{
+ PLEventQueue *queue = (PLEventQueue*)info;
+ PL_ProcessPendingEvents(queue);
+}
+
+#elif defined(MAC_USE_CARBON_EVENT)
+/*
+** _md_CreateEventQueue() -- ModelDependent initializer
+*/
+
+static pascal OSStatus _md_EventReceiverProc(EventHandlerCallRef nextHandler,
+ EventRef inEvent,
+ void* userData)
+{
+ if (GetEventClass(inEvent) == kEventClassPL &&
+ GetEventKind(inEvent) == kEventProcessPLEvents)
+ {
+ PREventQueue *queue;
+ if (GetEventParameter(inEvent, kEventParamPLEventQueue,
+ typeUInt32, NULL, sizeof(PREventQueue*), NULL,
+ &queue) == noErr)
+ {
+ PL_ProcessPendingEvents(queue);
+ return noErr;
+ }
+ }
+ return eventNotHandledErr;
+}
+
+static pascal Boolean _md_CarbonEventComparator(EventRef inEvent,
+ void *inCompareData)
+{
+ Boolean match = false;
+
+ if (GetEventClass(inEvent) == kEventClassPL &&
+ GetEventKind(inEvent) == kEventProcessPLEvents)
+ {
+ PREventQueue *queue;
+ match = ((GetEventParameter(inEvent, kEventParamPLEventQueue,
+ typeUInt32, NULL, sizeof(PREventQueue*), NULL,
+ &queue) == noErr) && (queue == inCompareData));
+ }
+ return match;
+}
+
+#endif /* defined(MAC_USE_CARBON_EVENT) */
+
+#if defined(XP_MACOSX)
+static void _md_CreateEventQueue( PLEventQueue *eventQueue )
+{
+#if defined(MAC_USE_CFRUNLOOPSOURCE)
+ CFRunLoopSourceContext sourceContext = { 0 };
+ sourceContext.version = 0;
+ sourceContext.info = (void*)eventQueue;
+ sourceContext.perform = _md_EventReceiverProc;
+
+ /* make a run loop source */
+ eventQueue->mRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0 /* order */, &sourceContext);
+ PR_ASSERT(eventQueue->mRunLoopSource);
+
+ eventQueue->mMainRunLoop = CFRunLoopGetCurrent();
+ CFRetain(eventQueue->mMainRunLoop);
+
+ /* and add it to the run loop */
+ CFRunLoopAddSource(eventQueue->mMainRunLoop, eventQueue->mRunLoopSource, kCFRunLoopCommonModes);
+
+ /* Add it again but with a unique mode name so we can acknowledge it
+ without processing any other message sources. */
+ { /* vbox */
+ char szModeName[80]; /* vbox */
+ snprintf(szModeName, sizeof(szModeName), "VBoxXPCOMQueueMode-%p", eventQueue); /* vbox */
+ eventQueue->mRunLoopModeStr = CFStringCreateWithCString(kCFAllocatorDefault, /* vbox */
+ szModeName, kCFStringEncodingASCII); /* vbox */
+ CFRunLoopAddSource(eventQueue->mMainRunLoop, /* vbox */
+ eventQueue->mRunLoopSource, eventQueue->mRunLoopModeStr); /* vbox */
+ } /* vbox */
+
+#elif defined(MAC_USE_CARBON_EVENT)
+ eventQueue->eventHandlerUPP = NewEventHandlerUPP(_md_EventReceiverProc);
+ PR_ASSERT(eventQueue->eventHandlerUPP);
+ if (eventQueue->eventHandlerUPP)
+ {
+ EventTypeSpec eventType;
+
+ eventType.eventClass = kEventClassPL;
+ eventType.eventKind = kEventProcessPLEvents;
+
+ InstallApplicationEventHandler(eventQueue->eventHandlerUPP, 1, &eventType,
+ eventQueue, &eventQueue->eventHandlerRef);
+ PR_ASSERT(eventQueue->eventHandlerRef);
+ }
+#endif
+} /* end _md_CreateEventQueue() */
+#endif /* defined(XP_MACOSX) */
+
+/* extra functions for unix */
+
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
+
+PR_IMPLEMENT(PRInt32)
+PL_ProcessEventsBeforeID(PLEventQueue *aSelf, unsigned long aID)
+{
+ PRInt32 count = 0;
+ PRInt32 fullCount;
+
+ if (aSelf == NULL)
+ return -1;
+
+ PR_EnterMonitor(aSelf->monitor);
+
+ if (aSelf->processingEvents) {
+ PR_ExitMonitor(aSelf->monitor);
+ return 0;
+ }
+
+ aSelf->processingEvents = PR_TRUE;
+
+ /* Only process the events that are already in the queue, and
+ * not any new events that get added. Do this by counting the
+ * number of events currently in the queue
+ */
+ fullCount = _pl_GetEventCount(aSelf);
+ PR_LOG(event_lm, PR_LOG_DEBUG,
+ ("$$$ fullCount is %d id is %ld\n", fullCount, aID));
+
+ if (fullCount == 0) {
+ aSelf->processingEvents = PR_FALSE;
+ PR_ExitMonitor(aSelf->monitor);
+ return 0;
+ }
+
+ PR_ExitMonitor(aSelf->monitor);
+
+ while (fullCount-- > 0) {
+ /* peek at the next event */
+ PLEvent *event;
+ event = PR_EVENT_PTR(aSelf->queue.next);
+ if (event == NULL)
+ break;
+ PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ processing event %ld\n",
+ event->id));
+ if (event->id >= aID) {
+ PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ skipping event and breaking"));
+ break;
+ }
+
+ event = PL_GetEvent(aSelf);
+ PL_HandleEvent(event);
+ PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ done processing event"));
+ count++;
+ }
+
+ PR_EnterMonitor(aSelf->monitor);
+
+ /* if full count still had items left then there's still items left
+ in the queue. Let the native notify token stay. */
+
+ if (aSelf->type == EventQueueIsNative) {
+ fullCount = _pl_GetEventCount(aSelf);
+
+ if (fullCount <= 0) {
+ _pl_AcknowledgeNativeNotify(aSelf);
+ aSelf->notified = PR_FALSE;
+ }
+ }
+
+ aSelf->processingEvents = PR_FALSE;
+
+ PR_ExitMonitor(aSelf->monitor);
+
+ return count;
+}
+
+PR_IMPLEMENT(void)
+PL_RegisterEventIDFunc(PLEventQueue *aSelf, PLGetEventIDFunc aFunc,
+ void *aClosure)
+{
+ aSelf->idFunc = aFunc;
+ aSelf->idFuncClosure = aClosure;
+}
+
+PR_IMPLEMENT(void)
+PL_UnregisterEventIDFunc(PLEventQueue *aSelf)
+{
+ aSelf->idFunc = 0;
+ aSelf->idFuncClosure = 0;
+}
+
+#endif /* defined(XP_UNIX) && !defined(XP_MACOSX) */
+
+/* --- end plevent.c --- */
diff --git a/src/libs/xpcom18a4/xpcom/threads/plevent.h b/src/libs/xpcom18a4/xpcom/threads/plevent.h
new file mode 100644
index 00000000..5bc9c89f
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/threads/plevent.h
@@ -0,0 +1,690 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**********************************************************************
+NSPL Events
+
+Defining Events
+---------------
+
+Events are essentially structures that represent argument lists for a
+function that will run on another thread. All event structures you
+define must include a PLEvent struct as their first field:
+
+ typedef struct MyEventType {
+ PLEvent e;
+ // arguments follow...
+ int x;
+ char* y;
+ } MyEventType;
+
+It is also essential that you establish a model of ownership for each
+argument passed in an event record, i.e. whether particular arguments
+will be deleted by the event destruction callback, or whether they
+only loaned to the event handler callback, and guaranteed to persist
+until the time at which the handler is called.
+
+Sending Events
+--------------
+
+Events are initialized by PL_InitEvent and can be sent via
+PL_PostEvent or PL_PostSynchronousEvent. Events can also have an
+owner. The owner of an event can revoke all the events in a given
+event-queue by calling PL_RevokeEvents. An owner might want
+to do this if, for instance, it is being destroyed, and handling the
+events after the owner's destruction would cause an error (e.g. an
+MWContext).
+
+Since the act of initializing and posting an event must be coordinated
+with it's possible revocation, it is essential that the event-queue's
+monitor be entered surrounding the code that constructs, initializes
+and posts the event:
+
+ void postMyEvent(MyOwner* owner, int x, char* y)
+ {
+ MyEventType* event;
+
+ PL_ENTER_EVENT_QUEUE_MONITOR(myQueue);
+
+ // construct
+ event = PR_NEW(MyEventType);
+ if (event == NULL) goto done;
+
+ // initialize
+ PL_InitEvent(event, owner,
+ (PLHandleEventProc)handleMyEvent,
+ (PLDestroyEventProc)destroyMyEvent);
+ event->x = x;
+ event->y = strdup(y);
+
+ // post
+ PL_PostEvent(myQueue, &event->e);
+
+ done:
+ PL_EXIT_EVENT_QUEUE_MONITOR(myQueue);
+ }
+
+If you don't call PL_InitEvent and PL_PostEvent within the
+event-queue's monitor, you'll get a big red assert.
+
+Handling Events
+---------------
+
+To handle an event you must write a callback that is passed the event
+record you defined containing the event's arguments:
+
+ void* handleMyEvent(MyEventType* event)
+ {
+ doit(event->x, event->y);
+ return NULL; // you could return a value for a sync event
+ }
+
+Similarly for the destruction callback:
+
+ void destroyMyEvent(MyEventType* event)
+ {
+ free(event->y); // created by strdup
+ free(event);
+ }
+
+Processing Events in Your Event Loop
+------------------------------------
+
+If your main loop only processes events delivered to the event queue,
+things are rather simple. You just get the next event (which may
+block), and then handle it:
+
+ while (1) {
+ event = PL_GetEvent(myQueue);
+ PL_HandleEvent(event);
+ }
+
+However, if other things must be waited on, you'll need to obtain a
+file-descriptor that represents your event queue, and hand it to select:
+
+ fd = PL_GetEventQueueSelectFD(myQueue);
+ ...add fd to select set...
+ while (select(...)) {
+ if (...fd...) {
+ PL_ProcessPendingEvents(myQueue);
+ }
+ ...
+ }
+
+Of course, with Motif and Windows it's more complicated than that, and
+on Mac it's completely different, but you get the picture.
+
+Revoking Events
+---------------
+If at any time an owner of events is about to be destroyed, you must
+take steps to ensure that no one tries to use the event queue after
+the owner is gone (or a crash may result). You can do this by either
+processing all the events in the queue before destroying the owner:
+
+ {
+ ...
+ PL_ENTER_EVENT_QUEUE_MONITOR(myQueue);
+ PL_ProcessPendingEvents(myQueue);
+ DestroyMyOwner(owner);
+ PL_EXIT_EVENT_QUEUE_MONITOR(myQueue);
+ ...
+ }
+
+or by revoking the events that are in the queue for that owner. This
+removes them from the queue and calls their destruction callback:
+
+ {
+ ...
+ PL_ENTER_EVENT_QUEUE_MONITOR(myQueue);
+ PL_RevokeEvents(myQueue, owner);
+ DestroyMyOwner(owner);
+ PL_EXIT_EVENT_QUEUE_MONITOR(myQueue);
+ ...
+ }
+
+In either case it is essential that you be in the event-queue's monitor
+to ensure that all events are removed from the queue for that owner,
+and to ensure that no more events will be delivered for that owner.
+**********************************************************************/
+
+#ifndef plevent_h___
+#define plevent_h___
+
+#include "prtypes.h"
+#include "prclist.h"
+#include "prthread.h"
+#include "prlock.h"
+#include "prcvar.h"
+#include "prmon.h"
+
+/* For HWND */
+#if defined(XP_WIN32)
+#include <windef.h>
+#elif defined(XP_OS2)
+#define INCL_DOSMISC
+#define INCL_DOSPROCESS
+#define INCL_DOSERRORS
+#include <os2.h>
+#endif
+
+#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP
+#define PL_DestroyEvent VBoxNsplPL_DestroyEvent
+#define PL_HandleEvent VBoxNsplPL_HandleEvent
+#define PL_InitEvent VBoxNsplPL_InitEvent
+#define PL_CreateEventQueue VBoxNsplPL_CreateEventQueue
+#define PL_CreateMonitoredEventQueue VBoxNsplPL_CreateMonitoredEventQueue
+#define PL_CreateNativeEventQueue VBoxNsplPL_CreateNativeEventQueue
+#define PL_DequeueEvent VBoxNsplPL_DequeueEvent
+#define PL_DestroyEventQueue VBoxNsplPL_DestroyEventQueue
+#define PL_EventAvailable VBoxNsplPL_EventAvailable
+#define PL_EventLoop VBoxNsplPL_EventLoop
+#define PL_GetEvent VBoxNsplPL_GetEvent
+#define PL_GetEventOwner VBoxNsplPL_GetEventOwner
+#define PL_GetEventQueueMonitor VBoxNsplPL_GetEventQueueMonitor
+#define PL_GetEventQueueSelectFD VBoxNsplPL_GetEventQueueSelectFD
+#define PL_MapEvents VBoxNsplPL_MapEvents
+#define PL_PostEvent VBoxNsplPL_PostEvent
+#define PL_PostSynchronousEvent VBoxNsplPL_PostSynchronousEvent
+#define PL_ProcessEventsBeforeID VBoxNsplPL_ProcessEventsBeforeID
+#define PL_ProcessPendingEvents VBoxNsplPL_ProcessPendingEvents
+#define PL_RegisterEventIDFunc VBoxNsplPL_RegisterEventIDFunc
+#define PL_RevokeEvents VBoxNsplPL_RevokeEvents
+#define PL_UnregisterEventIDFunc VBoxNsplPL_UnregisterEventIDFunc
+#define PL_WaitForEvent VBoxNsplPL_WaitForEvent
+#define PL_IsQueueNative VBoxNsplPL_IsQueueNative
+#define PL_IsQueueOnCurrentThread VBoxNsplPL_IsQueueOnCurrentThread
+#define PL_FavorPerformanceHint VBoxNsplPL_FavorPerformanceHint
+#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */
+
+PR_BEGIN_EXTERN_C
+
+/* Typedefs */
+
+typedef struct PLEvent PLEvent;
+typedef struct PLEventQueue PLEventQueue;
+
+/*******************************************************************************
+ * Event Queue Operations
+ ******************************************************************************/
+
+/*
+** Creates a new event queue. Returns NULL on failure.
+*/
+PR_EXTERN(PLEventQueue*)
+PL_CreateEventQueue(const char* name, PRThread* handlerThread);
+
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PL_CreateNativeEventQueue()
+**
+** DESCRIPTION:
+** PL_CreateNativeEventQueue() creates an event queue that
+** uses platform specific notify mechanisms.
+**
+** For Unix, the platform specific notify mechanism provides
+** an FD that may be extracted using the function
+** PL_GetEventQueueSelectFD(). The FD returned may be used in
+** a select() function call.
+**
+** For Windows, the platform specific notify mechanism
+** provides an event receiver window that is called by
+** Windows to process the event using the windows message
+** pump engine.
+**
+** INPUTS:
+** name: A name, as a diagnostic aid.
+**
+** handlerThread: A pointer to the PRThread structure for
+** the thread that will "handle" events posted to this event
+** queue.
+**
+** RETURNS:
+** A pointer to a PLEventQueue structure or NULL.
+**
+*/
+PR_EXTERN(PLEventQueue *)
+ PL_CreateNativeEventQueue(
+ const char *name,
+ PRThread *handlerThread
+ );
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PL_CreateMonitoredEventQueue()
+**
+** DESCRIPTION:
+** PL_CreateMonitoredEventQueue() creates an event queue. No
+** platform specific notify mechanism is created with the
+** event queue.
+**
+** Users of this type of event queue must explicitly poll the
+** event queue to retreive and process events.
+**
+**
+** INPUTS:
+** name: A name, as a diagnostic aid.
+**
+** handlerThread: A pointer to the PRThread structure for
+** the thread that will "handle" events posted to this event
+** queue.
+**
+** RETURNS:
+** A pointer to a PLEventQueue structure or NULL.
+**
+*/
+PR_EXTERN(PLEventQueue *)
+ PL_CreateMonitoredEventQueue(
+ const char *name,
+ PRThread *handlerThread
+ );
+
+/*
+** Destroys an event queue.
+*/
+PR_EXTERN(void)
+PL_DestroyEventQueue(PLEventQueue* self);
+
+/*
+** Returns the monitor associated with an event queue. This monitor is
+** selectable. The monitor should be entered to protect against anyone
+** calling PL_RevokeEvents while the event is trying to be constructed
+** and delivered.
+*/
+PR_EXTERN(PRMonitor*)
+PL_GetEventQueueMonitor(PLEventQueue* self);
+
+#define PL_ENTER_EVENT_QUEUE_MONITOR(queue) \
+ PR_EnterMonitor(PL_GetEventQueueMonitor(queue))
+
+#define PL_EXIT_EVENT_QUEUE_MONITOR(queue) \
+ PR_ExitMonitor(PL_GetEventQueueMonitor(queue))
+
+/*
+** Posts an event to an event queue, waking up any threads waiting for an
+** event. If event is NULL, notification still occurs, but no event will
+** be available.
+**
+** Any events delivered by this routine will be destroyed by PL_HandleEvent
+** when it is called (by the event-handling thread).
+*/
+PR_EXTERN(PRStatus)
+PL_PostEvent(PLEventQueue* self, PLEvent* event);
+
+/*
+** Like PL_PostEvent, this routine posts an event to the event handling
+** thread, but does so synchronously, waiting for the result. The result
+** which is the value of the handler routine is returned.
+**
+** Any events delivered by this routine will be not be destroyed by
+** PL_HandleEvent, but instead will be destroyed just before the result is
+** returned (by the current thread).
+*/
+PR_EXTERN(void*)
+PL_PostSynchronousEvent(PLEventQueue* self, PLEvent* event);
+
+/*
+** Gets an event from an event queue. Returns NULL if no event is
+** available.
+*/
+PR_EXTERN(PLEvent*)
+PL_GetEvent(PLEventQueue* self);
+
+/*
+** Returns true if there is an event available for PL_GetEvent.
+*/
+PR_EXTERN(PRBool)
+PL_EventAvailable(PLEventQueue* self);
+
+/*
+** This is the type of the function that must be passed to PL_MapEvents
+** (see description below).
+*/
+typedef void
+(PR_CALLBACK *PLEventFunProc)(PLEvent* event, void* data, PLEventQueue* queue);
+
+/*
+** Applies a function to every event in the event queue. This can be used
+** to selectively handle, filter, or remove events. The data pointer is
+** passed to each invocation of the function fun.
+*/
+PR_EXTERN(void)
+PL_MapEvents(PLEventQueue* self, PLEventFunProc fun, void* data);
+
+/*
+** This routine walks an event queue and destroys any event whose owner is
+** the owner specified. The == operation is used to compare owners.
+*/
+PR_EXTERN(void)
+PL_RevokeEvents(PLEventQueue* self, void* owner);
+
+/*
+** This routine processes all pending events in the event queue. It can be
+** called from the thread's main event-processing loop whenever the event
+** queue's selectFD is ready (returned by PL_GetEventQueueSelectFD).
+*/
+PR_EXTERN(void)
+PL_ProcessPendingEvents(PLEventQueue* self);
+
+/*******************************************************************************
+ * Pure Event Queues
+ *
+ * For when you're only processing PLEvents and there is no native
+ * select, thread messages, or AppleEvents.
+ ******************************************************************************/
+
+/*
+** Blocks until an event can be returned from the event queue. This routine
+** may return NULL if the current thread is interrupted.
+*/
+PR_EXTERN(PLEvent*)
+PL_WaitForEvent(PLEventQueue* self);
+
+/*
+** One stop shopping if all you're going to do is process PLEvents. Just
+** call this and it loops forever processing events as they arrive. It will
+** terminate when your thread is interrupted or dies.
+*/
+PR_EXTERN(void)
+PL_EventLoop(PLEventQueue* self);
+
+/*******************************************************************************
+ * Native Event Queues
+ *
+ * For when you need to call select, or WaitNextEvent, and yet also want
+ * to handle PLEvents.
+ ******************************************************************************/
+
+/*
+** This routine allows you to grab the file descriptor associated with an
+** event queue and use it in the readFD set of select. Useful for platforms
+** that support select, and must wait on other things besides just PLEvents.
+*/
+PR_EXTERN(PRInt32)
+PL_GetEventQueueSelectFD(PLEventQueue* self);
+
+/*
+** This routine will allow you to check to see if the given eventQueue in
+** on the current thread. It will return PR_TRUE if so, else it will return
+** PR_FALSE
+*/
+PR_EXTERN(PRBool)
+ PL_IsQueueOnCurrentThread( PLEventQueue *queue );
+
+/*
+** Returns whether the queue is native (true) or monitored (false)
+*/
+PR_EXTERN(PRBool)
+PL_IsQueueNative(PLEventQueue *queue);
+
+/*******************************************************************************
+ * Event Operations
+ ******************************************************************************/
+
+/*
+** The type of an event handler function. This function is passed as an
+** initialization argument to PL_InitEvent, and called by
+** PL_HandleEvent. If the event is called synchronously, a void* result
+** may be returned (otherwise any result will be ignored).
+*/
+typedef void*
+(PR_CALLBACK *PLHandleEventProc)(PLEvent* self);
+
+/*
+** The type of an event destructor function. This function is passed as
+** an initialization argument to PL_InitEvent, and called by
+** PL_DestroyEvent.
+*/
+typedef void
+(PR_CALLBACK *PLDestroyEventProc)(PLEvent* self);
+
+/*
+** Initializes an event. Usually events are embedded in a larger event
+** structure which holds event-specific data, so this is an initializer
+** for that embedded part of the structure.
+*/
+PR_EXTERN(void)
+PL_InitEvent(PLEvent* self, void* owner,
+ PLHandleEventProc handler,
+ PLDestroyEventProc destructor);
+
+/*
+** Returns the owner of an event.
+*/
+PR_EXTERN(void*)
+PL_GetEventOwner(PLEvent* self);
+
+/*
+** Handles an event, calling the event's handler routine.
+*/
+PR_EXTERN(void)
+PL_HandleEvent(PLEvent* self);
+
+/*
+** Destroys an event, calling the event's destructor.
+*/
+PR_EXTERN(void)
+PL_DestroyEvent(PLEvent* self);
+
+/*
+** Removes an event from an event queue.
+*/
+PR_EXTERN(void)
+PL_DequeueEvent(PLEvent* self, PLEventQueue* queue);
+
+
+/*
+ * Give hint to native PL_Event notification mechanism. If the native
+ * platform needs to tradeoff performance vs. native event starvation
+ * this hint tells the native dispatch code which to favor.
+ * The default is to prevent event starvation.
+ *
+ * Calls to this function may be nested. When the number of calls that
+ * pass PR_TRUE is subtracted from the number of calls that pass PR_FALSE
+ * is greater than 0, performance is given precedence over preventing
+ * event starvation.
+ *
+ * The starvationDelay arg is only used when
+ * favorPerformanceOverEventStarvation is PR_FALSE. It is the
+ * amount of time in milliseconds to wait before the PR_FALSE actually
+ * takes effect.
+ */
+PR_EXTERN(void)
+PL_FavorPerformanceHint(PRBool favorPerformanceOverEventStarvation, PRUint32 starvationDelay);
+
+
+/*******************************************************************************
+ * Private Stuff
+ ******************************************************************************/
+
+struct PLEvent {
+ PRCList link;
+ PLHandleEventProc handler;
+ PLDestroyEventProc destructor;
+ void* owner;
+ void* synchronousResult;
+ PRLock* lock;
+ PRCondVar* condVar;
+ PRBool handled;
+#ifdef PL_POST_TIMINGS
+ PRIntervalTime postTime;
+#endif
+#ifdef XP_UNIX
+ unsigned long id;
+#endif /* XP_UNIX */
+ /* other fields follow... */
+};
+
+/******************************************************************************/
+
+/*
+** Returns the event queue associated with the main thread.
+**
+*/
+#if defined(XP_WIN) || defined(XP_OS2)
+/* -----------------------------------------------------------------------
+** FUNCTION: PL_GetNativeEventReceiverWindow()
+**
+** DESCRIPTION:
+** PL_GetNativeEventReceiverWindow() returns the windows
+** handle of the event receiver window associated with the
+** referenced PLEventQueue argument.
+**
+** INPUTS:
+** PLEventQueue pointer
+**
+** RETURNS:
+** event receiver window handle.
+**
+** RESTRICTIONS: MS-Windows ONLY.
+**
+*/
+PR_EXTERN(HWND)
+ PL_GetNativeEventReceiverWindow(
+ PLEventQueue *eqp
+ );
+#endif /* XP_WIN || XP_OS2 */
+
+#ifdef XP_UNIX
+/* -----------------------------------------------------------------------
+** FUNCTION: PL_ProcessEventsBeforeID()
+**
+** DESCRIPTION:
+**
+** PL_ProcessEventsBeforeID() will process events in a native event
+** queue that have an id that is older than the ID passed in.
+**
+** INPUTS:
+** PLEventQueue *aSelf
+** unsigned long aID
+**
+** RETURNS:
+** PRInt32 number of requests processed, -1 on error.
+**
+** RESTRICTIONS: Unix only (well, X based unix only)
+*/
+PR_EXTERN(PRInt32)
+PL_ProcessEventsBeforeID(PLEventQueue *aSelf, unsigned long aID);
+
+/* This prototype is a function that can be called when an event is
+ posted to stick an ID on it. */
+
+typedef unsigned long
+(PR_CALLBACK *PLGetEventIDFunc)(void *aClosure);
+
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PL_RegisterEventIDFunc()
+**
+** DESCRIPTION:
+**
+** This function registers a function for getting the ID on unix for
+** this event queue.
+**
+** INPUTS:
+** PLEventQueue *aSelf
+** PLGetEventIDFunc func
+** void *aClosure
+**
+** RETURNS:
+** void
+**
+** RESTRICTIONS: Unix only (well, X based unix only) */
+PR_EXTERN(void)
+PL_RegisterEventIDFunc(PLEventQueue *aSelf, PLGetEventIDFunc aFunc,
+ void *aClosure);
+
+/* -----------------------------------------------------------------------
+** FUNCTION: PL_RegisterEventIDFunc()
+**
+** DESCRIPTION:
+**
+** This function unregisters a function for getting the ID on unix for
+** this event queue.
+**
+** INPUTS:
+** PLEventQueue *aSelf
+**
+** RETURNS:
+** void
+**
+** RESTRICTIONS: Unix only (well, X based unix only) */
+PR_EXTERN(void)
+PL_UnregisterEventIDFunc(PLEventQueue *aSelf);
+
+#endif /* XP_UNIX */
+
+
+/* ----------------------------------------------------------------------- */
+
+#if defined(NO_NSPR_10_SUPPORT)
+#else
+/********* ???????????????? FIX ME ??????????????????????????? *****/
+/********************** Some old definitions *****************************/
+
+/* Re: prevent.h->plevent.h */
+#define PREvent PLEvent
+#define PREventQueue PLEventQueue
+#define PR_CreateEventQueue PL_CreateEventQueue
+#define PR_DestroyEventQueue PL_DestroyEventQueue
+#define PR_GetEventQueueMonitor PL_GetEventQueueMonitor
+#define PR_ENTER_EVENT_QUEUE_MONITOR PL_ENTER_EVENT_QUEUE_MONITOR
+#define PR_EXIT_EVENT_QUEUE_MONITOR PL_EXIT_EVENT_QUEUE_MONITOR
+#define PR_PostEvent PL_PostEvent
+#define PR_PostSynchronousEvent PL_PostSynchronousEvent
+#define PR_GetEvent PL_GetEvent
+#define PR_EventAvailable PL_EventAvailable
+#define PREventFunProc PLEventFunProc
+#define PR_MapEvents PL_MapEvents
+#define PR_RevokeEvents PL_RevokeEvents
+#define PR_ProcessPendingEvents PL_ProcessPendingEvents
+#define PR_WaitForEvent PL_WaitForEvent
+#define PR_EventLoop PL_EventLoop
+#define PR_GetEventQueueSelectFD PL_GetEventQueueSelectFD
+#define PRHandleEventProc PLHandleEventProc
+#define PRDestroyEventProc PLDestroyEventProc
+#define PR_InitEvent PL_InitEvent
+#define PR_GetEventOwner PL_GetEventOwner
+#define PR_HandleEvent PL_HandleEvent
+#define PR_DestroyEvent PL_DestroyEvent
+#define PR_DequeueEvent PL_DequeueEvent
+#define PR_GetMainEventQueue PL_GetMainEventQueue
+
+/********* ????????????? End Fix me ?????????????????????????????? *****/
+#endif /* NO_NSPR_10_SUPPORT */
+
+PR_END_EXTERN_C
+
+#endif /* plevent_h___ */