1 | /* -*- C++ -*- |
2 | This file implements the Collection class. |
3 | |
4 | SPDX-FileCopyrightText: 2004-2013 Mirko Boehm <mirko@kde.org> |
5 | |
6 | SPDX-License-Identifier: LGPL-2.0-or-later |
7 | */ |
8 | |
9 | #include "collection.h" |
10 | |
11 | #include "collection_p.h" |
12 | #include "debuggingaids.h" |
13 | #include "queueapi.h" |
14 | #include "queueing.h" |
15 | |
16 | #include <QList> |
17 | #include <QObject> |
18 | #include <QPointer> |
19 | |
20 | #include "dependencypolicy.h" |
21 | #include "executewrapper_p.h" |
22 | #include "thread.h" |
23 | |
24 | namespace ThreadWeaver |
25 | { |
26 | class CollectionExecuteWrapper : public ExecuteWrapper |
27 | { |
28 | public: |
29 | CollectionExecuteWrapper() |
30 | : collection(nullptr) |
31 | { |
32 | } |
33 | |
34 | void setCollection(Collection *collection_) |
35 | { |
36 | collection = collection_; |
37 | } |
38 | |
39 | void begin(const JobPointer &job, Thread *thread) override |
40 | { |
41 | TWDEBUG(4, "CollectionExecuteWrapper::begin: collection %p\n" , collection); |
42 | ExecuteWrapper::begin(job, thread); |
43 | Q_ASSERT(collection); |
44 | collection->d()->elementStarted(collection, job, thread); |
45 | ExecuteWrapper::begin(job, thread); |
46 | } |
47 | |
48 | void end(const JobPointer &job, Thread *thread) override |
49 | { |
50 | TWDEBUG(4, "CollectionExecuteWrapper::end: collection %p\n" , collection); |
51 | Q_ASSERT(collection); |
52 | ExecuteWrapper::end(job, thread); |
53 | collection->d()->elementFinished(collection, job, thread); |
54 | } |
55 | |
56 | bool ownedByJob() const override |
57 | { |
58 | return true; |
59 | } |
60 | |
61 | private: |
62 | ThreadWeaver::Collection *collection; |
63 | }; |
64 | |
65 | Collection::Collection() |
66 | : Job(new Private::Collection_Private) |
67 | { |
68 | } |
69 | |
70 | Collection::Collection(Private::Collection_Private *d__) |
71 | : Job(d__) |
72 | { |
73 | } |
74 | |
75 | Collection::~Collection() |
76 | { |
77 | MUTEX_ASSERT_UNLOCKED(mutex()); |
78 | // dequeue all remaining jobs: |
79 | QMutexLocker l(mutex()); |
80 | Q_UNUSED(l); |
81 | if (d()->api != nullptr) { // still queued |
82 | d()->dequeueElements(collection: this, queueApiIsLocked: false); |
83 | } |
84 | } |
85 | |
86 | void Collection::addJob(JobPointer job) |
87 | { |
88 | QMutexLocker l(mutex()); |
89 | Q_UNUSED(l); |
90 | REQUIRE(d()->api == nullptr || d()->selfIsExecuting == true); // not queued yet or still running |
91 | REQUIRE(job != nullptr); |
92 | |
93 | CollectionExecuteWrapper *wrapper = new CollectionExecuteWrapper(); |
94 | wrapper->setCollection(this); |
95 | wrapper->wrap(previous: job->setExecutor(wrapper)); |
96 | d()->elements.append(t: job); |
97 | } |
98 | |
99 | void Collection::stop() |
100 | { |
101 | d()->stop(collection: this); |
102 | } |
103 | |
104 | void Collection::requestAbort() |
105 | { |
106 | Job::requestAbort(); |
107 | d()->requestAbort(collection: this); |
108 | } |
109 | |
110 | void Collection::aboutToBeQueued_locked(QueueAPI *api) |
111 | { |
112 | Q_ASSERT(!mutex()->tryLock()); |
113 | Q_ASSERT(d()->api == nullptr); // never queue twice |
114 | d()->api = api; |
115 | d()->selfExecuteWrapper.wrap(previous: setExecutor(&d()->selfExecuteWrapper)); |
116 | CollectionExecuteWrapper *wrapper = new CollectionExecuteWrapper(); |
117 | wrapper->setCollection(this); |
118 | wrapper->wrap(previous: setExecutor(wrapper)); |
119 | Job::aboutToBeQueued_locked(api); |
120 | } |
121 | |
122 | void Collection::aboutToBeDequeued_locked(QueueAPI *api) |
123 | { |
124 | Q_ASSERT(!mutex()->tryLock()); |
125 | Q_ASSERT(api && d()->api == api); |
126 | d()->dequeueElements(collection: this, queueApiIsLocked: true); |
127 | d()->api = nullptr; |
128 | |
129 | Q_ASSERT(dynamic_cast<CollectionExecuteWrapper *>(executor())); |
130 | auto wrapper = static_cast<CollectionExecuteWrapper *>(executor()); |
131 | wrapper->unwrap(job: this); |
132 | delete wrapper; |
133 | |
134 | Q_ASSERT(executor() == &d()->selfExecuteWrapper); |
135 | d()->selfExecuteWrapper.unwrap(job: this); |
136 | |
137 | Job::aboutToBeDequeued_locked(api); |
138 | } |
139 | |
140 | void Collection::execute(const JobPointer &job, Thread *thread) |
141 | { |
142 | { |
143 | QMutexLocker l(mutex()); |
144 | Q_UNUSED(l); |
145 | Q_ASSERT(d()->self.isNull()); |
146 | Q_ASSERT(d()->api != nullptr); |
147 | d()->self = job; |
148 | d()->selfIsExecuting = true; // reset in elementFinished |
149 | } |
150 | Job::execute(job, thread); |
151 | } |
152 | |
153 | void Collection::run(JobPointer, Thread *) |
154 | { |
155 | // empty |
156 | } |
157 | |
158 | Private::Collection_Private *Collection::d() |
159 | { |
160 | return reinterpret_cast<Private::Collection_Private *>(Job::d()); |
161 | } |
162 | |
163 | const Private::Collection_Private *Collection::d() const |
164 | { |
165 | return reinterpret_cast<const Private::Collection_Private *>(Job::d()); |
166 | } |
167 | |
168 | JobPointer Collection::jobAt(int i) |
169 | { |
170 | Q_ASSERT(!mutex()->tryLock()); |
171 | Q_ASSERT(i >= 0 && i < d()->elements.size()); |
172 | return d()->elements.at(i); |
173 | } |
174 | |
175 | int Collection::elementCount() const |
176 | { |
177 | QMutexLocker l(mutex()); |
178 | Q_UNUSED(l); |
179 | return jobListLength_locked(); |
180 | } |
181 | |
182 | int Collection::jobListLength_locked() const |
183 | { |
184 | return d()->elements.size(); |
185 | } |
186 | |
187 | Collection &Collection::operator<<(JobInterface *job) |
188 | { |
189 | addJob(job: make_job(job)); |
190 | return *this; |
191 | } |
192 | |
193 | Collection &Collection::operator<<(const JobPointer &job) |
194 | { |
195 | addJob(job); |
196 | return *this; |
197 | } |
198 | |
199 | Collection &Collection::operator<<(JobInterface &job) |
200 | { |
201 | addJob(job: make_job_raw(job: &job)); |
202 | return *this; |
203 | } |
204 | |
205 | } |
206 | |