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
24namespace ThreadWeaver
25{
26class CollectionExecuteWrapper : public ExecuteWrapper
27{
28public:
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
61private:
62 ThreadWeaver::Collection *collection;
63};
64
65Collection::Collection()
66 : Job(new Private::Collection_Private)
67{
68}
69
70Collection::Collection(Private::Collection_Private *d__)
71 : Job(d__)
72{
73}
74
75Collection::~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
86void 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
99void Collection::stop()
100{
101 d()->stop(collection: this);
102}
103
104void Collection::requestAbort()
105{
106 Job::requestAbort();
107 d()->requestAbort(collection: this);
108}
109
110void 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
122void 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
140void 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
153void Collection::run(JobPointer, Thread *)
154{
155 // empty
156}
157
158Private::Collection_Private *Collection::d()
159{
160 return reinterpret_cast<Private::Collection_Private *>(Job::d());
161}
162
163const Private::Collection_Private *Collection::d() const
164{
165 return reinterpret_cast<const Private::Collection_Private *>(Job::d());
166}
167
168JobPointer 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
175int Collection::elementCount() const
176{
177 QMutexLocker l(mutex());
178 Q_UNUSED(l);
179 return jobListLength_locked();
180}
181
182int Collection::jobListLength_locked() const
183{
184 return d()->elements.size();
185}
186
187Collection &Collection::operator<<(JobInterface *job)
188{
189 addJob(job: make_job(job));
190 return *this;
191}
192
193Collection &Collection::operator<<(const JobPointer &job)
194{
195 addJob(job);
196 return *this;
197}
198
199Collection &Collection::operator<<(JobInterface &job)
200{
201 addJob(job: make_job_raw(job: &job));
202 return *this;
203}
204
205}
206

source code of threadweaver/src/collection.cpp