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

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     TWDEBUG(3, "Thread::run [%u]: running.\n", id());
0075 
0076     bool wasBusy = false;
0077     while (true) {
0078         TWDEBUG(3, "Thread::run [%u]: trying to execute the next job.\n", id());
0079 
0080         try {
0081             // the assignment is intentional: newJob needs to go out of scope at the end of the if statement
0082             if (JobPointer newJob = d->parent->applyForWork(this, wasBusy)) {
0083                 QMutexLocker l(&d->mutex);
0084                 Q_UNUSED(l);
0085                 d->job = newJob;
0086             } else {
0087                 break;
0088             }
0089         } catch (AbortThread &) {
0090             break;
0091         }
0092 
0093         wasBusy = true;
0094         d->job->execute(d->job, this);
0095         JobPointer oldJob;
0096         { // When finally destroying the last reference to d->job, do not hold the mutex.
0097             // It may trigger destruction of the job, which can execute arbitrary code.
0098             QMutexLocker l(&d->mutex);
0099             Q_UNUSED(l);
0100             oldJob = d->job;
0101             d->job.clear();
0102         }
0103         oldJob.clear();
0104     }
0105     TWDEBUG(3, "Thread::run [%u]: exiting.\n", id());
0106 }
0107 
0108 void Thread::requestAbort()
0109 {
0110     QMutexLocker l(&d->mutex);
0111     Q_UNUSED(l);
0112     if (d->job) {
0113         d->job->requestAbort();
0114     }
0115 }
0116 
0117 #include "moc_thread.cpp"