ThreadWeaver

dependencypolicy.cpp
1 /* -*- C++ -*-
2  This file implements the DependencyPolicy class.
3 
4  SPDX-FileCopyrightText: 2004-2013 Mirko Boehm <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 
8  $Id: DebuggingAids.cpp 20 2005-08-08 21:02:51Z mirko $
9 */
10 
11 #include "dependencypolicy.h"
12 
13 #include <QCoreApplication>
14 #include <QDebug>
15 #include <QMutex>
16 
17 #include "debuggingaids.h"
18 #include "job.h"
19 #include "managedjobpointer.h"
20 
21 #include "dependency.h"
22 
23 using namespace ThreadWeaver;
24 
26 
27 class Q_DECL_HIDDEN DependencyPolicy::Private
28 {
29 public:
30  /** A container to keep track of Job dependencies.
31  * For each dependency A->B, which means Job B depends on Job A and may only be executed after A has been
32  * finished, an entry will be added with key A and value B. When A is finished, the entry will be removed.
33  */
34  JobMultiMap &dependencies()
35  {
36  return depMap_;
37  }
38 
39  QMutex *mutex()
40  {
41  return &mutex_;
42  }
43 
44  JobMultiMap depMap_;
45  QMutex mutex_;
46 };
47 
48 DependencyPolicy::DependencyPolicy()
49  : QueuePolicy()
50  , d(new Private())
51 {
52 }
53 
55 {
56  delete d;
57 }
58 
60 {
61  // jobA depends on jobB
62  REQUIRE(jobA != nullptr && jobB != nullptr && jobA != jobB);
63 
64  QMutexLocker a(jobA->mutex());
65  QMutexLocker b(jobB->mutex());
66  QMutexLocker l(d->mutex());
67  jobA->assignQueuePolicy(this);
68  jobB->assignQueuePolicy(this);
69  d->dependencies().insert(jobA, jobB);
70  TWDEBUG(2, "inserted dependency %p->%p.\n", jobA.data(), jobB.data());
71  ENSURE(d->dependencies().contains(jobA));
72 }
73 
74 void DependencyPolicy::addDependency(const Dependency &dep)
75 {
76  addDependency(dep.dependent(), dep.dependee());
77 }
78 
80 {
81  REQUIRE(jobA != nullptr && jobB != nullptr);
82  bool result = false;
83  QMutexLocker l(d->mutex());
84 
85  // there may be only one (!) occurrence of [this, dep]:
86 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
87  QMutableMultiMapIterator<JobPointer, JobPointer> it(d->dependencies());
88 #else
89  QMutableMapIterator<JobPointer, JobPointer> it(d->dependencies());
90 #endif
91  while (it.hasNext()) {
92  it.next();
93  if (it.key() == jobA && it.value() == jobB) {
94  it.remove();
95  TWDEBUG(2, "removed dependency %p->%p.\n", jobA.data(), jobB.data());
96  result = true;
97  break;
98  }
99  }
100  TWDEBUG(result == false, 2, "cannot remove dependency %p->%p, not found.\n", jobA.data(), jobB.data());
101  ENSURE(!d->dependencies().keys(jobB).contains(jobA));
102  return result;
103 }
104 
105 bool DependencyPolicy::removeDependency(const Dependency &dep)
106 {
107  return removeDependency(dep.dependent(), dep.dependee());
108 }
109 
111 {
112  if (job->success()) {
113  QMutexLocker l(d->mutex());
114 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
115  QMutableMultiMapIterator<JobPointer, JobPointer> it(d->dependencies());
116 #else
117  QMutableMapIterator<JobPointer, JobPointer> it(d->dependencies());
118 #endif
119  // there has to be a better way to do this: (?)
120  while (it.hasNext()) { // we remove all entries where jobs depend on *this* :
121  it.next();
122  if (it.value() == job) {
123  TWDEBUG(2, "resolved dependencies for %p: %p->%p.\n", job.data(), it.key().data(), it.value().data());
124  it.remove();
125  }
126  }
127  }
128 }
129 
130 // QList<JobPointer> DependencyPolicy::getDependencies(JobPointer job) const
131 //{
132 // REQUIRE (job != 0);
133 // QList<JobInterface*> result;
134 // JobMultiMap::const_iterator it;
135 // QMutexLocker l( & d->mutex() );
136 
137 // for ( it = d->dependencies().constBegin(); it != d->dependencies().constEnd(); ++it )
138 // {
139 // if ( it.key() == job )
140 // {
141 // result.append( it.value() );
142 // }
143 // }
144 // return result;
145 //}
146 
148 {
149  REQUIRE(job != nullptr);
150  QMutexLocker l(d->mutex());
151  return d->dependencies().contains(job);
152 }
153 
154 bool DependencyPolicy::isEmpty() const
155 {
156  QMutexLocker l(d->mutex());
157  return d->dependencies().isEmpty();
158 }
159 
160 DependencyPolicy &DependencyPolicy::instance()
161 {
162  static DependencyPolicy policy;
163  return policy;
164 }
165 
167 {
168  REQUIRE(job != nullptr);
169  return !hasUnresolvedDependencies(job);
170 }
171 
173 {
174  REQUIRE(job != nullptr);
175  REQUIRE(job->status() > Job::Status_Running);
176  if (job->success()) {
177  resolveDependencies(job);
178  TWDEBUG(3, "DependencyPolicy::free: dependencies resolved for job %p.\n", (void *)job.data());
179  } else {
180  TWDEBUG(3, "DependencyPolicy::free: not resolving dependencies for %p (execution not successful).\n", (void *)job.data());
181  }
182  ENSURE((!hasUnresolvedDependencies(job) && job->success()) || !job->success());
183 }
184 
186 {
187  REQUIRE(job != nullptr);
188  Q_UNUSED(job)
189 }
190 
191 void DependencyPolicy::destructed(JobInterface *job)
192 {
193  REQUIRE(job != nullptr);
194  resolveDependencies(ManagedJobPointer<JobInterface>(job));
195 }
196 
197 // void DependencyPolicy::dumpJobDependencies()
198 //{
199 // QMutexLocker l( & d->mutex() );
200 
201 // debug ( 0, "Job Dependencies (left depends on right side):\n" );
202 // for ( JobMultiMap::const_iterator it = d->dependencies().constBegin(); it != d->dependencies().constEnd(); ++it )
203 // {
204 // debug( 0, " : %p <-- %p\n", (void*)it.key(), (void*)it.value());
205 // }
206 // debug ( 0, "-----------------\n" );
207 //}
bool hasNext() const const
T * data() const const
~DependencyPolicy() override
Destructor.
QMutableMapIterator::Item next()
bool removeDependency(JobPointer jobA, JobPointer jobB)
Remove a dependency.
void resolveDependencies(JobPointer)
Resolve all dependencies for a job.
void free(JobPointer) override
free() is called after the job has been executed.
DependencyPolicy implements execution-time dependencies dependencies between Jobs.
bool canRun(JobPointer) override
canRun() is called before the job is executed.
const Key & key() const const
bool hasUnresolvedDependencies(JobPointer) const
Query whether the job has an unresolved dependency.
QueuePolicy is an interface for customizations of the queueing behaviour of jobs.
Definition: queuepolicy.h:38
void release(JobPointer) override
release() is called if canRun() returned true, but the job has not been executed for external reasons...
void destructed(JobInterface *job) override
destructing() is called when a Job that has this queue policy assigned gets destructed.
void addDependency(JobPointer jobA, JobPointer jobB)
Add jobB as a dependency of jobA.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Feb 7 2023 04:09:38 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.