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

0001 /* -*- C++ -*-
0002     This file is part of ThreadWeaver. It implements the Thread class.
0003 
0004     SPDX-FileCopyrightText: 2004-2013 Mirko Boehm <mirko@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 
0008     $Id: Thread.cpp 25 2005-08-14 12:41:38Z mirko $
0009 */
0010 
0011 #include "thread.h"
0012 
0013 #include <QCoreApplication>
0014 #include <QDebug>
0015 #include <QPointer>
0016 
0017 #include "debuggingaids.h"
0018 #include "exception.h"
0019 #include "job.h"
0020 #include "threadweaver.h"
0021 #include "weaver.h"
0022 
0023 using namespace ThreadWeaver;
0024 
0025 class Q_DECL_HIDDEN Thread::Private
0026 {
0027 public:
0028     explicit Private(Weaver *theParent)
0029         : parent(theParent)
0030         , id(makeId())
0031         , job(nullptr)
0032     {
0033         Q_ASSERT(parent);
0034     }
0035 
0036     Weaver *parent;
0037     const unsigned int id;
0038     JobPointer job;
0039     QMutex mutex;
0040 
0041     static unsigned int makeId()
0042     {
0043         static QAtomicInt s_id(1);
0044         return s_id.fetchAndAddRelease(1);
0045     }
0046 };
0047 
0048 Thread::Thread(Weaver *parent)
0049     : QThread() // no parent, because the QObject hierarchy of this thread
0050     // does not have a parent (see QObject::pushToThread)
0051     , d(new Private(parent))
0052 {
0053     const QString queueName =
0054         parent->objectName().isEmpty() ? QString::fromLatin1("Queue(0x%1)").arg(quintptr(parent), 0, 16, QChar::fromLatin1('0')) : parent->objectName();
0055     setObjectName(QString::fromLatin1("%1[%2]").arg(queueName).arg(QString::number(id()), 2, QChar::fromLatin1('0')));
0056 }
0057 
0058 Thread::~Thread()
0059 {
0060     delete d;
0061 }
0062 
0063 unsigned int Thread::id() const
0064 {
0065     return d->id; // id is const
0066 }
0067 
0068 void Thread::run()
0069 {
0070     Q_ASSERT(d->parent);
0071     Q_ASSERT(QCoreApplication::instance() != nullptr);
0072     d->parent->threadEnteredRun(this);
0073 
0074 #if THREADWEAVER_BUILD_DEPRECATED_SINCE(5, 80)
0075     Q_EMIT started(this);
0076 #endif
0077 
0078     TWDEBUG(3, "Thread::run [%u]: running.\n", id());
0079 
0080     bool wasBusy = false;
0081     while (true) {
0082         TWDEBUG(3, "Thread::run [%u]: trying to execute the next job.\n", id());
0083 
0084         try {
0085             // the assignment is intentional: newJob needs to go out of scope at the end of the if statement
0086             if (JobPointer newJob = d->parent->applyForWork(this, wasBusy)) {
0087                 QMutexLocker l(&d->mutex);
0088                 Q_UNUSED(l);
0089                 d->job = newJob;
0090             } else {
0091                 break;
0092             }
0093         } catch (AbortThread &) {
0094             break;
0095         }
0096 
0097         wasBusy = true;
0098         d->job->execute(d->job, this);
0099         JobPointer oldJob;
0100         { // When finally destroying the last reference to d->job, do not hold the mutex.
0101             // It may trigger destruction of the job, which can execute arbitrary code.
0102             QMutexLocker l(&d->mutex);
0103             Q_UNUSED(l);
0104             oldJob = d->job;
0105             d->job.clear();
0106         }
0107         oldJob.clear();
0108     }
0109     TWDEBUG(3, "Thread::run [%u]: exiting.\n", id());
0110 }
0111 
0112 void Thread::requestAbort()
0113 {
0114     QMutexLocker l(&d->mutex);
0115     Q_UNUSED(l);
0116     if (d->job) {
0117         d->job->requestAbort();
0118     }
0119 }
0120 
0121 #include "moc_thread.cpp"