1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QTHREADPOOL_P_H
41#define QTHREADPOOL_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists purely as an
48// implementation detail. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53//
54
55#include "QtCore/qmutex.h"
56#include "QtCore/qthread.h"
57#include "QtCore/qwaitcondition.h"
58#include "QtCore/qset.h"
59#include "QtCore/qqueue.h"
60#include "private/qobject_p.h"
61
62QT_REQUIRE_CONFIG(thread);
63
64QT_BEGIN_NAMESPACE
65
66class QDeadlineTimer;
67
68class QueuePage
69{
70public:
71 enum {
72 MaxPageSize = 256
73 };
74
75 QueuePage(QRunnable *runnable, int pri) : m_priority(pri) { push(runnable); }
76
77 bool isFull() { return m_lastIndex >= MaxPageSize - 1; }
78
79 bool isFinished() { return m_firstIndex > m_lastIndex; }
80
81 void push(QRunnable *runnable)
82 {
83 Q_ASSERT(runnable != nullptr);
84 Q_ASSERT(!isFull());
85 m_lastIndex += 1;
86 m_entries[m_lastIndex] = runnable;
87 }
88
89 void skipToNextOrEnd()
90 {
91 while (!isFinished() && m_entries[m_firstIndex] == nullptr) {
92 m_firstIndex += 1;
93 }
94 }
95
96 QRunnable *first()
97 {
98 Q_ASSERT(!isFinished());
99 QRunnable *runnable = m_entries[m_firstIndex];
100 Q_ASSERT(runnable);
101 return runnable;
102 }
103
104 QRunnable *pop()
105 {
106 Q_ASSERT(!isFinished());
107 QRunnable *runnable = first();
108 Q_ASSERT(runnable);
109
110 // clear the entry although this should not be necessary
111 m_entries[m_firstIndex] = nullptr;
112 m_firstIndex += 1;
113
114 // make sure the next runnable returned by first() is not a nullptr
115 skipToNextOrEnd();
116
117 return runnable;
118 }
119
120 bool tryTake(QRunnable *runnable)
121 {
122 Q_ASSERT(!isFinished());
123 for (int i = m_firstIndex; i <= m_lastIndex; i++) {
124 if (m_entries[i] == runnable) {
125 m_entries[i] = nullptr;
126 if (i == m_firstIndex) {
127 // make sure first() does not return a nullptr
128 skipToNextOrEnd();
129 }
130 return true;
131 }
132 }
133 return false;
134 }
135
136 int priority() const { return m_priority; }
137
138private:
139 int m_priority = 0;
140 int m_firstIndex = 0;
141 int m_lastIndex = -1;
142 QRunnable *m_entries[MaxPageSize];
143};
144
145class QThreadPoolThread;
146class Q_CORE_EXPORT QThreadPoolPrivate : public QObjectPrivate
147{
148 Q_DECLARE_PUBLIC(QThreadPool)
149 friend class QThreadPoolThread;
150
151public:
152 QThreadPoolPrivate();
153
154 bool tryStart(QRunnable *task);
155 void enqueueTask(QRunnable *task, int priority = 0);
156 int activeThreadCount() const;
157
158 void tryToStartMoreThreads();
159 bool tooManyThreadsActive() const;
160
161 void startThread(QRunnable *runnable = nullptr);
162 void reset();
163 bool waitForDone(int msecs);
164 bool waitForDone(const QDeadlineTimer &timer);
165 void clear();
166 void stealAndRunRunnable(QRunnable *runnable);
167 void deletePageIfFinished(QueuePage *page);
168
169 mutable QMutex mutex;
170 QSet<QThreadPoolThread *> allThreads;
171 QQueue<QThreadPoolThread *> waitingThreads;
172 QQueue<QThreadPoolThread *> expiredThreads;
173 QList<QueuePage *> queue;
174 QWaitCondition noActiveThreads;
175
176 int expiryTimeout = 30000;
177 int maxThreadCount = QThread::idealThreadCount();
178 int reservedThreads = 0;
179 int activeThreads = 0;
180 uint stackSize = 0;
181};
182
183QT_END_NAMESPACE
184
185#endif
186