File indexing completed on 2024-04-28 04:01:22

0001 /* -*- C++ -*-
0002     This file implements the Collection class.
0003 
0004     SPDX-FileCopyrightText: 2004-2013 Mirko Boehm <mirko@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "collection.h"
0010 
0011 #include "collection_p.h"
0012 #include "debuggingaids.h"
0013 #include "queueapi.h"
0014 #include "queueing.h"
0015 
0016 #include <QList>
0017 #include <QObject>
0018 #include <QPointer>
0019 
0020 #include "dependencypolicy.h"
0021 #include "executewrapper_p.h"
0022 #include "thread.h"
0023 
0024 namespace ThreadWeaver
0025 {
0026 class CollectionExecuteWrapper : public ExecuteWrapper
0027 {
0028 public:
0029     CollectionExecuteWrapper()
0030         : collection(nullptr)
0031     {
0032     }
0033 
0034     void setCollection(Collection *collection_)
0035     {
0036         collection = collection_;
0037     }
0038 
0039     void begin(const JobPointer &job, Thread *thread) override
0040     {
0041         TWDEBUG(4, "CollectionExecuteWrapper::begin: collection %p\n", collection);
0042         ExecuteWrapper::begin(job, thread);
0043         Q_ASSERT(collection);
0044         collection->d()->elementStarted(collection, job, thread);
0045         ExecuteWrapper::begin(job, thread);
0046     }
0047 
0048     void end(const JobPointer &job, Thread *thread) override
0049     {
0050         TWDEBUG(4, "CollectionExecuteWrapper::end: collection %p\n", collection);
0051         Q_ASSERT(collection);
0052         ExecuteWrapper::end(job, thread);
0053         collection->d()->elementFinished(collection, job, thread);
0054     }
0055 
0056     bool ownedByJob() const override
0057     {
0058         return true;
0059     }
0060 
0061 private:
0062     ThreadWeaver::Collection *collection;
0063 };
0064 
0065 Collection::Collection()
0066     : Job(new Private::Collection_Private)
0067 {
0068 }
0069 
0070 Collection::Collection(Private::Collection_Private *d__)
0071     : Job(d__)
0072 {
0073 }
0074 
0075 Collection::~Collection()
0076 {
0077     MUTEX_ASSERT_UNLOCKED(mutex());
0078     // dequeue all remaining jobs:
0079     QMutexLocker l(mutex());
0080     Q_UNUSED(l);
0081     if (d()->api != nullptr) { // still queued
0082         d()->dequeueElements(this, false);
0083     }
0084 }
0085 
0086 void Collection::addJob(JobPointer job)
0087 {
0088     QMutexLocker l(mutex());
0089     Q_UNUSED(l);
0090     REQUIRE(d()->api == nullptr || d()->selfIsExecuting == true); // not queued yet or still running
0091     REQUIRE(job != nullptr);
0092 
0093     CollectionExecuteWrapper *wrapper = new CollectionExecuteWrapper();
0094     wrapper->setCollection(this);
0095     wrapper->wrap(job->setExecutor(wrapper));
0096     d()->elements.append(job);
0097 }
0098 
0099 void Collection::stop()
0100 {
0101     d()->stop(this);
0102 }
0103 
0104 void Collection::requestAbort()
0105 {
0106     Job::requestAbort();
0107     d()->requestAbort(this);
0108 }
0109 
0110 void Collection::aboutToBeQueued_locked(QueueAPI *api)
0111 {
0112     Q_ASSERT(!mutex()->tryLock());
0113     Q_ASSERT(d()->api == nullptr); // never queue twice
0114     d()->api = api;
0115     d()->selfExecuteWrapper.wrap(setExecutor(&d()->selfExecuteWrapper));
0116     CollectionExecuteWrapper *wrapper = new CollectionExecuteWrapper();
0117     wrapper->setCollection(this);
0118     wrapper->wrap(setExecutor(wrapper));
0119     Job::aboutToBeQueued_locked(api);
0120 }
0121 
0122 void Collection::aboutToBeDequeued_locked(QueueAPI *api)
0123 {
0124     Q_ASSERT(!mutex()->tryLock());
0125     Q_ASSERT(api && d()->api == api);
0126     d()->dequeueElements(this, true);
0127     d()->api = nullptr;
0128 
0129     Q_ASSERT(dynamic_cast<CollectionExecuteWrapper *>(executor()));
0130     auto wrapper = static_cast<CollectionExecuteWrapper *>(executor());
0131     wrapper->unwrap(this);
0132     delete wrapper;
0133 
0134     Q_ASSERT(executor() == &d()->selfExecuteWrapper);
0135     d()->selfExecuteWrapper.unwrap(this);
0136 
0137     Job::aboutToBeDequeued_locked(api);
0138 }
0139 
0140 void Collection::execute(const JobPointer &job, Thread *thread)
0141 {
0142     {
0143         QMutexLocker l(mutex());
0144         Q_UNUSED(l);
0145         Q_ASSERT(d()->self.isNull());
0146         Q_ASSERT(d()->api != nullptr);
0147         d()->self = job;
0148         d()->selfIsExecuting = true; // reset in elementFinished
0149     }
0150     Job::execute(job, thread);
0151 }
0152 
0153 void Collection::run(JobPointer, Thread *)
0154 {
0155     // empty
0156 }
0157 
0158 Private::Collection_Private *Collection::d()
0159 {
0160     return reinterpret_cast<Private::Collection_Private *>(Job::d());
0161 }
0162 
0163 const Private::Collection_Private *Collection::d() const
0164 {
0165     return reinterpret_cast<const Private::Collection_Private *>(Job::d());
0166 }
0167 
0168 JobPointer Collection::jobAt(int i)
0169 {
0170     Q_ASSERT(!mutex()->tryLock());
0171     Q_ASSERT(i >= 0 && i < d()->elements.size());
0172     return d()->elements.at(i);
0173 }
0174 
0175 int Collection::elementCount() const
0176 {
0177     QMutexLocker l(mutex());
0178     Q_UNUSED(l);
0179     return jobListLength_locked();
0180 }
0181 
0182 int Collection::jobListLength_locked() const
0183 {
0184     return d()->elements.size();
0185 }
0186 
0187 Collection &Collection::operator<<(JobInterface *job)
0188 {
0189     addJob(make_job(job));
0190     return *this;
0191 }
0192 
0193 Collection &Collection::operator<<(const JobPointer &job)
0194 {
0195     addJob(job);
0196     return *this;
0197 }
0198 
0199 Collection &Collection::operator<<(JobInterface &job)
0200 {
0201     addJob(make_job_raw(&job));
0202     return *this;
0203 }
0204 
0205 }