Root/
Source at commit 1322 created 12 years 8 months ago. By meklort, Add doxygen to utils folder | |
---|---|
1 | /****************************************************************************␊ |
2 | **␊ |
3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).␊ |
4 | ** Contact: Nokia Corporation (qt-info@nokia.com)␊ |
5 | **␊ |
6 | ** This file is part of the QtCore module of the Qt Toolkit.␊ |
7 | **␊ |
8 | ** $QT_BEGIN_LICENSE:LGPL$␊ |
9 | ** No Commercial Usage␊ |
10 | ** This file contains pre-release code and may not be distributed.␊ |
11 | ** You may use this file in accordance with the terms and conditions␊ |
12 | ** contained in the either Technology Preview License Agreement or the␊ |
13 | ** Beta Release License Agreement.␊ |
14 | **␊ |
15 | ** GNU Lesser General Public License Usage␊ |
16 | ** Alternatively, this file may be used under the terms of the GNU Lesser␊ |
17 | ** General Public License version 2.1 as published by the Free Software␊ |
18 | ** Foundation and appearing in the file LICENSE.LGPL included in the␊ |
19 | ** packaging of this file. Please review the following information to␊ |
20 | ** ensure the GNU Lesser General Public License version 2.1 requirements␊ |
21 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.␊ |
22 | **␊ |
23 | ** In addition, as a special exception, Nokia gives you certain␊ |
24 | ** additional rights. These rights are described in the Nokia Qt LGPL␊ |
25 | ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this␊ |
26 | ** package.␊ |
27 | **␊ |
28 | ** GNU General Public License Usage␊ |
29 | ** Alternatively, this file may be used under the terms of the GNU␊ |
30 | ** General Public License version 3.0 as published by the Free Software␊ |
31 | ** Foundation and appearing in the file LICENSE.GPL included in the␊ |
32 | ** packaging of this file. Please review the following information to␊ |
33 | ** ensure the GNU General Public License version 3.0 requirements will be␊ |
34 | ** met: http://www.gnu.org/copyleft/gpl.html.␊ |
35 | **␊ |
36 | ** If you are unsure which license is appropriate for your use, please␊ |
37 | ** contact the sales department at http://www.qtsoftware.com/contact.␊ |
38 | ** $QT_END_LICENSE$␊ |
39 | **␊ |
40 | ****************************************************************************/␊ |
41 | ␊ |
42 | #include <windows.h>␊ |
43 | #include "qwaitcondition.h"␊ |
44 | #include "qmutex.h"␊ |
45 | #include "qlist.h"␊ |
46 | ␊ |
47 | //***********************************************************************␊ |
48 | // QWaitConditionPrivate␊ |
49 | // **********************************************************************␊ |
50 | ␊ |
51 | class QWaitConditionEvent␊ |
52 | {␊ |
53 | public:␊ |
54 | QWaitConditionEvent() : priority(0), wokenUp(false)␊ |
55 | {␊ |
56 | event = CreateEvent(NULL, TRUE, FALSE, NULL);␊ |
57 | }␊ |
58 | ~QWaitConditionEvent() { CloseHandle(event); }␊ |
59 | int priority;␊ |
60 | bool wokenUp;␊ |
61 | HANDLE event;␊ |
62 | };␊ |
63 | ␊ |
64 | class EventQueue : public QList<QWaitConditionEvent>␊ |
65 | {␊ |
66 | public:␊ |
67 | EventQueue() { setAutoDelete(TRUE); }␊ |
68 | ~EventQueue() {}␊ |
69 | };␊ |
70 | ␊ |
71 | class QWaitConditionPrivate␊ |
72 | {␊ |
73 | public:␊ |
74 | QMutex mtx;␊ |
75 | EventQueue queue;␊ |
76 | EventQueue freeQueue;␊ |
77 | ␊ |
78 | QWaitConditionEvent *pre();␊ |
79 | void wait(QWaitConditionEvent *wce);␊ |
80 | void post(QWaitConditionEvent *wce);␊ |
81 | };␊ |
82 | ␊ |
83 | QWaitConditionEvent *QWaitConditionPrivate::pre()␊ |
84 | {␊ |
85 | mtx.lock();␊ |
86 | QWaitConditionEvent *wce =␊ |
87 | freeQueue.isEmpty() ? new QWaitConditionEvent : freeQueue.take(0);␊ |
88 | wce->priority = GetThreadPriority(GetCurrentThread());␊ |
89 | wce->wokenUp = FALSE;␊ |
90 | ␊ |
91 | // insert 'wce' into the queue (sorted by priority)␊ |
92 | uint index = 0;␊ |
93 | for (; index < queue.count(); ++index)␊ |
94 | {␊ |
95 | QWaitConditionEvent *current = queue.at(index);␊ |
96 | if (current->priority < wce->priority)␊ |
97 | break;␊ |
98 | }␊ |
99 | queue.insert(index, wce);␊ |
100 | mtx.unlock();␊ |
101 | ␊ |
102 | return wce;␊ |
103 | }␊ |
104 | ␊ |
105 | void QWaitConditionPrivate::wait(QWaitConditionEvent *wce)␊ |
106 | {␊ |
107 | WaitForSingleObject(wce->event, INFINITE);␊ |
108 | }␊ |
109 | ␊ |
110 | void QWaitConditionPrivate::post(QWaitConditionEvent *wce)␊ |
111 | {␊ |
112 | mtx.lock();␊ |
113 | ␊ |
114 | // remove 'wce' from the queue␊ |
115 | int idx = queue.find(wce);␊ |
116 | ASSERT(idx!=-1);␊ |
117 | queue.take(idx);␊ |
118 | ResetEvent(wce->event);␊ |
119 | freeQueue.append(wce);␊ |
120 | ␊ |
121 | // wakeups delivered after the timeout should be forwarded to the next waiter␊ |
122 | if (wce->wokenUp && !queue.isEmpty())␊ |
123 | {␊ |
124 | QWaitConditionEvent *other = queue.getFirst();␊ |
125 | SetEvent(other->event);␊ |
126 | other->wokenUp = TRUE;␊ |
127 | }␊ |
128 | ␊ |
129 | mtx.unlock();␊ |
130 | }␊ |
131 | ␊ |
132 | //***********************************************************************␊ |
133 | // QWaitCondition implementation␊ |
134 | //***********************************************************************␊ |
135 | ␊ |
136 | QWaitCondition::QWaitCondition()␊ |
137 | {␊ |
138 | d = new QWaitConditionPrivate;␊ |
139 | }␊ |
140 | ␊ |
141 | QWaitCondition::~QWaitCondition()␊ |
142 | {␊ |
143 | if (!d->queue.isEmpty())␊ |
144 | {␊ |
145 | qWarning("QWaitCondition: Destroyed while threads are still waiting");␊ |
146 | }␊ |
147 | delete d;␊ |
148 | }␊ |
149 | ␊ |
150 | void QWaitCondition::wait(QMutex *mutex)␊ |
151 | {␊ |
152 | if (!mutex) return;␊ |
153 | ␊ |
154 | QWaitConditionEvent *wce = d->pre();␊ |
155 | mutex->unlock();␊ |
156 | d->wait(wce);␊ |
157 | mutex->lock();␊ |
158 | d->post(wce);␊ |
159 | }␊ |
160 | ␊ |
161 | void QWaitCondition::wakeOne()␊ |
162 | {␊ |
163 | // wake up the first waiting thread in the queue␊ |
164 | QMutexLocker locker(&d->mtx);␊ |
165 | for (uint i = 0; i < d->queue.count(); ++i)␊ |
166 | {␊ |
167 | QWaitConditionEvent *current = d->queue.at(i);␊ |
168 | if (current->wokenUp) continue;␊ |
169 | SetEvent(current->event);␊ |
170 | current->wokenUp = TRUE;␊ |
171 | break;␊ |
172 | }␊ |
173 | }␊ |
174 | ␊ |
175 | void QWaitCondition::wakeAll()␊ |
176 | {␊ |
177 | // wake up the all threads in the queue␊ |
178 | QMutexLocker locker(&d->mtx);␊ |
179 | for (uint i = 0; i < d->queue.count(); ++i) ␊ |
180 | {␊ |
181 | QWaitConditionEvent *current = d->queue.at(i);␊ |
182 | SetEvent(current->event);␊ |
183 | current->wokenUp = TRUE;␊ |
184 | }␊ |
185 | }␊ |
186 | ␊ |
187 |