File indexing completed on 2024-04-28 15:34:50

0001 /* -*- C++ -*-
0002     This file implements the DependencyPolicy class.
0003 
0004     SPDX-FileCopyrightText: 2004-2013 Mirko Boehm <mirko@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 
0008     $Id: DebuggingAids.cpp 20 2005-08-08 21:02:51Z mirko $
0009 */
0010 
0011 #include "dependencypolicy.h"
0012 
0013 #include <QCoreApplication>
0014 #include <QDebug>
0015 #include <QMutex>
0016 
0017 #include "debuggingaids.h"
0018 #include "job.h"
0019 #include "managedjobpointer.h"
0020 
0021 #include "dependency.h"
0022 
0023 using namespace ThreadWeaver;
0024 
0025 typedef QMultiMap<JobPointer, JobPointer> JobMultiMap;
0026 
0027 class Q_DECL_HIDDEN DependencyPolicy::Private
0028 {
0029 public:
0030     /** A container to keep track of Job dependencies.
0031      *  For each dependency A->B, which means Job B depends on Job A and may only be executed after A has been
0032      *  finished, an entry will be added with key A and value B. When A is finished, the entry will be removed.
0033      */
0034     JobMultiMap &dependencies()
0035     {
0036         return depMap_;
0037     }
0038 
0039     QMutex *mutex()
0040     {
0041         return &mutex_;
0042     }
0043 
0044     JobMultiMap depMap_;
0045     QMutex mutex_;
0046 };
0047 
0048 DependencyPolicy::DependencyPolicy()
0049     : QueuePolicy()
0050     , d(new Private())
0051 {
0052 }
0053 
0054 DependencyPolicy::~DependencyPolicy()
0055 {
0056     delete d;
0057 }
0058 
0059 void DependencyPolicy::addDependency(JobPointer jobA, JobPointer jobB)
0060 {
0061     // jobA depends on jobB
0062     REQUIRE(jobA != nullptr && jobB != nullptr && jobA != jobB);
0063 
0064     QMutexLocker a(jobA->mutex());
0065     QMutexLocker b(jobB->mutex());
0066     QMutexLocker l(d->mutex());
0067     jobA->assignQueuePolicy(this);
0068     jobB->assignQueuePolicy(this);
0069     d->dependencies().insert(jobA, jobB);
0070     TWDEBUG(2, "inserted dependency %p->%p.\n", jobA.data(), jobB.data());
0071     ENSURE(d->dependencies().contains(jobA));
0072 }
0073 
0074 void DependencyPolicy::addDependency(const Dependency &dep)
0075 {
0076     addDependency(dep.dependent(), dep.dependee());
0077 }
0078 
0079 bool DependencyPolicy::removeDependency(JobPointer jobA, JobPointer jobB)
0080 {
0081     REQUIRE(jobA != nullptr && jobB != nullptr);
0082     bool result = false;
0083     QMutexLocker l(d->mutex());
0084 
0085     // there may be only one (!) occurrence of [this, dep]:
0086 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0087     QMutableMultiMapIterator<JobPointer, JobPointer> it(d->dependencies());
0088 #else
0089     QMutableMapIterator<JobPointer, JobPointer> it(d->dependencies());
0090 #endif
0091     while (it.hasNext()) {
0092         it.next();
0093         if (it.key() == jobA && it.value() == jobB) {
0094             it.remove();
0095             TWDEBUG(2, "removed dependency %p->%p.\n", jobA.data(), jobB.data());
0096             result = true;
0097             break;
0098         }
0099     }
0100     TWDEBUG(result == false, 2, "cannot remove dependency %p->%p, not found.\n", jobA.data(), jobB.data());
0101     ENSURE(!d->dependencies().keys(jobB).contains(jobA));
0102     return result;
0103 }
0104 
0105 bool DependencyPolicy::removeDependency(const Dependency &dep)
0106 {
0107     return removeDependency(dep.dependent(), dep.dependee());
0108 }
0109 
0110 void DependencyPolicy::resolveDependencies(JobPointer job)
0111 {
0112     if (job->success()) {
0113         QMutexLocker l(d->mutex());
0114 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0115         QMutableMultiMapIterator<JobPointer, JobPointer> it(d->dependencies());
0116 #else
0117         QMutableMapIterator<JobPointer, JobPointer> it(d->dependencies());
0118 #endif
0119         // there has to be a better way to do this: (?)
0120         while (it.hasNext()) { // we remove all entries where jobs depend on *this* :
0121             it.next();
0122             if (it.value() == job) {
0123                 TWDEBUG(2, "resolved dependencies for %p: %p->%p.\n", job.data(), it.key().data(), it.value().data());
0124                 it.remove();
0125             }
0126         }
0127     }
0128 }
0129 
0130 // QList<JobPointer> DependencyPolicy::getDependencies(JobPointer job) const
0131 //{
0132 //    REQUIRE (job != 0);
0133 //    QList<JobInterface*> result;
0134 //    JobMultiMap::const_iterator it;
0135 //    QMutexLocker l( & d->mutex() );
0136 
0137 //    for ( it = d->dependencies().constBegin(); it != d->dependencies().constEnd(); ++it )
0138 //    {
0139 //        if ( it.key() == job )
0140 //        {
0141 //            result.append( it.value() );
0142 //        }
0143 //    }
0144 //    return result;
0145 //}
0146 
0147 bool DependencyPolicy::hasUnresolvedDependencies(JobPointer job) const
0148 {
0149     REQUIRE(job != nullptr);
0150     QMutexLocker l(d->mutex());
0151     return d->dependencies().contains(job);
0152 }
0153 
0154 bool DependencyPolicy::isEmpty() const
0155 {
0156     QMutexLocker l(d->mutex());
0157     return d->dependencies().isEmpty();
0158 }
0159 
0160 DependencyPolicy &DependencyPolicy::instance()
0161 {
0162     static DependencyPolicy policy;
0163     return policy;
0164 }
0165 
0166 bool DependencyPolicy::canRun(JobPointer job)
0167 {
0168     REQUIRE(job != nullptr);
0169     return !hasUnresolvedDependencies(job);
0170 }
0171 
0172 void DependencyPolicy::free(JobPointer job)
0173 {
0174     REQUIRE(job != nullptr);
0175     REQUIRE(job->status() > Job::Status_Running);
0176     if (job->success()) {
0177         resolveDependencies(job);
0178         TWDEBUG(3, "DependencyPolicy::free: dependencies resolved for job %p.\n", (void *)job.data());
0179     } else {
0180         TWDEBUG(3, "DependencyPolicy::free: not resolving dependencies for %p (execution not successful).\n", (void *)job.data());
0181     }
0182     ENSURE((!hasUnresolvedDependencies(job) && job->success()) || !job->success());
0183 }
0184 
0185 void DependencyPolicy::release(JobPointer job)
0186 {
0187     REQUIRE(job != nullptr);
0188     Q_UNUSED(job)
0189 }
0190 
0191 void DependencyPolicy::destructed(JobInterface *job)
0192 {
0193     REQUIRE(job != nullptr);
0194     resolveDependencies(ManagedJobPointer<JobInterface>(job));
0195 }
0196 
0197 // void DependencyPolicy::dumpJobDependencies()
0198 //{
0199 //    QMutexLocker l( & d->mutex() );
0200 
0201 //    debug ( 0, "Job Dependencies (left depends on right side):\n" );
0202 //    for ( JobMultiMap::const_iterator it = d->dependencies().constBegin(); it != d->dependencies().constEnd(); ++it )
0203 //    {
0204 //        debug( 0, "  : %p <-- %p\n", (void*)it.key(), (void*)it.value());
0205 //    }
0206 //    debug ( 0, "-----------------\n" );
0207 //}