kdelibs/threadweaver/Weaver/DependencyPolicy.cpp
2015-09-30 10:37:53 +03:00

211 lines
5.6 KiB
C++

/* -*- C++ -*-
This file implements the DependencyPolicy class.
$ Author: Mirko Boehm $
$ Copyright: (C) 2004-2013 Mirko Boehm $
$ Contact: mirko@kde.org
http://www.kde.org
http://creative-destruction.me $
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
$Id: DebuggingAids.cpp 20 2005-08-08 21:02:51Z mirko $
*/
#include "DependencyPolicy.h"
#include <QtCore/QMutex>
#include <QtCore/QDebug>
#include "Job.h"
#include "DebuggingAids.h"
using namespace ThreadWeaver;
typedef QMultiMap<Job*, Job*> JobMultiMap;
class DependencyPolicy::Private
{
public:
/** A container to keep track of Job dependencies.
For each dependency A->B, which means Job B depends on Job A and
may only be executed after A has been finished, an entry will be
added with key A and value B. When A is finished, the entry will
be removed. */
JobMultiMap& dependencies()
{
static JobMultiMap depMap;
return depMap;
}
QMutex& mutex()
{
static QMutex s_mutex;
return s_mutex;
}
};
DependencyPolicy::DependencyPolicy()
: QueuePolicy()
, d ( new Private() )
{
}
DependencyPolicy::~DependencyPolicy()
{
delete d;
}
void DependencyPolicy::addDependency( Job* jobA, Job* jobB )
{
// jobA depends on jobB
REQUIRE ( jobA != 0 && jobB != 0 && jobA != jobB );
jobA->assignQueuePolicy( this );
jobB->assignQueuePolicy( this );
QMutexLocker l( & d->mutex() );
d->dependencies().insert( jobA, jobB );
ENSURE ( d->dependencies().contains (jobA));
}
bool DependencyPolicy::removeDependency( Job* jobA, Job* jobB )
{
REQUIRE (jobA != 0 && jobB != 0);
bool result = false;
QMutexLocker l( & d->mutex() );
// there may be only one (!) occurrence of [this, dep]:
QMutableMapIterator<Job*, Job*> it( d->dependencies () );
while ( it.hasNext() )
{
it.next();
if ( it.key()==jobA && it.value()==jobB )
{
it.remove();
result = true;
break;
}
}
ENSURE ( ! d->dependencies().keys(jobB).contains(jobA) );
return result;
}
void DependencyPolicy::resolveDependencies( Job* job )
{
if ( job->success() )
{
QMutexLocker l( & d->mutex() );
QMutableMapIterator<Job*, Job*> it( d->dependencies() );
// there has to be a better way to do this: (?)
while ( it.hasNext() )
{ // we remove all entries where jobs depend on *this* :
it.next();
if ( it.value()==job )
{
it.remove();
}
}
}
}
QList<Job*> DependencyPolicy::getDependencies( Job* job ) const
{
REQUIRE (job != 0);
QList<Job*> result;
// basicly JobMultiMap
QMapIterator<ThreadWeaver::Job*, ThreadWeaver::Job*> it(d->dependencies());
QMutexLocker l( & d->mutex() );
while ( it.hasNext() )
{
it.next();
if ( it.key() == job )
{
result.append( it.value() );
}
}
return result;
}
bool DependencyPolicy::hasUnresolvedDependencies( Job* job ) const
{
REQUIRE (job != 0);
QMutexLocker l( & d->mutex() );
return d->dependencies().contains( job );
}
DependencyPolicy& DependencyPolicy::instance ()
{
static DependencyPolicy policy;
return policy;
}
bool DependencyPolicy::canRun( Job* job )
{
REQUIRE (job != 0);
return ! hasUnresolvedDependencies( job );
}
void DependencyPolicy::free( Job* job )
{
REQUIRE (job != 0);
if ( job->success() )
{
resolveDependencies( job );
debug( 3, "DependencyPolicy::free: dependencies resolved for job %p.\n", (void*)job);
} else {
debug( 3, "DependencyPolicy::free: not resolving dependencies for %p (execution not successful).\n",
(void*)job);
}
ENSURE ( ( ! hasUnresolvedDependencies( job ) && job->success() ) || ! job->success() );
}
void DependencyPolicy::release( Job* job )
{
REQUIRE (job != 0); Q_UNUSED(job)
}
void DependencyPolicy::destructed( Job* job )
{
REQUIRE (job != 0);
resolveDependencies ( job );
}
void DependencyPolicy::dumpJobDependencies()
{
QMutexLocker l( & d->mutex() );
// basicly JobMultiMap
QMapIterator<ThreadWeaver::Job*, ThreadWeaver::Job*> it(d->dependencies());
debug ( 0, "Job Dependencies (left depends on right side):\n" );
while ( it.hasNext() )
{
it.next();
debug( 0, " : %p (%s%s) <-- %p (%s%s)\n",
(void*)it.key(),
it.key()->objectName().isEmpty() ? "" : qPrintable ( QString(it.key()->objectName() + QObject::tr ( " of type " )) ),
it.key()->metaObject()->className(),
(void*)it.value(),
it.value()->objectName().isEmpty() ? "" : qPrintable ( QString(it.value()->objectName() + QObject::tr ( " of type " )) ),
it.value()->metaObject()->className() );
}
debug ( 0, "-----------------\n" );
}