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 //}