UIThreadPool.cpp revision 12cbe990234bb127e4e4d2ab6c98511304193889
/* $Id$ */
/** @file
* VBox Qt GUI - UIThreadPool and UITask class implementation.
*/
/*
* Copyright (C) 2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/* Qt includes: */
#include <QThread>
/* GUI includes: */
#include "COMDefs.h"
#include "UIThreadPool.h"
/* Other VBox defines: */
#define LOG_GROUP LOG_GROUP_GUI
/* Other VBox includes: */
/**
* COM capable worker thread for the UIThreadPool.
*/
class UIThreadWorker : public QThread
{
/* Notifier: Worker stuff: */
public:
/* Constructor: */
/** Disables sigFinished. For optimizing pool termination. */
void setNoFinishedSignal()
{
m_fNoFinishedSignal = true;
}
private:
/* Helper: Worker stuff: */
void run();
/* Variables: General stuff: */
/** The index into UIThreadPool::m_workers. */
int m_iIndex;
/** Indicates whether sigFinished should be emitted or not. */
bool m_fNoFinishedSignal;
};
, m_cWorkers(0)
, m_cIdleWorkers(0)
, m_fTerminating(false) /* termination status */
{
}
{
/* Set termination status and alert all idle worker threads: */
/* Cleanup all the workers: */
{
/* Clean up the worker, if there was one. */
if (pWorker)
{
m_cWorkers--;
delete pWorker;
}
}
}
{
Assert(!isTerminating());
/* Prepare task: */
connect(pTask, SIGNAL(sigComplete(UITask*)), this, SLOT(sltHandleTaskComplete(UITask*)), Qt::QueuedConnection);
/* Put the task onto the queue: */
/* Wake up an idle worker if we got one: */
if (m_cIdleWorkers > 0)
{
}
/* No idle worker threads, should we create a new one? */
{
/* Find free slot: */
while (idxFirstUnused-- > 0)
{
/* Prepare the new worker: */
m_cWorkers++;
/* And start it: */
break;
}
}
/* else: wait for some worker to complete whatever it's busy with and jump to it. */
}
/**
* Checks if the thread pool is terminating.
*
* @returns @c true if terminating, @c false if not.
* @note Do NOT call this while owning the thread pool mutex!
*/
bool UIThreadPool::isTerminating() const
{
/* Acquire termination-flag: */
bool fTerminating = m_fTerminating;
return fTerminating;
}
void UIThreadPool::setTerminating()
{
/* Indicate that we're terminating: */
m_fTerminating = true;
/* Tell all threads to NOT queue any termination signals: */
{
if (pWorker)
}
/* Wake up all idle worker threads: */
}
{
/* Dequeue a task, watching out for terminations.
* For opimal efficiency in enqueueTask() we keep count of idle threads.
* If the wait times out, we'll return NULL and terminate the thread. */
bool fIdleTimedOut = false;
while (!m_fTerminating)
{
/* Dequeue task if there is one: */
{
if (pTask)
{
return pTask;
}
}
/* If we timed out already, then quit the worker thread. To prevent a
race between enqueueTask and the queue removal of the thread from
the workers vector, we remove it here already. (This does not apply
to the termination scenario.) */
if (fIdleTimedOut)
{
m_cWorkers--;
break;
}
/* Wait for a task or timeout.*/
}
return NULL;
}
{
/* Skip on termination: */
if (isTerminating())
return;
/* Notify listener: */
}
{
/* Wait for the thread to finish completely, then delete the thread
object. We have already removed the thread from the workers vector.
Note! We don't want to use 'this' here, in case it's invalid. */
delete pWorker;
}
{
}
{
return m_data;
}
{
/* Run task: */
run();
/* Notify listener: */
emit sigComplete(this);
}
, m_fNoFinishedSignal(false)
{
}
void UIThreadWorker::run()
{
/* Initialize COM: */
COMBase::InitializeCOM(false);
/* Try get a task from the pool queue. */
{
/* Process the task if we are not terminating.
* Please take into account tasks are cleared by their creator. */
if (!m_pPool->isTerminating())
}
/* Cleanup COM: */
COMBase::CleanupCOM();
/* Queue a signal to for the pool to do thread cleanup, unless the pool is
already terminating and doesn't need the signal. */
if (!m_fNoFinishedSignal)
emit sigFinished(this);
}
#include "UIThreadPool.moc"