Diffstat (limited to 'qmake/tools/qwaitcondition_unix.cpp') (more/less context) (show whitespace changes)
-rw-r--r-- | qmake/tools/qwaitcondition_unix.cpp | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/qmake/tools/qwaitcondition_unix.cpp b/qmake/tools/qwaitcondition_unix.cpp new file mode 100644 index 0000000..99c1014 --- a/dev/null +++ b/qmake/tools/qwaitcondition_unix.cpp | |||
@@ -0,0 +1,310 @@ | |||
1 | /**************************************************************************** | ||
2 | ** $Id$ | ||
3 | ** | ||
4 | ** QWaitCondition class for Unix | ||
5 | ** | ||
6 | ** Created : 20010725 | ||
7 | ** | ||
8 | ** Copyright (C) 1992-2002 Trolltech AS. All rights reserved. | ||
9 | ** | ||
10 | ** This file is part of the tools module of the Qt GUI Toolkit. | ||
11 | ** | ||
12 | ** This file may be distributed under the terms of the Q Public License | ||
13 | ** as defined by Trolltech AS of Norway and appearing in the file | ||
14 | ** LICENSE.QPL included in the packaging of this file. | ||
15 | ** | ||
16 | ** This file may be distributed and/or modified under the terms of the | ||
17 | ** GNU General Public License version 2 as published by the Free Software | ||
18 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
19 | ** packaging of this file. | ||
20 | ** | ||
21 | ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition | ||
22 | ** licenses may use this file in accordance with the Qt Commercial License | ||
23 | ** Agreement provided with the Software. | ||
24 | ** | ||
25 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
26 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
27 | ** | ||
28 | ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for | ||
29 | ** information about Qt Commercial License Agreements. | ||
30 | ** See http://www.trolltech.com/qpl/ for QPL licensing information. | ||
31 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
32 | ** | ||
33 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
34 | ** not clear to you. | ||
35 | ** | ||
36 | **********************************************************************/ | ||
37 | |||
38 | #if defined(QT_THREAD_SUPPORT) | ||
39 | |||
40 | #include "qplatformdefs.h" | ||
41 | |||
42 | typedef pthread_mutex_t Q_MUTEX_T; | ||
43 | |||
44 | #include "qwaitcondition.h" | ||
45 | #include "qmutex.h" | ||
46 | #include "qmutex_p.h" | ||
47 | |||
48 | #include <errno.h> | ||
49 | #include <string.h> | ||
50 | |||
51 | |||
52 | struct QWaitConditionPrivate { | ||
53 | pthread_cond_t cond; | ||
54 | }; | ||
55 | |||
56 | |||
57 | /*! | ||
58 | \class QWaitCondition qwaitcondition.h | ||
59 | \threadsafe | ||
60 | \brief The QWaitCondition class allows waiting/waking for conditions between threads. | ||
61 | |||
62 | \ingroup thread | ||
63 | \ingroup environment | ||
64 | |||
65 | QWaitConditions allow a thread to tell other threads that some | ||
66 | sort of condition has been met; one or many threads can block | ||
67 | waiting for a QWaitCondition to set a condition with wakeOne() or | ||
68 | wakeAll(). Use wakeOne() to wake one randomly selected event or | ||
69 | wakeAll() to wake them all. For example, say we have three tasks | ||
70 | that should be performed every time the user presses a key; each | ||
71 | task could be split into a thread, each of which would have a | ||
72 | run() body like this: | ||
73 | |||
74 | \code | ||
75 | QWaitCondition key_pressed; | ||
76 | |||
77 | for (;;) { | ||
78 | key_pressed.wait(); // This is a QWaitCondition global variable | ||
79 | // Key was pressed, do something interesting | ||
80 | do_something(); | ||
81 | } | ||
82 | \endcode | ||
83 | |||
84 | A fourth thread would read key presses and wake the other three | ||
85 | threads up every time it receives one, like this: | ||
86 | |||
87 | \code | ||
88 | QWaitCondition key_pressed; | ||
89 | |||
90 | for (;;) { | ||
91 | getchar(); | ||
92 | // Causes any thread in key_pressed.wait() to return from | ||
93 | // that method and continue processing | ||
94 | key_pressed.wakeAll(); | ||
95 | } | ||
96 | \endcode | ||
97 | |||
98 | Note that the order the three threads are woken up in is | ||
99 | undefined, and that if some or all of the threads are still in | ||
100 | do_something() when the key is pressed, they won't be woken up | ||
101 | (since they're not waiting on the condition variable) and so the | ||
102 | task will not be performed for that key press. This can be | ||
103 | avoided by, for example, doing something like this: | ||
104 | |||
105 | \code | ||
106 | QMutex mymutex; | ||
107 | QWaitCondition key_pressed; | ||
108 | int mycount=0; | ||
109 | |||
110 | // Worker thread code | ||
111 | for (;;) { | ||
112 | key_pressed.wait(); // This is a QWaitCondition global variable | ||
113 | mymutex.lock(); | ||
114 | mycount++; | ||
115 | mymutex.unlock(); | ||
116 | do_something(); | ||
117 | mymutex.lock(); | ||
118 | mycount--; | ||
119 | mymutex.unlock(); | ||
120 | } | ||
121 | |||
122 | // Key reading thread code | ||
123 | for (;;) { | ||
124 | getchar(); | ||
125 | mymutex.lock(); | ||
126 | // Sleep until there are no busy worker threads | ||
127 | while( count > 0 ) { | ||
128 | mymutex.unlock(); | ||
129 | sleep( 1 ); | ||
130 | mymutex.lock(); | ||
131 | } | ||
132 | mymutex.unlock(); | ||
133 | key_pressed.wakeAll(); | ||
134 | } | ||
135 | \endcode | ||
136 | |||
137 | The mutexes are necessary because the results of two threads | ||
138 | attempting to change the value of the same variable simultaneously | ||
139 | are unpredictable. | ||
140 | */ | ||
141 | |||
142 | /*! | ||
143 | Constructs a new event signalling, i.e. wait condition, object. | ||
144 | */ | ||
145 | QWaitCondition::QWaitCondition() | ||
146 | { | ||
147 | d = new QWaitConditionPrivate; | ||
148 | |||
149 | int ret = pthread_cond_init(&d->cond, NULL); | ||
150 | |||
151 | #ifdef QT_CHECK_RANGE | ||
152 | if (ret) | ||
153 | qWarning( "Wait condition init failure: %s", strerror( ret ) ); | ||
154 | #endif | ||
155 | } | ||
156 | |||
157 | |||
158 | /*! | ||
159 | Deletes the event signalling, i.e. wait condition, object. | ||
160 | */ | ||
161 | QWaitCondition::~QWaitCondition() | ||
162 | { | ||
163 | int ret = pthread_cond_destroy(&d->cond); | ||
164 | |||
165 | if (ret) { | ||
166 | #ifdef QT_CHECK_RANGE | ||
167 | qWarning( "Wait condition destroy failure: %s", strerror( ret ) ); | ||
168 | #endif | ||
169 | |||
170 | // seems we have threads waiting on us, lets wake them up | ||
171 | pthread_cond_broadcast(&d->cond); | ||
172 | } | ||
173 | |||
174 | delete d; | ||
175 | } | ||
176 | |||
177 | /*! | ||
178 | This wakes one thread waiting on the QWaitCondition. The thread | ||
179 | that is woken up depends on the operating system's scheduling | ||
180 | policies, and cannot be controlled or predicted. | ||
181 | |||
182 | \sa wakeAll() | ||
183 | */ | ||
184 | void QWaitCondition::wakeOne() | ||
185 | { | ||
186 | int ret = pthread_cond_signal(&d->cond); | ||
187 | |||
188 | #ifdef QT_CHECK_RANGE | ||
189 | if (ret) | ||
190 | qWarning("Wait condition wakeOne failure: %s", strerror(ret)); | ||
191 | #endif | ||
192 | } | ||
193 | |||
194 | /*! | ||
195 | This wakes all threads waiting on the QWaitCondition. The order in | ||
196 | which the threads are woken up depends on the operating system's | ||
197 | scheduling policies, and cannot be controlled or predicted. | ||
198 | |||
199 | \sa wakeOne() | ||
200 | */ | ||
201 | void QWaitCondition::wakeAll() | ||
202 | { | ||
203 | int ret = pthread_cond_broadcast(&d->cond); | ||
204 | |||
205 | #ifdef QT_CHECK_RANGE | ||
206 | if (ret) | ||
207 | qWarning("Wait condition wakeAll failure: %s", strerror(ret)); | ||
208 | #endif | ||
209 | } | ||
210 | |||
211 | /*! | ||
212 | Wait on the thread event object. The thread calling this will | ||
213 | block until either of these conditions is met: | ||
214 | \list | ||
215 | \i Another thread signals it using wakeOne() or wakeAll(). This | ||
216 | function will return TRUE in this case. | ||
217 | \i \a time milliseconds has elapsed. If \a time is ULONG_MAX (the | ||
218 | default), then the wait will never timeout (the event must be | ||
219 | signalled). This function will return FALSE if the wait timed | ||
220 | out. | ||
221 | \endlist | ||
222 | |||
223 | \sa wakeOne(), wakeAll() | ||
224 | */ | ||
225 | bool QWaitCondition::wait(unsigned long time) | ||
226 | { | ||
227 | pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; | ||
228 | |||
229 | int ret; | ||
230 | if (time != ULONG_MAX) { | ||
231 | struct timeval tv; | ||
232 | gettimeofday(&tv, 0); | ||
233 | |||
234 | timespec ti; | ||
235 | ti.tv_nsec = (tv.tv_usec * 1000) + (time % 1000) * 1000; | ||
236 | ti.tv_sec = tv.tv_sec + (time / 1000) + ( ti.tv_nsec / 1000000000 ); | ||
237 | ti.tv_nsec %= 1000000000; | ||
238 | |||
239 | ret = pthread_cond_timedwait(&d->cond, &mutex, &ti); | ||
240 | } else | ||
241 | ret = pthread_cond_wait(&d->cond, &mutex); | ||
242 | |||
243 | #ifdef QT_CHECK_RANGE | ||
244 | if (ret && ret != ETIMEDOUT) | ||
245 | qWarning("Wait condition wait failure: %s",strerror(ret)); | ||
246 | #endif | ||
247 | |||
248 | return (ret == 0); | ||
249 | } | ||
250 | |||
251 | /*! | ||
252 | \overload | ||
253 | |||
254 | Release the locked \a mutex and wait on the thread event object. | ||
255 | The \a mutex must be initially locked by the calling thread. If \a | ||
256 | mutex is not in a locked state, this function returns immediately. | ||
257 | If \a mutex is a recursive mutex, this function returns | ||
258 | immediately. The \a mutex will be unlocked, and the calling thread | ||
259 | will block until either of these conditions is met: | ||
260 | \list | ||
261 | \i Another thread signals it using wakeOne() or wakeAll(). This | ||
262 | function will return TRUE in this case. | ||
263 | \i \a time milliseconds has elapsed. If \a time is ULONG_MAX (the | ||
264 | default), then the wait will never timeout (the event must be | ||
265 | signalled). This function will return FALSE if the wait timed | ||
266 | out. | ||
267 | \endlist | ||
268 | |||
269 | The mutex will be returned to the same locked state. This function | ||
270 | is provided to allow the atomic transition from the locked state | ||
271 | to the wait state. | ||
272 | |||
273 | \sa wakeOne(), wakeAll() | ||
274 | */ | ||
275 | bool QWaitCondition::wait(QMutex *mutex, unsigned long time) | ||
276 | { | ||
277 | if (! mutex) | ||
278 | return FALSE; | ||
279 | |||
280 | if (mutex->d->type() == Q_MUTEX_RECURSIVE) { | ||
281 | #ifdef QT_CHECK_RANGE | ||
282 | qWarning("Wait condition warning: using recursive mutexes with\n" | ||
283 | " wait conditions is undefined!"); | ||
284 | #endif | ||
285 | return FALSE; | ||
286 | } | ||
287 | |||
288 | int ret; | ||
289 | if (time != ULONG_MAX) { | ||
290 | struct timeval tv; | ||
291 | gettimeofday(&tv, 0); | ||
292 | |||
293 | timespec ti; | ||
294 | ti.tv_nsec = (tv.tv_usec * 1000) + (time % 1000) * 1000; | ||
295 | ti.tv_sec = tv.tv_sec + (time / 1000) + ( ti.tv_nsec / 1000000000 ); | ||
296 | ti.tv_nsec %= 1000000000; | ||
297 | |||
298 | ret = pthread_cond_timedwait(&d->cond, &mutex->d->handle, &ti); | ||
299 | } else | ||
300 | ret = pthread_cond_wait(&d->cond, &mutex->d->handle); | ||
301 | |||
302 | #ifdef QT_CHECK_RANGE | ||
303 | if (ret && ret != ETIMEDOUT) | ||
304 | qWarning("Wait condition wait failure: %s",strerror(ret)); | ||
305 | #endif | ||
306 | |||
307 | return (ret == 0); | ||
308 | } | ||
309 | |||
310 | #endif // QT_THREAD_SUPPORT | ||