Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwaitcondition_win.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
7#include "qnamespace.h"
8#include "qmutex.h"
10#include "qlist.h"
11#include "qalgorithms.h"
12
13#define Q_MUTEX_T void *
14#include <private/qmutex_p.h>
15#include <private/qreadwritelock_p.h>
16#include <qt_windows.h>
17
19
20//***********************************************************************
21// QWaitConditionPrivate
22// **********************************************************************
23
25{
26public:
27 inline QWaitConditionEvent() : priority(0), wokenUp(false)
28 {
29 event = CreateEvent(NULL, TRUE, FALSE, NULL);
30 }
31 inline ~QWaitConditionEvent() { CloseHandle(event); }
33 bool wokenUp;
35};
36
38
40{
41public:
42 QMutex mtx;
45
47 bool wait(QWaitConditionEvent *wce, QDeadlineTimer deadline);
48 void post(QWaitConditionEvent *wce, bool ret);
49};
50
52{
53 mtx.lock();
55 freeQueue.isEmpty() ? new QWaitConditionEvent : freeQueue.takeFirst();
56 wce->priority = GetThreadPriority(GetCurrentThread());
57 wce->wokenUp = false;
58
59 // insert 'wce' into the queue (sorted by priority)
60 int index = 0;
61 for (; index < queue.size(); ++index) {
62 QWaitConditionEvent *current = queue.at(index);
63 if (current->priority < wce->priority)
64 break;
65 }
66 queue.insert(index, wce);
67 mtx.unlock();
68
69 return wce;
70}
71
72bool QWaitConditionPrivate::wait(QWaitConditionEvent *wce, QDeadlineTimer deadline)
73{
74 // wait for the event
75 while (true) {
76 const DWORD timeout = deadline.isForever()
77 ? INFINITE
78 : DWORD(std::min(deadline.remainingTime(), qint64(INFINITE - 1)));
79
80 switch (WaitForSingleObjectEx(wce->event, timeout, FALSE)) {
81 case WAIT_OBJECT_0:
82 return true;
83 case WAIT_TIMEOUT:
84 if (deadline.hasExpired())
85 return false;
86 break;
87 default:
88 return false;
89 }
90 }
91}
92
94{
95 mtx.lock();
96
97 // remove 'wce' from the queue
98 queue.removeAll(wce);
99 ResetEvent(wce->event);
100 freeQueue.append(wce);
101
102 // wakeups delivered after the timeout should be forwarded to the next waiter
103 if (!ret && wce->wokenUp && !queue.isEmpty()) {
104 QWaitConditionEvent *other = queue.constFirst();
105 SetEvent(other->event);
106 other->wokenUp = true;
107 }
108
109 mtx.unlock();
110}
111
112//***********************************************************************
113// QWaitCondition implementation
114//***********************************************************************
115
116QWaitCondition::QWaitCondition()
117{
118 d = new QWaitConditionPrivate;
119}
120
121QWaitCondition::~QWaitCondition()
122{
123 if (!d->queue.isEmpty()) {
124 qWarning("QWaitCondition: Destroyed while threads are still waiting");
125 qDeleteAll(d->queue);
126 }
127
128 qDeleteAll(d->freeQueue);
129 delete d;
130}
131
132bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
133{
134 if (time == std::numeric_limits<unsigned long>::max())
135 return wait(mutex, QDeadlineTimer(QDeadlineTimer::Forever));
136 return wait(mutex, QDeadlineTimer(time));
137}
138
139bool QWaitCondition::wait(QMutex *mutex, QDeadlineTimer deadline)
140{
141 if (!mutex)
142 return false;
143
144 QWaitConditionEvent *wce = d->pre();
145 mutex->unlock();
146
147 bool returnValue = d->wait(wce, deadline);
148
149 mutex->lock();
150 d->post(wce, returnValue);
151
152 return returnValue;
153}
154
155bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
156{
157 if (time == std::numeric_limits<unsigned long>::max())
158 return wait(readWriteLock, QDeadlineTimer(QDeadlineTimer::Forever));
159 return wait(readWriteLock, QDeadlineTimer(time));
160}
161
162bool QWaitCondition::wait(QReadWriteLock *readWriteLock, QDeadlineTimer deadline)
163{
164 using namespace QReadWriteLockStates;
165
166 if (!readWriteLock)
167 return false;
168 auto previousState = QReadWriteLockPrivate::stateForWaitCondition(readWriteLock);
169 if (previousState == Unlocked)
170 return false;
171 if (previousState == RecursivelyLocked) {
172 qWarning("QWaitCondition: cannot wait on QReadWriteLocks with recursive lockForWrite()");
173 return false;
174 }
175
176 QWaitConditionEvent *wce = d->pre();
177 readWriteLock->unlock();
178
179 bool returnValue = d->wait(wce, deadline);
180
181 if (previousState == LockedForWrite)
182 readWriteLock->lockForWrite();
183 else
184 readWriteLock->lockForRead();
185 d->post(wce, returnValue);
186
187 return returnValue;
188}
189
190void QWaitCondition::wakeOne()
191{
192 // wake up the first waiting thread in the queue
193 QMutexLocker locker(&d->mtx);
194 for (QWaitConditionEvent *current : std::as_const(d->queue)) {
195 if (current->wokenUp)
196 continue;
197 SetEvent(current->event);
198 current->wokenUp = true;
199 break;
200 }
201}
202
203void QWaitCondition::wakeAll()
204{
205 // wake up the all threads in the queue
206 QMutexLocker locker(&d->mtx);
207 for (QWaitConditionEvent *current : std::as_const(d->queue)) {
208 SetEvent(current->event);
209 current->wokenUp = true;
210 }
211}
212
213QT_END_NAMESPACE
Definition qlist.h:80
bool wait(QWaitConditionEvent *wce, QDeadlineTimer deadline)
QWaitConditionEvent * pre()
void post(QWaitConditionEvent *wce, bool ret)
QList< QWaitConditionEvent * > EventQueue