File indexing completed on 2024-04-28 15:34:50

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     void cleanup(const JobPointer &job, Thread *) override
0057     {
0058         // Once job is unwrapped from us, this object is dangling. Job::executor points to the next higher up execute wrapper.
0059         // It is thus safe to "delete this". By no means add any later steps after delete!
0060         delete unwrap(job);
0061     }
0062 
0063 private:
0064     ThreadWeaver::Collection *collection;
0065 };
0066 
0067 Collection::Collection()
0068     : Job(new Private::Collection_Private)
0069 {
0070 }
0071 
0072 Collection::Collection(Private::Collection_Private *d__)
0073     : Job(d__)
0074 {
0075 }
0076 
0077 Collection::~Collection()
0078 {
0079     MUTEX_ASSERT_UNLOCKED(mutex());
0080     // dequeue all remaining jobs:
0081     QMutexLocker l(mutex());
0082     Q_UNUSED(l);
0083     if (d()->api != nullptr) { // still queued
0084         d()->dequeueElements(this, false);
0085     }
0086 }
0087 
0088 void Collection::addJob(JobPointer job)
0089 {
0090     QMutexLocker l(mutex());
0091     Q_UNUSED(l);
0092     REQUIRE(d()->api == nullptr || d()->selfIsExecuting == true); // not queued yet or still running
0093     REQUIRE(job != nullptr);
0094 
0095     CollectionExecuteWrapper *wrapper = new CollectionExecuteWrapper();
0096     wrapper->setCollection(this);
0097     wrapper->wrap(job->setExecutor(wrapper));
0098     d()->elements.append(job);
0099 }
0100 
0101 void Collection::stop(JobPointer job)
0102 {
0103     Q_UNUSED(job);
0104     QMutexLocker l(mutex());
0105     Q_UNUSED(l);
0106     d()->stop_locked(this);
0107 }
0108 
0109 void Collection::aboutToBeQueued_locked(QueueAPI *api)
0110 {
0111     Q_ASSERT(!mutex()->tryLock());
0112     Q_ASSERT(d()->api == nullptr); // never queue twice
0113     d()->api = api;
0114     d()->selfExecuteWrapper.wrap(setExecutor(&d()->selfExecuteWrapper));
0115     CollectionExecuteWrapper *wrapper = new CollectionExecuteWrapper();
0116     wrapper->setCollection(this);
0117     wrapper->wrap(setExecutor(wrapper));
0118     Job::aboutToBeQueued_locked(api);
0119 }
0120 
0121 void Collection::aboutToBeDequeued_locked(QueueAPI *api)
0122 {
0123     Q_ASSERT(!mutex()->tryLock());
0124     Q_ASSERT(api && d()->api == api);
0125     d()->dequeueElements(this, true);
0126     d()->api = nullptr;
0127     Job::aboutToBeDequeued_locked(api);
0128 }
0129 
0130 void Collection::execute(const JobPointer &job, Thread *thread)
0131 {
0132     {
0133         QMutexLocker l(mutex());
0134         Q_UNUSED(l);
0135         Q_ASSERT(d()->self.isNull());
0136         Q_ASSERT(d()->api != nullptr);
0137         d()->self = job;
0138         d()->selfIsExecuting = true; // reset in elementFinished
0139     }
0140     Job::execute(job, thread);
0141 }
0142 
0143 void Collection::run(JobPointer, Thread *)
0144 {
0145     // empty
0146 }
0147 
0148 Private::Collection_Private *Collection::d()
0149 {
0150     return reinterpret_cast<Private::Collection_Private *>(Job::d());
0151 }
0152 
0153 const Private::Collection_Private *Collection::d() const
0154 {
0155     return reinterpret_cast<const Private::Collection_Private *>(Job::d());
0156 }
0157 
0158 JobPointer Collection::jobAt(int i)
0159 {
0160     Q_ASSERT(!mutex()->tryLock());
0161     Q_ASSERT(i >= 0 && i < d()->elements.size());
0162     return d()->elements.at(i);
0163 }
0164 
0165 int Collection::elementCount() const
0166 {
0167     QMutexLocker l(mutex());
0168     Q_UNUSED(l);
0169     return jobListLength_locked();
0170 }
0171 
0172 #if THREADWEAVER_BUILD_DEPRECATED_SINCE(5, 0)
0173 int Collection::jobListLength() const
0174 {
0175     QMutexLocker l(mutex());
0176     Q_UNUSED(l);
0177     return jobListLength_locked();
0178 }
0179 #endif
0180 
0181 int Collection::jobListLength_locked() const
0182 {
0183     return d()->elements.size();
0184 }
0185 
0186 Collection &Collection::operator<<(JobInterface *job)
0187 {
0188     addJob(make_job(job));
0189     return *this;
0190 }
0191 
0192 Collection &Collection::operator<<(const JobPointer &job)
0193 {
0194     addJob(job);
0195     return *this;
0196 }
0197 
0198 Collection &Collection::operator<<(JobInterface &job)
0199 {
0200     addJob(make_job_raw(&job));
0201     return *this;
0202 }
0203 
0204 }