Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Toshihiro Shimizu 890ddd
#define _STLP_DEBUG 1
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tthreadmessage.h"
Toshihiro Shimizu 890ddd
#include "tsystem.h"
Toshihiro Shimizu 890ddd
#include "tatomicvar.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tthread.h"
Campbell Barton d0e335
#include "tthreadp.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// STL includes
Toshihiro Shimizu 890ddd
#include <set></set>
Toshihiro Shimizu 890ddd
#include <deque></deque>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// tcg includes
Toshihiro Shimizu 890ddd
#include "tcg/tcg_pool.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Qt includes
Toshihiro Shimizu 890ddd
#include <qmultimap></qmultimap>
Toshihiro Shimizu 890ddd
#include <qmutablemapiterator></qmutablemapiterator>
Toshihiro Shimizu 890ddd
#include <qmutex></qmutex>
Toshihiro Shimizu 890ddd
#include <qwaitcondition></qwaitcondition>
Toshihiro Shimizu 890ddd
#include <qmetatype></qmetatype>
Toshihiro Shimizu 890ddd
#include <qcoreapplication></qcoreapplication>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==================================================
Toshihiro Shimizu 890ddd
//    Paradigms of the Executor tasks management
Toshihiro Shimizu 890ddd
//--------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Basics:
Toshihiro Shimizu 890ddd
//  * Tasks added by Executors are always stored in a global QMultiMap first -
Toshihiro Shimizu 890ddd
//    ordering primarily being the schedulingPriority(), and insertion instant
Toshihiro Shimizu 890ddd
//    (implicit) when they have the same scheduling priority.
Toshihiro Shimizu 890ddd
//  * The QMultiMap needs to be reverse-iterated to do that, since values with
Toshihiro Shimizu 890ddd
//    the same key are ordered from the most recent to the oldest one (see Qt's
Toshihiro Shimizu 890ddd
//    manual).
Toshihiro Shimizu 890ddd
//  * Worker threads are stored in a global set.
Toshihiro Shimizu 890ddd
//  * When a task is added or a task has been performed, the workers list is
Toshihiro Shimizu 890ddd
//    refreshed, possibly adding new Workers for some executable tasks.
Toshihiro Shimizu 890ddd
//  * When a worker ends a task, it automatically takes a new one before refreshing
Toshihiro Shimizu 890ddd
//    the workers list. If no task can be taken, by default the thread exits and
Toshihiro Shimizu 890ddd
//    invokes its own destruction.
Toshihiro Shimizu 890ddd
//  * The thread may instead be put to rest if explicitly told by the user with
Toshihiro Shimizu 890ddd
//    the appropriate method.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Default execution conditions:
Toshihiro Shimizu 890ddd
//  * A task is executable if, by default, its task load added to the sum of that of
Toshihiro Shimizu 890ddd
//    all other active tasks does not exceed the available resources of the system
Toshihiro Shimizu 890ddd
//    (i.e.: 100 * # of cores of the machine).
Toshihiro Shimizu 890ddd
//    In other words, in every instant of execution, the sum of all active task's loads
Toshihiro Shimizu 890ddd
//    never exceeds the available machine resources.
Toshihiro Shimizu 890ddd
//  * When such default execution condition is not met when attempting to take the
Toshihiro Shimizu 890ddd
//    task, no other task is taken instead - we wait until enough resources have been
Toshihiro Shimizu 890ddd
//    freed before attempting to take the same task again.
Toshihiro Shimizu 890ddd
//    In other words, the default execution condition is *BLOCKING*.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Custom execution conditions:
Toshihiro Shimizu 890ddd
//  * The user may decide to impose more tight conditions for tasks added by a certain
Toshihiro Shimizu 890ddd
//    Executor. Let's call such conditions 'custom' conditions.
Toshihiro Shimizu 890ddd
//  * Custom conditions are always tested *AFTER* the default ones (on the same task).
Toshihiro Shimizu 890ddd
//    This is necessary to enforce the global scheduling priorities mechanism.
Toshihiro Shimizu 890ddd
//  * When no task of a certain executor is active, custom conditions are always considered
Toshihiro Shimizu 890ddd
//    satisfied.
Toshihiro Shimizu 890ddd
//  * If custom conditions are not met, we enqueue the task in an Executor-private queue
Toshihiro Shimizu 890ddd
//    for later execution and remove it from the global tasks queue - making it possible
Toshihiro Shimizu 890ddd
//    to perform other tasks before our custom-failed one (such operation will be called
Toshihiro Shimizu 890ddd
//    "ACCUMULATION").
Toshihiro Shimizu 890ddd
//    In other words, custom conditions are *NOT BLOCKING* among different Executors.
Toshihiro Shimizu 890ddd
//  * Tasks in the last task's Executor-private queue are always polled before those in
Toshihiro Shimizu 890ddd
//    the global queue by Workers which ended a task, and this is done in a *BLOCKING* way
Toshihiro Shimizu 890ddd
//    inside the same Executor.
Toshihiro Shimizu 890ddd
//  * When an Executor-private tasks queue is not empty, all the other tasks added by the
Toshihiro Shimizu 890ddd
//    same executor are scheduled in the queue.
Toshihiro Shimizu 890ddd
//    In other words, the order of execution is always that of global insertion, *inside
Toshihiro Shimizu 890ddd
//    the same executor*.
Toshihiro Shimizu 890ddd
//  * Tasks polled from an Executor-private queue (which therefore satisfied custom conditions)
Toshihiro Shimizu 890ddd
//    may still fail with default execution conditions. If that happens, we put the task
Toshihiro Shimizu 890ddd
//    back into the global queue with highest possible priority (timedOut) and the worker dies.
Toshihiro Shimizu 890ddd
//    Tasks with this special priority are polled *before every other task*. So, again, default
Toshihiro Shimizu 890ddd
//    conditions are *BLOCKING*.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Thread-safety:
Toshihiro Shimizu 890ddd
//  * Most of the following code is mutex-protected, altough it might seem not - indeed,
Toshihiro Shimizu 890ddd
//    only *one* mutex is locked and unlocked all of the time. This 'transition mutex' is
Toshihiro Shimizu 890ddd
//    the key to thread-safety: we're considered to lie in a 'transition state' if we are
Toshihiro Shimizu 890ddd
//    operating outside the run() of some task - which covers almost the totality of the code.
Toshihiro Shimizu 890ddd
//  * The transition mutex is *not* recursive. The reason is that threads con not wait on
Toshihiro Shimizu 890ddd
//    QWaitConditions if the mutex is recursive. That makes it necessary (and welcome) to put
Toshihiro Shimizu 890ddd
//    mutex lockers in strategic points of the code - in many low-level functions no mutex
Toshihiro Shimizu 890ddd
//    is locked *because some caller already did it before*. If you're modifying the code
Toshihiro Shimizu 890ddd
//    always trace back the callers of a function before inserting misleading mutex lockers.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==================
Toshihiro Shimizu 890ddd
//    TODO list
Toshihiro Shimizu 890ddd
//------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//  * Improve dedicated threads support: make sure that tasks added to a dedicated
Toshihiro Shimizu 890ddd
//    executor are directly moved to the accumulation queue. The setDedicatedThreads()
Toshihiro Shimizu 890ddd
//    method must therefore react accordingly.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//  * It could be possible to implement a dependency-based mechanism...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//  * Should the hosting thread wait for worker ones upon ExecutorImp destruction??
Toshihiro Shimizu 890ddd
//    It could be a problem on some forever-waiting tasks...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//  * Ricontrolla che con le ultime modifiche gli ExecutorId rimangano quando si passano
Toshihiro Shimizu 890ddd
//    i puntatori in takeTask e refreshAss..
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace TThread;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
DEFINE_CLASS_CODE(TThread::Runnable, 21)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================
Toshihiro Shimizu 890ddd
//    Global init() initializer function
Toshihiro Shimizu 890ddd
//------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TThread::init()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	Executor::init();
Toshihiro Shimizu 890ddd
	TThreadMessageDispatcher::init();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TThread::shutdown()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	Executor::shutdown();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace TThread
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===========================
Toshihiro Shimizu 890ddd
//    Worker Thread class
Toshihiro Shimizu 890ddd
//---------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! A Worker is a specialized QThread that continuously polls Runnable
Toshihiro Shimizu 890ddd
//! tasks from a global execution queue to make them work.
Toshihiro Shimizu 890ddd
class Worker : public QThread
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	RunnableP m_task;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TSmartPointerT<executorid> m_master;</executorid>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool m_exit;
Toshihiro Shimizu 890ddd
	QWaitCondition m_waitCondition;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Worker();
Toshihiro Shimizu 890ddd
	~Worker();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void run();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline void takeTask();
Toshihiro Shimizu 890ddd
	inline bool canAdopt(const RunnableP &task);
Toshihiro Shimizu 890ddd
	inline void adoptTask(RunnableP &task);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline void rest();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline void updateCountsOnTake();
Toshihiro Shimizu 890ddd
	inline void updateCountsOnRelease();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline void onFinish();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=====================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================
Toshihiro Shimizu 890ddd
//    ExecutorId class
Toshihiro Shimizu 890ddd
//------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Contains all the executor data that need to persist until all tasks
Toshihiro Shimizu 890ddd
//! added by the executor have been processed. Upon creation of an Executor
Toshihiro Shimizu 890ddd
//! object, it instantiates one ExecutorId for both storing the Executor's data
Toshihiro Shimizu 890ddd
//! sensible to the underlying code of the Executor manager, and to identify all
Toshihiro Shimizu 890ddd
//! tasks added through it - by copying the smart pointer to the id into each
Toshihiro Shimizu 890ddd
//! added task.
Toshihiro Shimizu 890ddd
//! \sa Executor and Runnable class.
Toshihiro Shimizu 890ddd
class ExecutorId : public TSmartObject
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	size_t m_id;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int m_activeTasks;
Toshihiro Shimizu 890ddd
	int m_maxActiveTasks;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int m_activeLoad;
Toshihiro Shimizu 890ddd
	int m_maxActiveLoad;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool m_dedicatedThreads;
Toshihiro Shimizu 890ddd
	bool m_persistentThreads;
Toshihiro Shimizu 890ddd
	std::deque<worker *=""> m_sleepings;</worker>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ExecutorId();
Toshihiro Shimizu 890ddd
	~ExecutorId();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline void accumulate(const RunnableP &task);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void newWorker(RunnableP &task);
Toshihiro Shimizu 890ddd
	void refreshDedicatedList();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=====================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===========================
Toshihiro Shimizu 890ddd
//    Executor::Imp class
Toshihiro Shimizu 890ddd
//---------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! ExecutorImp both manages the allocation of worker threads for the
Toshihiro Shimizu 890ddd
//! execution of Runnable tasks and centralizes the tasks collection.
Toshihiro Shimizu 890ddd
//! One process only hosts one instance of the ExecutorImp class as a
Toshihiro Shimizu 890ddd
//! a global variable that needs to be allocated in an application-lasting
Toshihiro Shimizu 890ddd
//! and event-looped thread - typically the main thread in GUI applications.
Toshihiro Shimizu 890ddd
class ExecutorImp
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	QMultiMap<int, runnablep=""> m_tasks;</int,>
Toshihiro Shimizu 890ddd
	std::set<worker *=""> m_workers; // Used just for debugging purposes</worker>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	tcg::indices_pool<> m_executorIdPool;
Toshihiro Shimizu 890ddd
	std::vector<uchar> m_waitingFlagsPool;</uchar>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int m_activeLoad;
Toshihiro Shimizu 890ddd
	int m_maxLoad;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QMutex m_transitionMutex; // Workers' transition mutex
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ExecutorImp();
Toshihiro Shimizu 890ddd
	~ExecutorImp();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline void insertTask(int schedulingPriority, RunnableP &task);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void refreshAssignments();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline bool isExecutable(RunnableP &task);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=====================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace TThread
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=====================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===========================
Toshihiro Shimizu 890ddd
//     Global variables
Toshihiro Shimizu 890ddd
//---------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
ExecutorImp *globalImp = 0;
Toshihiro Shimizu 890ddd
ExecutorImpSlots *globalImpSlots = 0;
Toshihiro Shimizu 890ddd
bool shutdownVar = false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=====================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================
Toshihiro Shimizu 890ddd
//     ExecutorImp methods
Toshihiro Shimizu 890ddd
//-----------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
ExecutorImp::ExecutorImp()
Toshihiro Shimizu 890ddd
	: m_activeLoad(0), m_maxLoad(TSystem::getProcessorCount() * 100), m_transitionMutex() //NOTE: We'll wait on this mutex - so it can't be recursive
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
ExecutorImp::~ExecutorImp()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//A task is executable <==> its load allows it. The task load is considered
Toshihiro Shimizu 890ddd
//fixed until another isExecutable() call is made again - in case it may
Toshihiro Shimizu 890ddd
//change in time.
Toshihiro Shimizu 890ddd
inline bool ExecutorImp::isExecutable(RunnableP &task)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return m_activeLoad + task->m_load <= m_maxLoad;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void ExecutorImp::insertTask(int schedulingPriority, RunnableP &task)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	task->m_schedulingPriority = schedulingPriority;
Toshihiro Shimizu 890ddd
	m_tasks.insert(schedulingPriority, task);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=====================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================
Toshihiro Shimizu 890ddd
//    Runnable methods
Toshihiro Shimizu 890ddd
//------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Runnable::Runnable()
Toshihiro Shimizu 890ddd
	: TSmartObject(m_classCode), m_id(0)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Runnable::~Runnable()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_id)
Toshihiro Shimizu 890ddd
		m_id->release(); //see Executor::addTask()
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Returns the predicted CPU load generated by the task, expressed in percentage
Toshihiro Shimizu 890ddd
//! of core usage (that is, 100 is intended to fully occupy one processing core).
Toshihiro Shimizu 890ddd
//! Appropriate task load calibration is an important step to take when implementing
Toshihiro Shimizu 890ddd
//! a new task; for this purpose, remember some rules to follow:
Toshihiro Shimizu 890ddd
//! 
    Toshihiro Shimizu 890ddd
    //! 
  • In every moment, the task manager ensures that the overall sum of the active
  • Toshihiro Shimizu 890ddd
    //!     task's load does not exceed the number of machine's processing cores multiplied
    Toshihiro Shimizu 890ddd
    //!     by 100. This condition is \a blocking with respect to the execution of any other
    Toshihiro Shimizu 890ddd
    //!     task - meaning that when a task is about to be executed the task manager \a waits
    Toshihiro Shimizu 890ddd
    //!     until enough CPU resources are available to make it run.
    Toshihiro Shimizu 890ddd
    //!     In particular, observe that a task's load \b never has to exceed the total CPU
    Toshihiro Shimizu 890ddd
    //!     resources - doing so would surely result in a block of your application. The number
    Toshihiro Shimizu 890ddd
    //!     of available cores can be accessed via the \b TSystem::getProcessorCount() or
    Toshihiro Shimizu 890ddd
    //!     \b QThread::idealThreadCount().
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //! 
  • The task load is considered constant for the duration of the task. Changing its
  • Toshihiro Shimizu 890ddd
    //!     value does not affect the task manager in any way once the task has been started.
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //! 
  • The default task load is 0, representing a very light task. If the task load
  • Toshihiro Shimizu 890ddd
    //!     is 0 the condition at point 1 always succeeds - so the task is always executed when
    Toshihiro Shimizu 890ddd
    //!     encountered. Observe that a long succession of 0 task loads leads to the creation of
    Toshihiro Shimizu 890ddd
    //!     a proportional number of threads simultaneously running to dispatch it; if this is
    Toshihiro Shimizu 890ddd
    //!     a problem, consider the use of \b Executor::setMaxActiveTasks()
    Toshihiro Shimizu 890ddd
    //!     to make only a certain number of tasks being executed at the same time.
    Toshihiro Shimizu 890ddd
    //! 
    Toshihiro Shimizu 890ddd
    int Runnable::taskLoad()
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    	return 0;
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //---------------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //! Returns the priority value used to schedule a task for execution. Tasks
    Toshihiro Shimizu 890ddd
    //! with higher priority start before tasks with lower priority. The default
    Toshihiro Shimizu 890ddd
    //! value returned is 5 (halfway from 0 to 10) - but any value other than
    Toshihiro Shimizu 890ddd
    //! (std::numeric_limits<int>::max)() is acceptable.</int>
    Toshihiro Shimizu 890ddd
    int Runnable::schedulingPriority()
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    	return 5;
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //---------------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //! Returns the QThread::Priority used by worker threads when they adopt
    Toshihiro Shimizu 890ddd
    //! the task. The default value returned is QThread::Normal.
    Toshihiro Shimizu 890ddd
    QThread::Priority Runnable::runningPriority()
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    	return QThread::NormalPriority;
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //---------------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    inline bool Runnable::customConditions()
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    	return (m_id->m_activeTasks < m_id->m_maxActiveTasks) &&
    Toshihiro Shimizu 890ddd
    		   (m_id->m_activeLoad + m_load <= m_id->m_maxActiveLoad);
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    /*!
    Toshihiro Shimizu 890ddd
      \fn void Runnable::started(RunnableP sender)
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
      This signal is emitted from working threads just before the run() code
    Toshihiro Shimizu 890ddd
      is executed. Observe that the passed smart pointer ensures the survival of
    Toshihiro Shimizu 890ddd
      the emitting task for the time required by connected slots execution.
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
      \warning The started(), finished() and exception() signals are emitted in
    Toshihiro Shimizu 890ddd
      a mutex-protected environment in order to provide the correct sequence of
    Toshihiro Shimizu 890ddd
      emissions (i.e. so that canceled() and terminated() controller-emitted signals
    Toshihiro Shimizu 890ddd
      are either delivered after started() and before finished() or exception(),
    Toshihiro Shimizu 890ddd
      or \a instead of them).
    Toshihiro Shimizu 890ddd
      \warning Thus, setting up blocking connections or \a direct slots that contain a
    Toshihiro Shimizu 890ddd
      blocking instruction or even calls to the Executor API (which would definitely
    Toshihiro Shimizu 890ddd
      try to relock the aforementioned mutex) is dangerous and could result in an
    Toshihiro Shimizu 890ddd
      application freeze.
    Toshihiro Shimizu 890ddd
      \warning In case it's necessary to use blocking features, they should be enforced
    Toshihiro Shimizu 890ddd
      through custom signals to be invoked manually in the run() method, outside the
    Toshihiro Shimizu 890ddd
      mutex.
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
      \sa \b finished and \b exception signals.
    Toshihiro Shimizu 890ddd
    */
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    /*!
    Toshihiro Shimizu 890ddd
      \fn void Runnable::finished(RunnableP sender)
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
      The \b finished signal is emitted from working threads once the run()
    Toshihiro Shimizu 890ddd
      code is returned without unmanaged exceptions.
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
      \sa \b started and \b exception signals.
    Toshihiro Shimizu 890ddd
    */
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    /*!
    Toshihiro Shimizu 890ddd
      \fn void Runnable::exception(RunnableP sender)
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
      The \b exception signal is emitted from working threads whenever an
    Toshihiro Shimizu 890ddd
      untrapped exception is found within the run() method.
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
      \sa \b started and \b finished signals.
    Toshihiro Shimizu 890ddd
    */
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    /*!
    Toshihiro Shimizu 890ddd
      \fn void Runnable::canceled(RunnableP sender)
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
      The \b canceled signal is emitted from the controller thread whenever
    Toshihiro Shimizu 890ddd
      a task which is currently under the task manager's control is canceled
    Toshihiro Shimizu 890ddd
      by the user (the signal is emitted from the thread invoking the cancel).
    Toshihiro Shimizu 890ddd
      Observe that tasks under execution are not stopped by the task manager
    Toshihiro Shimizu 890ddd
      when they are canceled, but the signal is emitted anyway - helping the
    Toshihiro Shimizu 890ddd
      user to stop the actual execution of the run() code in advance.
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
      \sa \b Executor::removeTask and \b Executor::cancelAll methods.
    Toshihiro Shimizu 890ddd
    */
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    /*!
    Toshihiro Shimizu 890ddd
      \fn void Runnable::terminated(RunnableP sender)
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
      The \b terminated signal is emitted from the controller thread when
    Toshihiro Shimizu 890ddd
      the Executor components are shutting down inside a call to
    Toshihiro Shimizu 890ddd
      Executor::shutdown(). Implementing a slot connected to this signal
    Toshihiro Shimizu 890ddd
      helps the user in controlling the flow of an Executor-multithreaded
    Toshihiro Shimizu 890ddd
      application when it is shutting down - for example, it can be imposed
    Toshihiro Shimizu 890ddd
      that the application must wait for the task to be finished, print logs
    Toshihiro Shimizu 890ddd
      or similar.
    Toshihiro Shimizu 890ddd
      This signal is always preceded by a canceled() signal, informing all
    Toshihiro Shimizu 890ddd
      active tasks that thay should begin quitting on their own in a 'soft'
    Toshihiro Shimizu 890ddd
      way before brute termination may occur.
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
      \sa \b Executor::shutdown static method and \b Runnable::canceled signal.
    Toshihiro Shimizu 890ddd
    */
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //! Convenience slot for the started() signal - so it's not necessary to declare
    Toshihiro Shimizu 890ddd
    //! the task in a header file for moc'ing each time. You must both reimplement
    Toshihiro Shimizu 890ddd
    //! \b and connect it to the started() signal to make it work.
    Toshihiro Shimizu 890ddd
    void Runnable::onStarted(RunnableP)
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //---------------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //! The analogous of onStarted() for the finished() signal.
    Toshihiro Shimizu 890ddd
    void Runnable::onFinished(RunnableP)
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //---------------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //! The analogous of onStarted() for the exception() signal.
    Toshihiro Shimizu 890ddd
    void Runnable::onException(RunnableP)
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //---------------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //! The analogous of onStarted() for the canceled() signal.
    Toshihiro Shimizu 890ddd
    void Runnable::onCanceled(RunnableP)
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //---------------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //! The analogous of onStarted() for the terminated() signal.
    Toshihiro Shimizu 890ddd
    void Runnable::onTerminated(RunnableP)
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //=====================================================================
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //==========================
    Toshihiro Shimizu 890ddd
    //    ExecutorId methods
    Toshihiro Shimizu 890ddd
    //--------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    ExecutorId::ExecutorId()
    Toshihiro Shimizu 890ddd
    	: m_activeTasks(0), m_maxActiveTasks(1), m_activeLoad(0), m_maxActiveLoad((std::numeric_limits<int>::max)()), m_dedicatedThreads(false), m_persistentThreads(false)</int>
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    	QMutexLocker transitionLocker(&globalImp->m_transitionMutex);
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	m_id = globalImp->m_executorIdPool.acquire();
    Toshihiro Shimizu 890ddd
    	globalImp->m_waitingFlagsPool.resize(globalImp->m_executorIdPool.size());
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //---------------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    ExecutorId::~ExecutorId()
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    	QMutexLocker transitionLocker(&globalImp->m_transitionMutex);
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	if (m_dedicatedThreads) {
    Toshihiro Shimizu 890ddd
    		m_persistentThreads = 0;
    Toshihiro Shimizu 890ddd
    		refreshDedicatedList();
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	globalImp->m_executorIdPool.release(m_id);
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //---------------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //Make sure that sleeping workers are eliminated properly if the permanent
    Toshihiro Shimizu 890ddd
    //workers count decreases.
    Toshihiro Shimizu 890ddd
    void ExecutorId::refreshDedicatedList()
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    	//QMutexLocker transitionLocker(&globalImp->m_transitionMutex);  //Already covered
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	if (!m_dedicatedThreads || !m_persistentThreads) {
    Toshihiro Shimizu 890ddd
    		//Release all sleeping workers
    Toshihiro Shimizu 890ddd
    		//Wake them - they will exit on their own
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		unsigned int i, size = m_sleepings.size();
    Toshihiro Shimizu 890ddd
    		for (i = 0; i < size; ++i) {
    Toshihiro Shimizu 890ddd
    			m_sleepings[i]->m_exit = true;
    Toshihiro Shimizu 890ddd
    			m_sleepings[i]->m_waitCondition.wakeOne();
    Toshihiro Shimizu 890ddd
    		}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		m_sleepings.clear();
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //=====================================================================
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //===========================
    Toshihiro Shimizu 890ddd
    //      Worker methods
    Toshihiro Shimizu 890ddd
    //---------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    Worker::Worker()
    Toshihiro Shimizu 890ddd
    	: QThread(), m_task(0), m_master(0), m_exit(true)
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //---------------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    Worker::~Worker()
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //---------------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    void Worker::run()
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    	//Ensure atomicity of worker's state transitions
    Toshihiro Shimizu 890ddd
    	QMutexLocker sl(&globalImp->m_transitionMutex);
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	if (shutdownVar)
    Toshihiro Shimizu 890ddd
    		return;
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    	for (;;) {
    Toshihiro Shimizu 890ddd
    		//Run the taken task
    Toshihiro Shimizu 890ddd
    		setPriority(m_task->runningPriority());
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		try {
    Toshihiro Shimizu 890ddd
    			Q_EMIT m_task->started(m_task);
    Toshihiro Shimizu 890ddd
    			sl.unlock();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    			m_task->run();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    			sl.relock();
    Toshihiro Shimizu 890ddd
    			Q_EMIT m_task->finished(m_task);
    Toshihiro Shimizu 890ddd
    		} catch (...) {
    Toshihiro Shimizu 890ddd
    			sl.relock(); //throw must be in the run() block
    Toshihiro Shimizu 890ddd
    			Q_EMIT m_task->exception(m_task);
    Toshihiro Shimizu 890ddd
    		}
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		updateCountsOnRelease();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		if (shutdownVar)
    Toshihiro Shimizu 890ddd
    			return;
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		//Get the next task
    Toshihiro Shimizu 890ddd
    		takeTask();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		if (!m_task) {
    Toshihiro Shimizu 890ddd
    			onFinish();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    			if (!m_exit && !shutdownVar) {
    Toshihiro Shimizu 890ddd
    				//Put the worker to sleep
    Toshihiro Shimizu 890ddd
    				m_waitCondition.wait(sl.mutex());
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    				//Upon thread destruction the wait condition is implicitly woken up.
    Toshihiro Shimizu 890ddd
    				//If this is the case, m_task == 0 and we return.
    Toshihiro Shimizu 890ddd
    				if (!m_task || shutdownVar)
    Toshihiro Shimizu 890ddd
    					return;
    Toshihiro Shimizu 890ddd
    			} else
    Toshihiro Shimizu 890ddd
    				return;
    Toshihiro Shimizu 890ddd
    		}
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //---------------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    inline void Worker::updateCountsOnTake()
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    	globalImp->m_activeLoad += m_task->m_load;
    Toshihiro Shimizu 890ddd
    	m_task->m_id->m_activeLoad += m_task->m_load;
    Toshihiro Shimizu 890ddd
    	++m_task->m_id->m_activeTasks;
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //---------------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    inline void Worker::updateCountsOnRelease()
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    	globalImp->m_activeLoad -= m_task->m_load;
    Toshihiro Shimizu 890ddd
    	m_task->m_id->m_activeLoad -= m_task->m_load;
    Toshihiro Shimizu 890ddd
    	--m_task->m_id->m_activeTasks;
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //---------------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    inline void Worker::onFinish()
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    	if (m_master && m_master->m_dedicatedThreads && m_master->m_persistentThreads) {
    Toshihiro Shimizu 890ddd
    		m_exit = false;
    Toshihiro Shimizu 890ddd
    		m_master->m_sleepings.push_back(this);
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		// Unlock the mutex - since eventually invoked ~ExecutorId will relock it...
    Toshihiro Shimizu 890ddd
    		globalImp->m_transitionMutex.unlock();
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		m_master = 0; //Master may be destroyed here - and m_exit= true for all sleepings
    Toshihiro Shimizu 890ddd
    					  //in that case
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    		globalImp->m_transitionMutex.lock();
    Toshihiro Shimizu 890ddd
    	} else {
    Toshihiro Shimizu 890ddd
    		m_exit = true;
    Toshihiro Shimizu 890ddd
    		globalImp->m_workers.erase(this);
    Toshihiro Shimizu 890ddd
    	}
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //=====================================================================
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //===========================
    Toshihiro Shimizu 890ddd
    //     Executor methods
    Toshihiro Shimizu 890ddd
    //---------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    Executor::Executor()
    Toshihiro Shimizu 890ddd
    	: m_id(new ExecutorId)
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    	m_id->addRef();
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //---------------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    Executor::~Executor()
    Toshihiro Shimizu 890ddd
    {
    Toshihiro Shimizu 890ddd
    	m_id->release();
    Toshihiro Shimizu 890ddd
    }
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //---------------------------------------------------------------------
    Toshihiro Shimizu 890ddd
    Toshihiro Shimizu 890ddd
    //! This static method declares the use of the Executor's task manager into
    Toshihiro Shimizu 890ddd
    //! the application code. Be sure to use it according to the following rules:
    Toshihiro Shimizu 890ddd
    //! 
      Toshihiro Shimizu 890ddd
      //! 
    • Only QCoreApplications or QApplications may use Executors.
    • Toshihiro Shimizu 890ddd
      //! 
    • This method must be invoked in a thread which performs constant Qt event
    • Toshihiro Shimizu 890ddd
      //!      processing - like the main loop of interactive GUI applications.
      Toshihiro Shimizu 890ddd
      //! 
    • No task processing is allowed after event processing stops.
    • Toshihiro Shimizu 890ddd
      //! 
      Toshihiro Shimizu 890ddd
      void Executor::init()
      Toshihiro Shimizu 890ddd
      {
      Toshihiro Shimizu 890ddd
      	//If no global ExecutorImp exists, allocate it now. You may not move this
      Toshihiro Shimizu 890ddd
      	//to a static declaration, since ExecutorImpSlots's connections must be
      Toshihiro Shimizu 890ddd
      	//made once the QCoreApplication has been constructed.
      Toshihiro Shimizu 890ddd
      	if (!globalImp) {
      Toshihiro Shimizu 890ddd
      		globalImp = new ExecutorImp;
      Toshihiro Shimizu 890ddd
      		globalImpSlots = new ExecutorImpSlots;
      Toshihiro Shimizu 890ddd
      	}
      Toshihiro Shimizu 890ddd
      Toshihiro Shimizu 890ddd
      	qRegisterMetaType<tthread::runnablep>("TThread::RunnableP");</tthread::runnablep>
      Toshihiro Shimizu 890ddd
      }
      Toshihiro Shimizu 890ddd
      Toshihiro Shimizu 890ddd
      //---------------------------------------------------------------------
      Toshihiro Shimizu 890ddd
      Toshihiro Shimizu 890ddd
      //! This static method, which \b must be invoked in the controller thread, declares
      Toshihiro Shimizu 890ddd
      //! termination of all Executor-based components, forcing the execution of tasks submitted
      Toshihiro Shimizu 890ddd
      //! by any Executor to quit as soon as possible in a safe way.
      Toshihiro Shimizu 890ddd
      //! When the shutdown method is invoked, the task manager first emits a canceled()
      Toshihiro Shimizu 890ddd
      //! signal for all the tasks that were submitted to it, independently from the Executor that
      Toshihiro Shimizu 890ddd
      //! performed the submission; then, tasks that are still active once all the cancellation signals
      Toshihiro Shimizu 890ddd
      //! were delivered further receive a terminated() signal informing them that they must provide
      Toshihiro Shimizu 890ddd
      //! code termination (or at least remain silent in a safe state until the application quits).
      Toshihiro Shimizu 890ddd
      Toshihiro Shimizu 890ddd
      //! \b NOTE: Observe that this method does not explicitly wait for all the tasks to terminate - this depends
      Toshihiro Shimizu 890ddd
      //! on the code connected to the terminated() signal and is under the user's responsibility (see the
      Toshihiro Shimizu 890ddd
      //! remarks specified in started() signal descritpion); if this is the intent and the terminated slot
      Toshihiro Shimizu 890ddd
      //! is invoked in the controller thread, you should remember to implement a local event loop in it (so that
      Toshihiro Shimizu 890ddd
      //! event processing is still performed) and wait there until the first finished() or catched()
      Toshihiro Shimizu 890ddd
      //! slot make it quit.
      Toshihiro Shimizu 890ddd
      void Executor::shutdown()
      Toshihiro Shimizu 890ddd
      {
      Toshihiro Shimizu 890ddd
      	{
      Toshihiro Shimizu 890ddd
      		//Updating tasks list - lock against state transitions
      Toshihiro Shimizu 890ddd
      		QMutexLocker transitionLocker(&globalImp->m_transitionMutex);
      Toshihiro Shimizu 890ddd
      Toshihiro Shimizu 890ddd
      		shutdownVar = true;
      Toshihiro Shimizu 890ddd
      Toshihiro Shimizu 890ddd
      		//Cancel all tasks  - first the active ones
      Toshihiro Shimizu 890ddd
      		std::set<worker *="">::iterator it;</worker>
      Toshihiro Shimizu 890ddd
      		for (it = globalImp->m_workers.begin(); it != globalImp->m_workers.end(); ++it) {
      Toshihiro Shimizu 890ddd
      			RunnableP task = (*it)->m_task;
      Toshihiro Shimizu 890ddd
      			if (task)
      Toshihiro Shimizu 890ddd
      				Q_EMIT task->canceled(task);
      Toshihiro Shimizu 890ddd
      		}
      Toshihiro Shimizu 890ddd
      Toshihiro Shimizu 890ddd
      		//Finally, deal with the global queue tasks
      Toshihiro Shimizu 890ddd
      		QMutableMapIterator<int, runnablep=""> jt(globalImp->m_tasks);</int,>
      Toshihiro Shimizu 890ddd
      		while (jt.hasNext()) {
      Toshihiro Shimizu 890ddd
      			jt.next();
      Toshihiro Shimizu 890ddd
      			RunnableP task = jt.value();
      Toshihiro Shimizu 890ddd
      			Q_EMIT task->canceled(task);
      Toshihiro Shimizu 890ddd
      			jt.remove();
      Toshihiro Shimizu 890ddd
      		}
      Toshihiro Shimizu 890ddd
      Toshihiro Shimizu 890ddd
      		//Now, send the terminate() signal to all active tasks
      Toshihiro Shimizu 890ddd
      		for (it = globalImp->m_workers.begin(); it != globalImp->m_workers.end(); ++it) {
      Toshihiro Shimizu 890ddd
      			RunnableP task = (*it)->m_task;
      Toshihiro Shimizu 890ddd
      			if (task)
      Toshihiro Shimizu 890ddd
      				Q_EMIT task->terminated(task);
      Toshihiro Shimizu 890ddd
      		}
      Toshihiro Shimizu 890ddd
      	}
      Toshihiro Shimizu 890ddd
      Toshihiro Shimizu 890ddd
      	//Just placing a convenience processEvents() to make sure that queued slots invoked by the
      Toshihiro Shimizu 890ddd
      	//signals above are effectively invoked in this method - without having to return to an event loop.
      Toshihiro Shimizu 890ddd
      	QCoreApplication::processEvents();
      Toshihiro Shimizu 890ddd
      }
      Toshihiro Shimizu 890ddd
      Toshihiro Shimizu 890ddd
      //---------------------------------------------------------------------
      Toshihiro Shimizu 890ddd
      Toshihiro Shimizu 890ddd
      //! Specifies the use of dedicated threads for the Executor's task group.
      Toshihiro Shimizu 890ddd
      Toshihiro Shimizu 890ddd
      //! By default a worker thread attempts adoption of Runnable tasks
      Toshihiro Shimizu 890ddd
      //! without regard to the Executor that performed the submission. This helps
      Toshihiro Shimizu 890ddd
      //! in stabilizing the number of threads that are created and destroyed
      Toshihiro Shimizu 890ddd
      //! by the task manager - but may be a problem in some cases.
      Toshihiro Shimizu 890ddd
      Toshihiro Shimizu 890ddd
      //! Using this method the user can explicitly tell the Executor to seize the
      Toshihiro Shimizu 890ddd
      //! ownership of worker threads assigned to its tasks, so that they will not
      Toshihiro Shimizu 890ddd
      //! try adoption of external tasks but instead remain focused on Executor's
      Toshihiro Shimizu 890ddd
      //! tasks only.
      Toshihiro Shimizu 890ddd
      Toshihiro Shimizu 890ddd
      //! An optional \b persistent parameter may be passed, which specifies if
      Toshihiro Shimizu 890ddd
      //! dedicated threads should remain sleeping or should rather die when no
      Toshihiro Shimizu 890ddd
      //! processable tasks from the Executor are found.
      Toshihiro Shimizu 890ddd
      Toshihiro Shimizu 890ddd
      //! This method is especially helpful in two occasions:
      Toshihiro Shimizu 890ddd
      //! 
        Toshihiro Shimizu 890ddd
        //! 
      • The Executor's tasks use thread-specific data such as QThreadStorages,
      • Toshihiro Shimizu 890ddd
        //!      which may be recycled among different tasks.
        Toshihiro Shimizu 890ddd
        //! 
      • The Executor receives tasks at a frequent rate, but mostly ends each one before
      • Toshihiro Shimizu 890ddd
        //!      another one is submitted - resulting in a continuous thread turnover.
        Toshihiro Shimizu 890ddd
        //! 
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        void Executor::setDedicatedThreads(bool dedicated, bool persistent)
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	QMutexLocker transitionLocker(&globalImp->m_transitionMutex);
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	m_id->m_dedicatedThreads = dedicated;
        Toshihiro Shimizu 890ddd
        	m_id->m_persistentThreads = persistent;
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	m_id->refreshDedicatedList();
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //! Submits a task for execution. The task is executed according to
        Toshihiro Shimizu 890ddd
        //! its task load, insertion time and scheduling priority.
        Toshihiro Shimizu 890ddd
        void Executor::addTask(RunnableP task)
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	{
        Toshihiro Shimizu 890ddd
        		if (task->m_id)			   // Must be done outside transition lock, since eventually
        Toshihiro Shimizu 890ddd
        			task->m_id->release(); // invoked ~ExecutorId will lock it
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        		//Updating tasks and workers list - lock against state transitions
        Toshihiro Shimizu 890ddd
        		QMutexLocker transitionLocker(&globalImp->m_transitionMutex);
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        		task->m_id = m_id;
        Toshihiro Shimizu 890ddd
        		m_id->addRef();
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        		globalImp->insertTask(task->schedulingPriority(), task);
        Toshihiro Shimizu 890ddd
        	}
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	//If addTask is called in the main thread, the emit works directly -
        Toshihiro Shimizu 890ddd
        	//so it is necessary to unlock the mutex *before* emitting the refresh.
        Toshihiro Shimizu 890ddd
        	globalImpSlots->emitRefreshAssignments();
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //! Removes the given task from scheduled execution and emits its
        Toshihiro Shimizu 890ddd
        //! Runnable::canceled signal. Tasks already under execution are not
        Toshihiro Shimizu 890ddd
        //! stopped by this method - although the canceled signal is still emitted.
        Toshihiro Shimizu 890ddd
        //! It has no effect if the task is not currently under the task manager's control.
        Toshihiro Shimizu 890ddd
        //! \sa \b Runnable::canceled signal and the \b cancelAll method.
        Toshihiro Shimizu 890ddd
        void Executor::removeTask(RunnableP task)
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	//If the task does not belong to this Executor, quit.
        Toshihiro Shimizu 890ddd
        	if (task->m_id != m_id)
        Toshihiro Shimizu 890ddd
        		return;
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	//Updating tasks list - lock against state transitions
        Toshihiro Shimizu 890ddd
        	QMutexLocker transitionLocker(&globalImp->m_transitionMutex);
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	//Then, look in the global queue - if it is found, emiminate the task and
        Toshihiro Shimizu 890ddd
        	//send the canceled signal.
        Toshihiro Shimizu 890ddd
        	if (globalImp->m_tasks.remove(task->m_schedulingPriority, task)) {
        Toshihiro Shimizu 890ddd
        		Q_EMIT task->canceled(task);
        Toshihiro Shimizu 890ddd
        		return;
        Toshihiro Shimizu 890ddd
        	}
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	//Finally, the task may be running - look in workers.
        Toshihiro Shimizu 890ddd
        	std::set<worker *=""> &workers = globalImp->m_workers;</worker>
        Toshihiro Shimizu 890ddd
        	std::set<worker *="">::iterator it;</worker>
        Toshihiro Shimizu 890ddd
        	for (it = workers.begin(); it != workers.end(); ++it)
        Toshihiro Shimizu 890ddd
        		if (task && (*it)->m_task == task)
        Toshihiro Shimizu 890ddd
        			Q_EMIT task->canceled(task);
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	//No need to refresh - tasks were eventually decremented...
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //! Clears the task manager of all tasks added by this Executor and emits
        Toshihiro Shimizu 890ddd
        //! the Runnable::canceled signal for each of them. The same specifications
        Toshihiro Shimizu 890ddd
        //! described in the \b removeTask method apply here.
        Toshihiro Shimizu 890ddd
        //! \sa \b Runnable::canceled signal and the \b removeTask method.
        Toshihiro Shimizu 890ddd
        void Executor::cancelAll()
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	//Updating tasks list - lock against state transitions
        Toshihiro Shimizu 890ddd
        	QMutexLocker transitionLocker(&globalImp->m_transitionMutex);
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	//Clear the tasks chronologically. So, first check currently working
        Toshihiro Shimizu 890ddd
        	//tasks.
        Toshihiro Shimizu 890ddd
        	std::set<worker *="">::iterator it;</worker>
        Toshihiro Shimizu 890ddd
        	for (it = globalImp->m_workers.begin(); it != globalImp->m_workers.end(); ++it) {
        Toshihiro Shimizu 890ddd
        		RunnableP task = (*it)->m_task;
        Toshihiro Shimizu 890ddd
        		if (task && task->m_id == m_id)
        Toshihiro Shimizu 890ddd
        			Q_EMIT task->canceled(task);
        Toshihiro Shimizu 890ddd
        	}
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	//Finally, clear the global tasks list from all tasks inserted by this executor
        Toshihiro Shimizu 890ddd
        	//NOTE: An easier way here?
        Toshihiro Shimizu 890ddd
        	QMutableMapIterator<int, runnablep=""> jt(globalImp->m_tasks);</int,>
        Toshihiro Shimizu 890ddd
        	while (jt.hasNext()) {
        Toshihiro Shimizu 890ddd
        		jt.next();
        Toshihiro Shimizu 890ddd
        		if (jt.value()->m_id == m_id) {
        Toshihiro Shimizu 890ddd
        			RunnableP task = jt.value();
        Toshihiro Shimizu 890ddd
        			Q_EMIT task->canceled(task);
        Toshihiro Shimizu 890ddd
        			jt.remove();
        Toshihiro Shimizu 890ddd
        		}
        Toshihiro Shimizu 890ddd
        	}
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //! Declares that only a certain number of tasks added by this Executor
        Toshihiro Shimizu 890ddd
        //! may be processed simultaneously. The default is 1 - meaning that tasks
        Toshihiro Shimizu 890ddd
        //! added to the executor are completely serialized. A negative task number
        Toshihiro Shimizu 890ddd
        //! disables any form of task serialization.
        Toshihiro Shimizu 890ddd
        //! \b NOTE: Currently, tasks that do not
        Toshihiro Shimizu 890ddd
        //! satisfy this condition avoid blocking execution of tasks not
        Toshihiro Shimizu 890ddd
        //! added by the same Executor - even if they were scheduled for later
        Toshihiro Shimizu 890ddd
        //! execution.
        Toshihiro Shimizu 890ddd
        void Executor::setMaxActiveTasks(int maxActiveTasks)
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	QMutexLocker transitionLocker(&globalImp->m_transitionMutex);
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	if (maxActiveTasks <= 0)
        Toshihiro Shimizu 890ddd
        		m_id->m_maxActiveTasks = (std::numeric_limits<int>::max)();</int>
        Toshihiro Shimizu 890ddd
        	else
        Toshihiro Shimizu 890ddd
        		m_id->m_maxActiveTasks = maxActiveTasks;
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        int Executor::maxActiveTasks() const
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	QMutexLocker transitionLocker(&globalImp->m_transitionMutex);
        Toshihiro Shimizu 890ddd
        	return m_id->m_maxActiveTasks;
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //! Declares a maximum overall task load for the tasks added by this Executor.
        Toshihiro Shimizu 890ddd
        //! \b NOTE: The same remark for setMaxActiveTasks() holds here.
        Toshihiro Shimizu 890ddd
        void Executor::setMaxActiveLoad(int maxActiveLoad)
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	QMutexLocker transitionLocker(&globalImp->m_transitionMutex);
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	m_id->m_maxActiveLoad = maxActiveLoad;
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        int Executor::maxActiveLoad() const
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	QMutexLocker transitionLocker(&globalImp->m_transitionMutex);
        Toshihiro Shimizu 890ddd
        	return m_id->m_maxActiveLoad;
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //=====================================================================
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //==================================
        Toshihiro Shimizu 890ddd
        //     ExecutorImpSlots methods
        Toshihiro Shimizu 890ddd
        //----------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        ExecutorImpSlots::ExecutorImpSlots()
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	connect(this, SIGNAL(refreshAssignments()), this, SLOT(onRefreshAssignments()));
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        ExecutorImpSlots::~ExecutorImpSlots()
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        void ExecutorImpSlots::emitRefreshAssignments()
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	Q_EMIT refreshAssignments();
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        void ExecutorImpSlots::onRefreshAssignments()
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	QMutexLocker transitionLocker(&globalImp->m_transitionMutex);
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	globalImp->refreshAssignments();
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        void ExecutorImpSlots::onTerminated()
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	delete QObject::sender();
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //=====================================================================
        Toshihiro Shimizu 890ddd
        //      Task adoption methods
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        inline void ExecutorId::newWorker(RunnableP &task)
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	Worker *worker;
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	if (m_sleepings.size()) {
        Toshihiro Shimizu 890ddd
        		worker = m_sleepings.front();
        Toshihiro Shimizu 890ddd
        		m_sleepings.pop_front();
        Toshihiro Shimizu 890ddd
        		worker->m_task = task;
        Toshihiro Shimizu 890ddd
        		worker->updateCountsOnTake();
        Toshihiro Shimizu 890ddd
        		worker->m_waitCondition.wakeOne();
        Toshihiro Shimizu 890ddd
        	} else {
        Toshihiro Shimizu 890ddd
        		worker = new Worker;
        Toshihiro Shimizu 890ddd
        		globalImp->m_workers.insert(worker);
        Toshihiro Shimizu 890ddd
        		QObject::connect(worker, SIGNAL(finished()), globalImpSlots, SLOT(onTerminated()));
        Toshihiro Shimizu 890ddd
        		worker->m_task = task;
        Toshihiro Shimizu 890ddd
        		worker->updateCountsOnTake();
        Toshihiro Shimizu 890ddd
        		worker->start();
        Toshihiro Shimizu 890ddd
        	}
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        inline void Worker::adoptTask(RunnableP &task)
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	m_task = task;
        Toshihiro Shimizu 890ddd
        	updateCountsOnTake();
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //  * Le task timedOut sono ex-accumulate che non soddisfano le condizioni
        Toshihiro Shimizu 890ddd
        //    standard. Quindi sono bloccanti *ovunque*.
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //  * Il refresh dei worker sulle task accumulate *deve* avvenire:
        Toshihiro Shimizu 890ddd
        //      -Se e solo se una task dello stesso executor finisce,
        Toshihiro Shimizu 890ddd
        //       perche' e' l'unico caso in cui le custom conditions
        Toshihiro Shimizu 890ddd
        //       vengono aggiornate
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //  * Se un thread dedicato non puo' prendere una task estranea, non e' detto
        Toshihiro Shimizu 890ddd
        //    che altri non possano!
        Toshihiro Shimizu 890ddd
        //  * Le task che richiedono dedizione dovrebbero essere adottate da thread
        Toshihiro Shimizu 890ddd
        //    gia' dedicati, se esistono! => Gli executor che richiedono thread dedicati
        Toshihiro Shimizu 890ddd
        //    li creano a parte e non li condividono con nessuno: cioe', thread creati
        Toshihiro Shimizu 890ddd
        //    senza dedizione non devono poter adottare task richiedenti dedizione!
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //Assigns tasks polled from the id's accumulation queue (if id is given) and
        Toshihiro Shimizu 890ddd
        //the global tasks queue.
        Toshihiro Shimizu 890ddd
        //It works like:
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //  a) First look if there exist tasks with timedOut priority and if so
        Toshihiro Shimizu 890ddd
        //     try to take them out
        Toshihiro Shimizu 890ddd
        //  b) Then look for tasks in the id's accumulation queue
        Toshihiro Shimizu 890ddd
        //  c) Finally search in the remaining global tasks queue
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        void ExecutorImp::refreshAssignments()
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	//QMutexLocker transitionLocker(&globalImp->m_transitionMutex);  //Already covered
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	if (m_tasks.isEmpty())
        Toshihiro Shimizu 890ddd
        		return;
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	// Erase the id vector data
        Toshihiro Shimizu 890ddd
        	assert(m_executorIdPool.size() == m_waitingFlagsPool.size());
        Toshihiro Shimizu 890ddd
        	memset(&m_waitingFlagsPool.front(), 0, m_waitingFlagsPool.size());
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	//c) Try with the global queue
        Toshihiro Shimizu 890ddd
        	int e, executorsCount = m_executorIdPool.acquiredSize();
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	int i, tasksCount = m_tasks.size();
        Toshihiro Shimizu 890ddd
        	QMultiMap<int, runnablep="">::iterator it;</int,>
        Toshihiro Shimizu 890ddd
        	for (i = 0, e = 0, it = m_tasks.end() - 1; i < tasksCount && e < executorsCount; ++i, --it) {
        Toshihiro Shimizu 890ddd
        		//std::cout<< "global tasks-refreshAss" << std::endl;
        Toshihiro Shimizu 890ddd
        		//Take the task
        Toshihiro Shimizu 890ddd
        		RunnableP task = it.value();
        Toshihiro Shimizu 890ddd
        		task->m_load = task->taskLoad();
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        		UCHAR &idWaitingForAnotherTask = m_waitingFlagsPool[task->m_id->m_id];
        Toshihiro Shimizu 890ddd
        		if (idWaitingForAnotherTask)
        Toshihiro Shimizu 890ddd
        			continue;
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        		if (!isExecutable(task))
        Toshihiro Shimizu 890ddd
        			break;
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        		if (!task->customConditions()) {
        Toshihiro Shimizu 890ddd
        			++e;
        Toshihiro Shimizu 890ddd
        			idWaitingForAnotherTask = 1;
        Toshihiro Shimizu 890ddd
        		} else {
        Toshihiro Shimizu 890ddd
        			task->m_id->newWorker(task);
        Toshihiro Shimizu 890ddd
        			it = m_tasks.erase(it);
        Toshihiro Shimizu 890ddd
        		}
        Toshihiro Shimizu 890ddd
        	}
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        inline bool Worker::canAdopt(const RunnableP &task)
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	return task->m_id->m_sleepings.size() == 0 &&				 //Always prefer sleeping dedicateds if present
        Toshihiro Shimizu 890ddd
        		   (!m_master || (m_master.getPointer() == task->m_id)); //If was seized by an Executor, ensure task compatibility
        Toshihiro Shimizu 890ddd
        }
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //---------------------------------------------------------------------
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        //Takes a task and assigns it to the worker in a way similar to the one above.
        Toshihiro Shimizu 890ddd
        inline void Worker::takeTask()
        Toshihiro Shimizu 890ddd
        {
        Toshihiro Shimizu 890ddd
        	TSmartPointerT<executorid> oldId = m_task->m_id;</executorid>
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	//When a new task is taken, the old one's Executor may seize the worker
        Toshihiro Shimizu 890ddd
        	m_master = oldId->m_dedicatedThreads ? oldId : (TSmartPointerT<executorid>)0;</executorid>
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	//c) No accumulated task can be taken - look for a task in the global tasks queue.
        Toshihiro Shimizu 890ddd
        	//   If the active load admits it, take the earliest task.
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	//Free the old task. NOTE: This instruction MUST be performed OUTSIDE the mutex-protected environment -
        Toshihiro Shimizu 890ddd
        	//since user code may be executed upon task destruction - including the mutex relock!!
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	globalImp->m_transitionMutex.unlock();
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	m_task = 0;
        Toshihiro Shimizu 890ddd
        	oldId = TSmartPointerT<executorid>();</executorid>
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	globalImp->m_transitionMutex.lock();
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	// Erase the executor id status pool
        Toshihiro Shimizu 890ddd
        	tcg::indices_pool<> &executorIdPool = globalImp->m_executorIdPool;
        Toshihiro Shimizu 890ddd
        	std::vector<uchar> &waitingFlagsPool = globalImp->m_waitingFlagsPool;</uchar>
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	assert(waitingFlagsPool.size() == globalImp->m_executorIdPool.size());
        Toshihiro Shimizu 890ddd
        	memset(&waitingFlagsPool.front(), 0, waitingFlagsPool.size());
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	int e, executorsCount = executorIdPool.acquiredSize();
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        	int i, tasksCount = globalImp->m_tasks.size();
        Toshihiro Shimizu 890ddd
        	QMultiMap<int, runnablep="">::iterator it;</int,>
        Toshihiro Shimizu 890ddd
        	for (i = 0, e = 0, it = globalImp->m_tasks.end() - 1; i < tasksCount && e < executorsCount; ++i, --it) {
        Toshihiro Shimizu 890ddd
        		//std::cout<< "global tasks-takeTask" << std::endl;
        Toshihiro Shimizu 890ddd
        		//Take the first task
        Toshihiro Shimizu 890ddd
        		RunnableP task = it.value();
        Toshihiro Shimizu 890ddd
        		task->m_load = task->taskLoad();
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        		UCHAR &idWaitingForAnotherTask = waitingFlagsPool[task->m_id->m_id];
        Toshihiro Shimizu 890ddd
        		if (idWaitingForAnotherTask)
        Toshihiro Shimizu 890ddd
        			continue;
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        		if (!globalImp->isExecutable(task))
        Toshihiro Shimizu 890ddd
        			break;
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        		//In case the worker was captured for dedication, check the task compatibility.
        Toshihiro Shimizu 890ddd
        		if (!canAdopt(task)) {
        Toshihiro Shimizu 890ddd
        			//some other worker may still take the task...
        Toshihiro Shimizu 890ddd
        			globalImpSlots->emitRefreshAssignments();
        Toshihiro Shimizu 890ddd
        			break;
        Toshihiro Shimizu 890ddd
        		}
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        		//Test its custom conditions
        Toshihiro Shimizu 890ddd
        		if (!task->customConditions()) {
        Toshihiro Shimizu 890ddd
        			++e;
        Toshihiro Shimizu 890ddd
        			idWaitingForAnotherTask = 1;
        Toshihiro Shimizu 890ddd
        		} else {
        Toshihiro Shimizu 890ddd
        			adoptTask(task);
        Toshihiro Shimizu 890ddd
        			it = globalImp->m_tasks.erase(it);
        Toshihiro Shimizu 890ddd
        Toshihiro Shimizu 890ddd
        			globalImpSlots->emitRefreshAssignments();
        Toshihiro Shimizu 890ddd
        			break;
        Toshihiro Shimizu 890ddd
        		}
        Toshihiro Shimizu 890ddd
        	}
        Toshihiro Shimizu 890ddd
        }