Bug 900047 - remove nsIOThreadPool code; r=jduell

This commit is contained in:
Nathan Froyd 2013-07-31 12:04:47 -04:00
parent 34261dd495
commit 8f04d5ed49
2 changed files with 0 additions and 295 deletions

View File

@ -1,281 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIEventTarget.h"
#include "nsIServiceManager.h"
#include "nsIObserverService.h"
#include "nsIObserver.h"
#include "nsAutoLock.h"
#include "nsCOMPtr.h"
#include "prclist.h"
#include "prlog.h"
#if defined(PR_LOGGING)
//
// NSPR_LOG_MODULES=nsIOThreadPool:5
//
static PRLogModuleInfo *gIOThreadPoolLog = nullptr;
#endif
#define LOG(args) PR_LOG(gIOThreadPoolLog, PR_LOG_DEBUG, args)
// this number specifies the maximum number of threads.
#define MAX_THREADS 4
// this number specifies how long to wait before killing an idle thread. it's
// important to pick a large enough value here to minimize thread churn.
#define IDLE_TIMEOUT PR_SecondsToInterval(60)
#define PLEVENT_FROM_LINK(_link) \
((PLEvent*) ((char*) (_link) - offsetof(PLEvent, link)))
//-----------------------------------------------------------------------------
// pool of joinable threads used for general purpose i/o tasks
//
// the main entry point to this class is nsIEventTarget. events posted to
// the thread pool are dispatched on one of the threads. a variable number
// of threads are maintained. the threads die off if they remain idle for
// more than THREAD_IDLE_TIMEOUT. the thread pool shuts down when it receives
// the "xpcom-shutdown-threads" event.
//-----------------------------------------------------------------------------
class nsIOThreadPool : public nsIEventTarget
, public nsIObserver
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIEVENTTARGET
NS_DECL_NSIOBSERVER
nsresult Init();
void Shutdown();
private:
virtual ~nsIOThreadPool();
static void ThreadFunc(void *);
// mLock protects all (exceptions during Init and Shutdown)
PRLock *mLock;
PRCondVar *mIdleThreadCV; // notified to wake up an idle thread
PRCondVar *mExitThreadCV; // notified when a thread exits
uint32_t mNumThreads; // number of active + idle threads
uint32_t mNumIdleThreads; // number of idle threads
PRCList mEventQ; // queue of PLEvent structs
bool mShutdown; // set to true if shutting down
nsThreadPoolNaming mNaming; // thread name numbering
};
NS_IMPL_ISUPPORTS2(nsIOThreadPool, nsIEventTarget, nsIObserver)
nsresult
nsIOThreadPool::Init()
{
#if defined(PR_LOGGING)
if (!gIOThreadPoolLog)
gIOThreadPoolLog = PR_NewLogModule("nsIOThreadPool");
#endif
mNumThreads = 0;
mNumIdleThreads = 0;
mShutdown = false;
mLock = nsAutoLock::NewLock("nsIOThreadPool::mLock");
if (!mLock)
return NS_ERROR_OUT_OF_MEMORY;
mIdleThreadCV = PR_NewCondVar(mLock);
if (!mIdleThreadCV)
return NS_ERROR_OUT_OF_MEMORY;
mExitThreadCV = PR_NewCondVar(mLock);
if (!mExitThreadCV)
return NS_ERROR_OUT_OF_MEMORY;
PR_INIT_CLIST(&mEventQ);
// We want to shutdown the i/o thread pool at xpcom-shutdown-threads time.
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os)
os->AddObserver(this, "xpcom-shutdown-threads", false);
return NS_OK;
}
nsIOThreadPool::~nsIOThreadPool()
{
LOG(("Destroying nsIOThreadPool @%p\n", this));
#ifdef DEBUG
NS_ASSERTION(PR_CLIST_IS_EMPTY(&mEventQ), "leaking events");
NS_ASSERTION(mNumThreads == 0, "leaking thread(s)");
#endif
if (mIdleThreadCV)
PR_DestroyCondVar(mIdleThreadCV);
if (mExitThreadCV)
PR_DestroyCondVar(mExitThreadCV);
if (mLock)
nsAutoLock::DestroyLock(mLock);
}
void
nsIOThreadPool::Shutdown()
{
LOG(("nsIOThreadPool::Shutdown\n"));
// synchronize with background threads...
{
nsAutoLock lock(mLock);
mShutdown = true;
PR_NotifyAllCondVar(mIdleThreadCV);
while (mNumThreads != 0)
PR_WaitCondVar(mExitThreadCV, PR_INTERVAL_NO_TIMEOUT);
}
}
NS_IMETHODIMP
nsIOThreadPool::PostEvent(PLEvent *event)
{
LOG(("nsIOThreadPool::PostEvent [event=%p]\n", event));
nsAutoLock lock(mLock);
// if we are shutting down, then prevent additional events from being
// added to the queue...
if (mShutdown)
return NS_ERROR_UNEXPECTED;
nsresult rv = NS_OK;
PR_APPEND_LINK(&event->link, &mEventQ);
// now, look for an available idle thread...
if (mNumIdleThreads)
PR_NotifyCondVar(mIdleThreadCV); // wake up an idle thread
// or, try to create a new thread unless we have reached our maximum...
else if (mNumThreads < MAX_THREADS) {
NS_ADDREF_THIS(); // the thread owns a reference to us
mNumThreads++;
PRThread *thread = PR_CreateThread(PR_USER_THREAD,
ThreadFunc,
this,
PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD,
PR_UNJOINABLE_THREAD,
0);
if (!thread) {
NS_RELEASE_THIS();
mNumThreads--;
rv = NS_ERROR_OUT_OF_MEMORY;
}
}
// else, we expect one of the active threads to process the event queue.
return rv;
}
NS_IMETHODIMP
nsIOThreadPool::IsOnCurrentThread(bool *result)
{
// no one should be calling this method. if this assertion gets hit,
// then we need to think carefully about what this method should be
// returning.
NS_NOTREACHED("nsIOThreadPool::IsOnCurrentThread");
// fudging this a bit since we actually cover several threads...
*result = false;
return NS_OK;
}
NS_IMETHODIMP
nsIOThreadPool::Observe(nsISupports *, const char *topic, const PRUnichar *)
{
NS_ASSERTION(strcmp(topic, "xpcom-shutdown-threads") == 0, "unexpected topic");
Shutdown();
return NS_OK;
}
void
nsIOThreadPool::ThreadFunc(void *arg)
{
nsIOThreadPool *pool = (nsIOThreadPool *) arg;
pool->mNaming.SetThreadPoolName("IO Thread");
LOG(("entering ThreadFunc\n"));
{
nsAutoLock lock(pool->mLock);
for (;;) {
PRIntervalTime start = PR_IntervalNow(), timeout = IDLE_TIMEOUT;
//
// wait for one or more of the following to occur:
// (1) the event queue has an event to process
// (2) the shutdown flag has been set
// (3) the thread has been idle for too long
//
// PR_WaitCondVar will return when any of these conditions is true.
//
while (PR_CLIST_IS_EMPTY(&pool->mEventQ) && !pool->mShutdown) {
pool->mNumIdleThreads++;
PR_WaitCondVar(pool->mIdleThreadCV, timeout);
pool->mNumIdleThreads--;
PRIntervalTime delta = PR_IntervalNow() - start;
if (delta >= timeout)
break;
timeout -= delta;
start += delta;
}
// if the queue is still empty, then kill this thread (either we
// are shutting down or the thread exceeded the idle timeout)...
if (PR_CLIST_IS_EMPTY(&pool->mEventQ))
break;
// handle one event at a time: we don't want this one thread to hog
// all the events while other threads may be able to help out ;-)
do {
PLEvent *event = PLEVENT_FROM_LINK(PR_LIST_HEAD(&pool->mEventQ));
PR_REMOVE_AND_INIT_LINK(&event->link);
LOG(("event:%p\n", event));
// release lock!
lock.unlock();
PL_HandleEvent(event);
lock.lock();
}
while (!PR_CLIST_IS_EMPTY(&pool->mEventQ));
}
// thread is going away...
pool->mNumThreads--;
PR_NotifyCondVar(pool->mExitThreadCV);
}
// release our reference to the pool
NS_RELEASE(pool);
LOG(("leaving ThreadFunc\n"));
}
//-----------------------------------------------------------------------------
NS_METHOD
net_NewIOThreadPool(nsISupports *outer, REFNSIID iid, void **result)
{
nsIOThreadPool *pool = new nsIOThreadPool();
if (!pool)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(pool);
nsresult rv = pool->Init();
if (NS_SUCCEEDED(rv))
rv = pool->QueryInterface(iid, result);
NS_RELEASE(pool);
return rv;
}

View File

@ -1,14 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsIOThreadPool_h__
#define nsIOThreadPool_h__
/**
* XPCOM constructor for nsIOThreadPool
*/
NS_METHOD NS_HIDDEN
net_NewIOThreadPool(nsISupports *outer, REFNSIID iid, void **result);
#endif // nsIOThreadPool_h__