1/* -*- C++ -*-
2 This file is part of ThreadWeaver. It implements the Thread class.
3
4 SPDX-FileCopyrightText: 2004-2013 Mirko Boehm <mirko@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7
8 $Id: Thread.cpp 25 2005-08-14 12:41:38Z mirko $
9*/
10
11#include "thread.h"
12
13#include <QCoreApplication>
14#include <QDebug>
15#include <QPointer>
16
17#include "debuggingaids.h"
18#include "exception.h"
19#include "job.h"
20#include "threadweaver.h"
21#include "weaver.h"
22
23using namespace ThreadWeaver;
24
25class Q_DECL_HIDDEN Thread::Private
26{
27public:
28 explicit Private(Weaver *theParent)
29 : parent(theParent)
30 , id(makeId())
31 , job(nullptr)
32 {
33 Q_ASSERT(parent);
34 }
35
36 Weaver *parent;
37 const unsigned int id;
38 JobPointer job;
39 QMutex mutex;
40
41 static unsigned int makeId()
42 {
43 static QAtomicInt s_id(1);
44 return s_id.fetchAndAddRelease(valueToAdd: 1);
45 }
46};
47
48Thread::Thread(Weaver *parent)
49 : QThread() // no parent, because the QObject hierarchy of this thread
50 // does not have a parent (see QObject::pushToThread)
51 , d(new Private(parent))
52{
53 const QString queueName =
54 parent->objectName().isEmpty() ? QString::fromLatin1(ba: "Queue(0x%1)").arg(a: quintptr(parent), fieldwidth: 0, base: 16, fillChar: QChar::fromLatin1(c: '0')) : parent->objectName();
55 setObjectName(QString::fromLatin1(ba: "%1[%2]").arg(a: queueName).arg(a: QString::number(id()), fieldWidth: 2, fillChar: QChar::fromLatin1(c: '0')));
56}
57
58Thread::~Thread()
59{
60 delete d;
61}
62
63unsigned int Thread::id() const
64{
65 return d->id; // id is const
66}
67
68void Thread::run()
69{
70 Q_ASSERT(d->parent);
71 Q_ASSERT(QCoreApplication::instance() != nullptr);
72 d->parent->threadEnteredRun(thread: this);
73
74 TWDEBUG(3, "Thread::run [%u]: running.\n", id());
75
76 bool wasBusy = false;
77 while (true) {
78 TWDEBUG(3, "Thread::run [%u]: trying to execute the next job.\n", id());
79
80 try {
81 // the assignment is intentional: newJob needs to go out of scope at the end of the if statement
82 if (JobPointer newJob = d->parent->applyForWork(thread: this, wasBusy)) {
83 QMutexLocker l(&d->mutex);
84 Q_UNUSED(l);
85 d->job = newJob;
86 } else {
87 break;
88 }
89 } catch (AbortThread &) {
90 break;
91 }
92
93 wasBusy = true;
94 d->job->execute(job: d->job, this);
95 JobPointer oldJob;
96 { // When finally destroying the last reference to d->job, do not hold the mutex.
97 // It may trigger destruction of the job, which can execute arbitrary code.
98 QMutexLocker l(&d->mutex);
99 Q_UNUSED(l);
100 oldJob = d->job;
101 d->job.clear();
102 }
103 oldJob.clear();
104 }
105 TWDEBUG(3, "Thread::run [%u]: exiting.\n", id());
106}
107
108void Thread::requestAbort()
109{
110 QMutexLocker l(&d->mutex);
111 Q_UNUSED(l);
112 if (d->job) {
113 d->job->requestAbort();
114 }
115}
116
117#include "moc_thread.cpp"
118

source code of threadweaver/src/thread.cpp