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