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 }