From faa62fcf4b72dfc9dca412c65aa97d193679f4af Mon Sep 17 00:00:00 2001 From: "darin%meer.net" Date: Wed, 15 Feb 2006 01:41:49 +0000 Subject: [PATCH] landing support for thread pools git-svn-id: svn://10.0.0.236/branches/THREADS_20060213_BRANCH@190050 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/xpcom/build/nsXPCOMCID.h | 10 + mozilla/xpcom/build/nsXPComInit.cpp | 7 +- mozilla/xpcom/tests/Makefile.in | 1 + mozilla/xpcom/tests/TestThreadPool.cpp | 49 ++++ mozilla/xpcom/threads/Makefile.in | 2 + mozilla/xpcom/threads/nsIThread.idl | 3 +- mozilla/xpcom/threads/nsIThreadManager.idl | 6 +- mozilla/xpcom/threads/nsIThreadPool.idl | 73 ++++++ mozilla/xpcom/threads/nsTaskQueue.cpp | 2 +- mozilla/xpcom/threads/nsTaskQueue.h | 5 + mozilla/xpcom/threads/nsThread.cpp | 23 -- mozilla/xpcom/threads/nsThread.h | 23 ++ mozilla/xpcom/threads/nsThreadManager.cpp | 25 +- mozilla/xpcom/threads/nsThreadManager.h | 1 - mozilla/xpcom/threads/nsThreadPool.cpp | 271 +++++++++++++++++++++ mozilla/xpcom/threads/nsThreadPool.h | 82 +++++++ 16 files changed, 544 insertions(+), 39 deletions(-) create mode 100644 mozilla/xpcom/tests/TestThreadPool.cpp create mode 100644 mozilla/xpcom/threads/nsIThreadPool.idl create mode 100644 mozilla/xpcom/threads/nsThreadPool.cpp create mode 100644 mozilla/xpcom/threads/nsThreadPool.h diff --git a/mozilla/xpcom/build/nsXPCOMCID.h b/mozilla/xpcom/build/nsXPCOMCID.h index 4920322c401..7d2a6f75785 100644 --- a/mozilla/xpcom/build/nsXPCOMCID.h +++ b/mozilla/xpcom/build/nsXPCOMCID.h @@ -181,4 +181,14 @@ { 0xb9, 0xb8, 0xc8, 0x11, 0x75, 0x95, 0x51, 0x99 } } #define NS_HASH_PROPERTY_BAG_CONTRACTID "@mozilla.org/hash-property-bag;1" +/** + * Implementation of nsIThreadManager + */ +#define NS_THREADMANAGER_CONTRACTID "@mozilla.org/thread-manager;1" + +/** + * Implementation of nsIThreadPool + */ +#define NS_THREADPOOL_CONTRACTID "@mozilla.org/thread-pool;1" + #endif diff --git a/mozilla/xpcom/build/nsXPComInit.cpp b/mozilla/xpcom/build/nsXPComInit.cpp index cae448b97d7..15b1c8c2bc1 100644 --- a/mozilla/xpcom/build/nsXPComInit.cpp +++ b/mozilla/xpcom/build/nsXPComInit.cpp @@ -72,6 +72,7 @@ #include "nsGenericFactory.h" #include "nsThreadManager.h" +#include "nsThreadPool.h" #include "nsIProxyObjectManager.h" #include "nsProxyEventPrivate.h" // access to the impl of nsProxyObjectManager for the generic factory registration. @@ -226,7 +227,9 @@ nsThreadManagerGetSingleton(nsISupports* outer, return nsThreadManager::get()->QueryInterface(aIID, aInstancePtr); } NS_DECL_CLASSINFO(nsThreadManager) -NS_DECL_CLASSINFO(nsThread) + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsThreadPool) +NS_DECL_CLASSINFO(nsThreadPool) static NS_METHOD nsXPTIInterfaceInfoManagerGetSingleton(nsISupports* outer, @@ -399,6 +402,8 @@ static const nsModuleComponentInfo components[] = { COMPONENT_CI_FLAGS(THREADMANAGER, nsThreadManagerGetSingleton, nsThreadManager, nsIClassInfo::THREADSAFE | nsIClassInfo::SINGLETON), + COMPONENT_CI_FLAGS(THREADPOOL, nsThreadPoolConstructor, + nsThreadPool, nsIClassInfo::THREADSAFE), COMPONENT_CI_FLAGS(STRINGINPUTSTREAM, nsStringInputStreamConstructor, nsStringInputStream, nsIClassInfo::THREADSAFE), diff --git a/mozilla/xpcom/tests/Makefile.in b/mozilla/xpcom/tests/Makefile.in index 2e425474000..40ae0bbc763 100644 --- a/mozilla/xpcom/tests/Makefile.in +++ b/mozilla/xpcom/tests/Makefile.in @@ -84,6 +84,7 @@ CPPSRCS += \ TestPermanentAtoms.cpp \ TestPipes.cpp \ TestThreads.cpp \ + TestThreadPool.cpp \ TestXPIDLString.cpp \ TestDeque.cpp \ TestStrings.cpp \ diff --git a/mozilla/xpcom/tests/TestThreadPool.cpp b/mozilla/xpcom/tests/TestThreadPool.cpp new file mode 100644 index 00000000000..4c708e0c54a --- /dev/null +++ b/mozilla/xpcom/tests/TestThreadPool.cpp @@ -0,0 +1,49 @@ +#include +#include "nsXPCOM.h" +#include "nsIThreadPool.h" +#include "nsComponentManagerUtils.h" +#include "nsCOMPtr.h" +#include "nsIRunnable.h" + +class Task : public nsIRunnable +{ +public: + NS_DECL_ISUPPORTS + + Task(int i) : mIndex(i) {} + + NS_IMETHOD Run() + { + printf("###(%d) running from thread: %p\n", mIndex, (void *) PR_GetCurrentThread()); + PR_Sleep(PR_MillisecondsToInterval(50)); + return NS_OK; + } + +private: + int mIndex; +}; +NS_IMPL_THREADSAFE_ISUPPORTS1(Task, nsIRunnable) + +static nsresult +RunTests() +{ + nsCOMPtr pool = do_CreateInstance(NS_THREADPOOL_CONTRACTID); + NS_ENSURE_STATE(pool); + + for (int i = 0; i < 100; ++i) { + nsCOMPtr task = new Task(i); + pool->Dispatch(task, NS_DISPATCH_NORMAL); + } + + pool->Shutdown(); + return NS_OK; +} + +int +main(int argc, char **argv) +{ + NS_InitXPCOM2(nsnull, nsnull, nsnull); + RunTests(); + NS_ShutdownXPCOM(nsnull); + return 0; +} diff --git a/mozilla/xpcom/threads/Makefile.in b/mozilla/xpcom/threads/Makefile.in index 21e73ff2710..0590c7acf4d 100644 --- a/mozilla/xpcom/threads/Makefile.in +++ b/mozilla/xpcom/threads/Makefile.in @@ -62,6 +62,7 @@ CPPSRCS = \ nsRunnable.cpp \ nsThread.cpp \ nsThreadManager.cpp \ + nsThreadPool.cpp \ nsProcessCommon.cpp \ nsTimerImpl.cpp \ TimerThread.cpp \ @@ -79,6 +80,7 @@ XPIDLSRCS = \ nsIThread.idl \ nsIThreadInternal.idl \ nsIThreadManager.idl \ + nsIThreadPool.idl \ nsITimer.idl \ nsITimerInternal.idl \ nsITimerManager.idl \ diff --git a/mozilla/xpcom/threads/nsIThread.idl b/mozilla/xpcom/threads/nsIThread.idl index a701c297098..0d5e66fb2f6 100644 --- a/mozilla/xpcom/threads/nsIThread.idl +++ b/mozilla/xpcom/threads/nsIThread.idl @@ -42,7 +42,8 @@ interface nsIThread : nsIDispatchTarget { /** - * Returns the name of the thread. + * Returns the name of the thread, which may be empty if this thread is + * anonymous. */ readonly attribute ACString name; diff --git a/mozilla/xpcom/threads/nsIThreadManager.idl b/mozilla/xpcom/threads/nsIThreadManager.idl index 082c5600d45..23551734eb8 100644 --- a/mozilla/xpcom/threads/nsIThreadManager.idl +++ b/mozilla/xpcom/threads/nsIThreadManager.idl @@ -44,8 +44,10 @@ interface nsIThread; interface nsIThreadManager : nsISupports { /** - * Create a new named thread (a global, user PRThread). The name - * must be unique. + * Create a new named thread (a global, user PRThread). If the name is + * non-empty, then the name of the thread must be unique. Specifying an + * empty name results in an anonymous thread that cannot be found later on + * using the getThread method. */ nsIThread newThread(in ACString name); diff --git a/mozilla/xpcom/threads/nsIThreadPool.idl b/mozilla/xpcom/threads/nsIThreadPool.idl new file mode 100644 index 00000000000..6894e2858bf --- /dev/null +++ b/mozilla/xpcom/threads/nsIThreadPool.idl @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 code. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsIDispatchTarget.idl" + +/** + * An interface to a thread pool. A thread pool creates a limited number of + * anonymous (unnamed) worker threads. A task dispatched to the thread pool + * will be run on the next available worker thread. + */ +[scriptable, uuid(394c29f0-225f-487f-86d3-4c259da76cab)] +interface nsIThreadPool : nsIDispatchTarget +{ + /** + * Shutdown the thread pool. This method may not be executed from any thread + * in the thread pool. Instead, it is meant to be executed from another + * thread (usually the thread that created this thread pool). When this + * function returns, the thread pool and all of its threads will be shutdown, + * and it will no longer be possible to dispatch tasks to the thread pool. + */ + void shutdown(); + + /** + * Get/set the maximum number of threads allowed at one time in this pool. + */ + attribute unsigned long threadLimit; + + /** + * Get/set the maximum number of idle threads kept alive. + */ + attribute unsigned long idleThreadLimit; + + /** + * Get/set the amount of time in milliseconds before an idle thread is + * destroyed. + */ + attribute unsigned long idleThreadTimeout; +}; diff --git a/mozilla/xpcom/threads/nsTaskQueue.cpp b/mozilla/xpcom/threads/nsTaskQueue.cpp index 12b5bb17cad..11572a82a31 100644 --- a/mozilla/xpcom/threads/nsTaskQueue.cpp +++ b/mozilla/xpcom/threads/nsTaskQueue.cpp @@ -113,7 +113,7 @@ nsTaskQueue::PutTask(nsIRunnable *runnable) if (rv) { task.swap(mTail->mTasks[mOffsetTail]); ++mOffsetTail; - mon.Notify(); + mon.NotifyAll(); } } return rv; diff --git a/mozilla/xpcom/threads/nsTaskQueue.h b/mozilla/xpcom/threads/nsTaskQueue.h index 7c4216ed0e9..8f7b677e8ad 100644 --- a/mozilla/xpcom/threads/nsTaskQueue.h +++ b/mozilla/xpcom/threads/nsTaskQueue.h @@ -68,6 +68,11 @@ public: return GetPendingTask(PR_TRUE, runnable); } + // Expose the task queue's monitor for "power users" + PRMonitor *Monitor() { + return mMonitor; + } + private: PRBool GetPendingTask(PRBool wait, nsIRunnable **runnable); diff --git a/mozilla/xpcom/threads/nsThread.cpp b/mozilla/xpcom/threads/nsThread.cpp index f7fb83336e7..eee87a58720 100644 --- a/mozilla/xpcom/threads/nsThread.cpp +++ b/mozilla/xpcom/threads/nsThread.cpp @@ -38,7 +38,6 @@ #include "nsThread.h" #include "nsThreadManager.h" -#include "nsRunnable.h" #include "nsAutoLock.h" #include "nsAutoPtr.h" #include "nsCOMPtr.h" @@ -153,28 +152,6 @@ private: //----------------------------------------------------------------------------- -class nsThreadSyncDispatch : public nsRunnable { -public: - nsThreadSyncDispatch(nsIRunnable *task) - : mSyncTask(task) { - } - - NS_IMETHODIMP Run() { - mSyncTask->Run(); - mSyncTask = nsnull; - return NS_OK; - } - - PRBool IsPending() { - return mSyncTask != nsnull; - } - -private: - nsCOMPtr mSyncTask; -}; - -//----------------------------------------------------------------------------- - // This class is used to convey initialization info to the newly created thread. class nsThreadStartup : public nsRunnable { public: diff --git a/mozilla/xpcom/threads/nsThread.h b/mozilla/xpcom/threads/nsThread.h index d005efcd82d..2d90c302bc5 100644 --- a/mozilla/xpcom/threads/nsThread.h +++ b/mozilla/xpcom/threads/nsThread.h @@ -42,6 +42,7 @@ #include "nsIThreadInternal.h" #include "nsISupportsPriority.h" #include "nsTaskQueue.h" +#include "nsRunnable.h" #include "nsString.h" #include "nsCOMPtr.h" @@ -83,4 +84,26 @@ private: PRIntn mActive; }; +//----------------------------------------------------------------------------- + +class nsThreadSyncDispatch : public nsRunnable { +public: + nsThreadSyncDispatch(nsIRunnable *task) + : mSyncTask(task) { + } + + NS_IMETHODIMP Run() { + mSyncTask->Run(); + mSyncTask = nsnull; + return NS_OK; + } + + PRBool IsPending() { + return mSyncTask != nsnull; + } + +private: + nsCOMPtr mSyncTask; +}; + #endif // nsThread_h__ diff --git a/mozilla/xpcom/threads/nsThreadManager.cpp b/mozilla/xpcom/threads/nsThreadManager.cpp index ddf3d971a38..3effb4719c7 100644 --- a/mozilla/xpcom/threads/nsThreadManager.cpp +++ b/mozilla/xpcom/threads/nsThreadManager.cpp @@ -141,6 +141,10 @@ nsThreadManager::NewThread(const nsACString &name, nsIThread **result) NS_IMETHODIMP nsThreadManager::GetThread(const nsACString &name, nsIThread **result) { + if (name.IsEmpty()) { + *result = nsnull; + return NS_OK; + } mThreads.Get(name, result); return NS_OK; } @@ -174,21 +178,22 @@ nsThreadManager::SetCurrentThread(nsIThread *thread, nsIThread **result) nsCString name; if (thread) { thread->GetName(name); + if (!name.IsEmpty()) { + // make sure thread name is unique + nsCOMPtr temp; + GetThread(name, getter_AddRefs(temp)); - // make sure thread name is unique - nsCOMPtr temp; - GetThread(name, getter_AddRefs(temp)); - - if (temp && temp != curr) { - NS_NOTREACHED("thread name is not unique"); - return NS_ERROR_INVALID_ARG; + if (temp && temp != curr) { + NS_NOTREACHED("thread name is not unique"); + return NS_ERROR_INVALID_ARG; + } + mThreads.Put(name, thread); } - mThreads.Put(name, thread); - NS_ADDREF(thread); // for TLS entry } else { curr->GetName(name); - mThreads.Remove(name); + if (!name.IsEmpty()) + mThreads.Remove(name); } // write thread local storage diff --git a/mozilla/xpcom/threads/nsThreadManager.h b/mozilla/xpcom/threads/nsThreadManager.h index cc483f577d5..93cbf04469d 100644 --- a/mozilla/xpcom/threads/nsThreadManager.h +++ b/mozilla/xpcom/threads/nsThreadManager.h @@ -86,7 +86,6 @@ private: }; #define NS_THREADMANAGER_CLASSNAME "nsThreadManager" -#define NS_THREADMANAGER_CONTRACTID "@mozilla.org/thread-manager;1" #define NS_THREADMANAGER_CID \ { /* 7a4204c6-e45a-4c37-8ebb-6709a22c917c */ \ 0x7a4204c6, \ diff --git a/mozilla/xpcom/threads/nsThreadPool.cpp b/mozilla/xpcom/threads/nsThreadPool.cpp new file mode 100644 index 00000000000..d185afc01de --- /dev/null +++ b/mozilla/xpcom/threads/nsThreadPool.cpp @@ -0,0 +1,271 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 code. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsThreadPool.h" +#include "nsThreadManager.h" +#include "nsThread.h" +#include "nsMemory.h" +#include "nsAutoPtr.h" +#include "nsAutoLock.h" +#include "prinrval.h" + +// DESIGN: +// o Allocate anonymous threads. +// o Use nsThreadPool::Run as the main routine for each thread. +// o Each thread waits on the task queue's monitor, checking for +// pending tasks and rescheduling itself as an idle thread. + +#define DEFAULT_THREAD_LIMIT 4 +#define DEFAULT_IDLE_THREAD_LIMIT 1 +#define DEFAULT_IDLE_THREAD_TIMEOUT PR_SecondsToInterval(60) + +NS_IMPL_THREADSAFE_ADDREF(nsThreadPool) +NS_IMPL_THREADSAFE_RELEASE(nsThreadPool) +NS_IMPL_QUERY_INTERFACE3_CI(nsThreadPool, nsIThreadPool, nsIDispatchTarget, + nsIRunnable) +NS_IMPL_CI_INTERFACE_GETTER2(nsThreadPool, nsIThreadPool, nsIDispatchTarget) + +nsThreadPool::nsThreadPool() + : mThreadLimit(DEFAULT_THREAD_LIMIT) + , mIdleThreadLimit(DEFAULT_IDLE_THREAD_LIMIT) + , mIdleThreadTimeout(DEFAULT_IDLE_THREAD_TIMEOUT) + , mIdleCount(0) + , mShutdown(PR_FALSE) +{ +} + +nsThreadPool::~nsThreadPool() +{ + Shutdown(); +} + +nsresult +nsThreadPool::PutTask(nsIRunnable *task) +{ + // Avoid spawning a new thread while holding the task queue lock... + + PRBool spawnThread = PR_FALSE; + { + nsAutoMonitor mon(mTasks.Monitor()); + // Make sure we have a thread to service this task. + if (mIdleCount == 0 && mThreads.Count() < (PRInt32) mThreadLimit) + spawnThread = PR_TRUE; + + mTasks.PutTask(task); + } + + if (!spawnThread) + return NS_OK; + + nsCOMPtr thread; + nsThreadManager::get()->NewThread(EmptyCString(), getter_AddRefs(thread)); + NS_ENSURE_STATE(thread); + + PRBool killThread = PR_FALSE; + { + nsAutoMonitor mon(mTasks.Monitor()); + if (mThreads.Count() < (PRInt32) mThreadLimit) { + mThreads.AppendObject(thread); + } else { + killThread = PR_TRUE; // okay, we don't need this thread anymore + } + } + if (killThread) { + thread->Shutdown(); + } else { + thread->Dispatch(this, NS_DISPATCH_NORMAL); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsThreadPool::Run() +{ + nsCOMPtr current; + nsThreadManager::get()->GetCurrentThread(getter_AddRefs(current)); + + PRBool exitThread = PR_FALSE; + PRBool wasIdle = PR_FALSE; + PRIntervalTime idleSince; + + do { + nsCOMPtr task; + { + nsAutoMonitor mon(mTasks.Monitor()); + if (!mTasks.GetPendingTask(getter_AddRefs(task))) { + PRIntervalTime now = PR_IntervalNow(); + PRIntervalTime timeout = PR_MillisecondsToInterval(mIdleThreadTimeout); + + // If we are shutting down, then don't keep any idle threads + if (mShutdown) { + exitThread = PR_TRUE; + } else { + if (wasIdle) { + // if too many idle threads or idle for too long, then bail. + if (mIdleCount > mIdleThreadLimit || (now - idleSince) > timeout) { + --mIdleCount; + exitThread = PR_TRUE; + } + } else { + // if would be too many idle threads... + if (mIdleCount == mIdleThreadLimit) { + exitThread = PR_TRUE; + } else { + ++mIdleCount; + idleSince = now; + wasIdle = PR_TRUE; + } + } + } + + if (exitThread) { + mThreads.RemoveObject(current); + } else { + mon.Wait(timeout - (now - idleSince)); + } + } + } + if (task) { + wasIdle = PR_FALSE; + task->Run(); + } + } while (!exitThread); + + return NS_OK; +} + +NS_IMETHODIMP +nsThreadPool::Dispatch(nsIRunnable *task, PRUint32 flags) +{ + NS_ENSURE_STATE(!mShutdown); + + if (flags == DISPATCH_NORMAL) { + PutTask(task); + } else if (flags & DISPATCH_SYNC) { + nsCOMPtr thread; + nsThreadManager::get()->GetCurrentThread(getter_AddRefs(thread)); + NS_ENSURE_STATE(thread); + + nsRefPtr wrapper = new nsThreadSyncDispatch(task); + PutTask(wrapper); + + while (wrapper->IsPending()) + thread->RunNextTask(nsIThread::RUN_NORMAL); + } + return NS_OK; +} + +NS_IMETHODIMP +nsThreadPool::IsOnCurrentThread(PRBool *result) +{ + *result = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP +nsThreadPool::Shutdown() +{ + nsCOMArray threads; + { + nsAutoMonitor mon(mTasks.Monitor()); + mShutdown = PR_TRUE; + mon.NotifyAll(); + + threads.AppendObjects(mThreads); + } + + // It's important that we shutdown the threads while outside the task queue + // monitor. Otherwise, we could end up dead-locking. The threads will take + // care of removing themselves from mThreads as they exit. + + for (PRInt32 i = 0; i < threads.Count(); ++i) + threads[i]->Shutdown(); + + return NS_OK; +} + +NS_IMETHODIMP +nsThreadPool::GetThreadLimit(PRUint32 *value) +{ + *value = mThreadLimit; + return NS_OK; +} + +NS_IMETHODIMP +nsThreadPool::SetThreadLimit(PRUint32 value) +{ + nsAutoMonitor mon(mTasks.Monitor()); + mThreadLimit = value; + if (mIdleThreadLimit > mThreadLimit) + mIdleThreadLimit = mThreadLimit; + mon.NotifyAll(); // wake up threads so they observe this change + return NS_OK; +} + +NS_IMETHODIMP +nsThreadPool::GetIdleThreadLimit(PRUint32 *value) +{ + *value = mIdleThreadLimit; + return NS_OK; +} + +NS_IMETHODIMP +nsThreadPool::SetIdleThreadLimit(PRUint32 value) +{ + nsAutoMonitor mon(mTasks.Monitor()); + mIdleThreadLimit = value; + mon.NotifyAll(); // wake up threads so they observe this change + return NS_OK; +} + +NS_IMETHODIMP +nsThreadPool::GetIdleThreadTimeout(PRUint32 *value) +{ + *value = mIdleThreadTimeout; + return NS_OK; +} + +NS_IMETHODIMP +nsThreadPool::SetIdleThreadTimeout(PRUint32 value) +{ + nsAutoMonitor mon(mTasks.Monitor()); + mIdleThreadTimeout = value; + mon.NotifyAll(); // wake up threads so they observe this change + return NS_OK; +} diff --git a/mozilla/xpcom/threads/nsThreadPool.h b/mozilla/xpcom/threads/nsThreadPool.h new file mode 100644 index 00000000000..331619235f3 --- /dev/null +++ b/mozilla/xpcom/threads/nsThreadPool.h @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 code. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsThreadPool_h__ +#define nsThreadPool_h__ + +#include "nsIThreadPool.h" +#include "nsIThread.h" +#include "nsIRunnable.h" +#include "nsTaskQueue.h" +#include "nsCOMArray.h" + +class nsThreadPool : public nsIThreadPool, public nsIRunnable +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIDISPATCHTARGET + NS_DECL_NSITHREADPOOL + NS_DECL_NSIRUNNABLE + + nsThreadPool(); + +private: + ~nsThreadPool(); + + nsresult PutTask(nsIRunnable *task); + + nsCOMArray mThreads; + nsTaskQueue mTasks; + PRUint32 mThreadLimit; + PRUint32 mIdleThreadLimit; + PRUint32 mIdleThreadTimeout; + PRUint32 mIdleCount; + PRBool mShutdown; +}; + +#define NS_THREADPOOL_CLASSNAME "nsThreadPool" +#define NS_THREADPOOL_CID \ +{ /* 547ec2a8-315e-4ec4-888e-6e4264fe90eb */ \ + 0x547ec2a8, \ + 0x315e, \ + 0x4ec4, \ + {0x88, 0x8e, 0x6e, 0x42, 0x64, 0xfe, 0x90, 0xeb} \ +} + + +#endif // nsThreadPool_h__