summaryrefslogtreecommitdiff
path: root/qmake/tools/qmutex_unix.cpp
Unidiff
Diffstat (limited to 'qmake/tools/qmutex_unix.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--qmake/tools/qmutex_unix.cpp687
1 files changed, 687 insertions, 0 deletions
diff --git a/qmake/tools/qmutex_unix.cpp b/qmake/tools/qmutex_unix.cpp
new file mode 100644
index 0000000..c861b2d
--- a/dev/null
+++ b/qmake/tools/qmutex_unix.cpp
@@ -0,0 +1,687 @@
1/****************************************************************************
2** $Id$
3**
4** QMutex 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
42typedef pthread_mutex_t Q_MUTEX_T;
43
44// POSIX threads mutex types
45#if ((defined(PTHREAD_MUTEX_RECURSIVE) && defined(PTHREAD_MUTEX_DEFAULT)) || \
46 defined(Q_OS_FREEBSD)) && !defined(Q_OS_UNIXWARE) && !defined(Q_OS_SOLARIS)
47 // POSIX 1003.1c-1995 - We love this OS
48# define Q_MUTEX_SET_TYPE(a, b) pthread_mutexattr_settype((a), (b))
49# if defined(QT_CHECK_RANGE)
50# define Q_NORMAL_MUTEX_TYPE PTHREAD_MUTEX_ERRORCHECK
51# else
52# define Q_NORMAL_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT
53# endif
54# define Q_RECURSIVE_MUTEX_TYPE PTHREAD_MUTEX_RECURSIVE
55#elif defined(MUTEX_NONRECURSIVE_NP) && defined(MUTEX_RECURSIVE_NP)
56// POSIX 1003.4a pthreads draft extensions
57# define Q_MUTEX_SET_TYPE(a, b) pthread_mutexattr_setkind_np((a), (b));
58# define Q_NORMAL_MUTEX_TYPE MUTEX_NONRECURSIVE_NP
59# define Q_RECURSIVE_MUTEX_TYPE MUTEX_RECURSIVE_NP
60#else
61// Unknown mutex types - skip them
62# define Q_MUTEX_SET_TYPE(a, b)
63# undef Q_NORMAL_MUTEX_TYPE
64# undef Q_RECURSIVE_MUTEX_TYPE
65#endif
66
67#include "qmutex.h"
68#include "qmutex_p.h"
69
70#include <errno.h>
71#include <string.h>
72
73
74// Private class declarations
75
76class QRealMutexPrivate : public QMutexPrivate {
77public:
78 QRealMutexPrivate(bool = FALSE);
79
80 void lock();
81 void unlock();
82 bool locked();
83 bool trylock();
84 int type() const;
85
86 bool recursive;
87};
88
89#ifndef Q_RECURSIVE_MUTEX_TYPE
90class QRecursiveMutexPrivate : public QMutexPrivate
91{
92public:
93 QRecursiveMutexPrivate();
94 ~QRecursiveMutexPrivate();
95
96 void lock();
97 void unlock();
98 bool locked();
99 bool trylock();
100 int type() const;
101
102 int count;
103 unsigned long owner;
104 pthread_mutex_t handle2;
105};
106#endif // !Q_RECURSIVE_MUTEX_TYPE
107
108
109// Private class implementation
110
111// base destructor
112QMutexPrivate::~QMutexPrivate()
113{
114 int ret = pthread_mutex_destroy(&handle);
115
116#ifdef QT_CHECK_RANGE
117 if ( ret )
118 qWarning( "Mutex destroy failure: %s", strerror( ret ) );
119#endif
120}
121
122// real mutex class
123QRealMutexPrivate::QRealMutexPrivate(bool recurs)
124 : recursive(recurs)
125{
126 pthread_mutexattr_t attr;
127 pthread_mutexattr_init(&attr);
128 Q_MUTEX_SET_TYPE(&attr, recursive ? Q_RECURSIVE_MUTEX_TYPE : Q_NORMAL_MUTEX_TYPE);
129 Q_UNUSED(recursive);
130 int ret = pthread_mutex_init(&handle, &attr);
131 pthread_mutexattr_destroy(&attr);
132
133#ifdef QT_CHECK_RANGE
134 if( ret )
135 qWarning( "Mutex init failure: %s", strerror( ret ) );
136#endif // QT_CHECK_RANGE
137}
138
139void QRealMutexPrivate::lock()
140{
141 int ret = pthread_mutex_lock(&handle);
142
143#ifdef QT_CHECK_RANGE
144 if (ret)
145 qWarning("Mutex lock failure: %s", strerror(ret));
146#endif
147}
148
149void QRealMutexPrivate::unlock()
150{
151 int ret = pthread_mutex_unlock(&handle);
152
153#ifdef QT_CHECK_RANGE
154 if (ret)
155 qWarning("Mutex unlock failure: %s", strerror(ret));
156#endif
157}
158
159bool QRealMutexPrivate::locked()
160{
161 int ret = pthread_mutex_trylock(&handle);
162
163 if (ret == EBUSY) {
164 return TRUE;
165 } else if (ret) {
166#ifdef QT_CHECK_RANGE
167 qWarning("Mutex locktest failure: %s", strerror(ret));
168#endif
169 } else
170 pthread_mutex_unlock(&handle);
171
172 return FALSE;
173}
174
175bool QRealMutexPrivate::trylock()
176{
177 int ret = pthread_mutex_trylock(&handle);
178
179 if (ret == EBUSY) {
180 return FALSE;
181 } else if (ret) {
182#ifdef QT_CHECK_RANGE
183 qWarning("Mutex trylock failure: %s", strerror(ret));
184#endif
185 return FALSE;
186 }
187
188 return TRUE;
189}
190
191int QRealMutexPrivate::type() const
192{
193 return recursive ? Q_MUTEX_RECURSIVE : Q_MUTEX_NORMAL;
194}
195
196
197#ifndef Q_RECURSIVE_MUTEX_TYPE
198QRecursiveMutexPrivate::QRecursiveMutexPrivate()
199 : count(0), owner(0)
200{
201 pthread_mutexattr_t attr;
202 pthread_mutexattr_init(&attr);
203 Q_MUTEX_SET_TYPE(&attr, Q_NORMAL_MUTEX_TYPE);
204 int ret = pthread_mutex_init(&handle, &attr);
205 pthread_mutexattr_destroy(&attr);
206
207# ifdef QT_CHECK_RANGE
208 if (ret)
209 qWarning( "Mutex init failure: %s", strerror(ret) );
210# endif
211
212 pthread_mutexattr_init(&attr);
213 ret = pthread_mutex_init( &handle2, &attr );
214 pthread_mutexattr_destroy(&attr);
215
216# ifdef QT_CHECK_RANGE
217 if (ret)
218 qWarning( "Mutex init failure: %s", strerror(ret) );
219# endif
220}
221
222QRecursiveMutexPrivate::~QRecursiveMutexPrivate()
223{
224 int ret = pthread_mutex_destroy(&handle2);
225
226# ifdef QT_CHECK_RANGE
227 if (ret)
228 qWarning( "Mutex destroy failure: %s", strerror(ret) );
229# endif
230}
231
232void QRecursiveMutexPrivate::lock()
233{
234 pthread_mutex_lock(&handle2);
235
236 if (count > 0 && owner == (unsigned long) pthread_self()) {
237 count++;
238 } else {
239 pthread_mutex_unlock(&handle2);
240 pthread_mutex_lock(&handle);
241 pthread_mutex_lock(&handle2);
242 count = 1;
243 owner = (unsigned long) pthread_self();
244 }
245
246 pthread_mutex_unlock(&handle2);
247}
248
249void QRecursiveMutexPrivate::unlock()
250{
251 pthread_mutex_lock(&handle2);
252
253 if (owner == (unsigned long) pthread_self()) {
254 // do nothing if the count is already 0... to reflect the behaviour described
255 // in the docs
256 if (count && (--count) < 1) {
257 count = 0;
258 pthread_mutex_unlock(&handle);
259 }
260 } else {
261#ifdef QT_CHECK_RANGE
262 qWarning("QMutex::unlock: unlock from different thread than locker");
263 qWarning(" was locked by %d, unlock attempt from %d",
264 (int)owner, (int)pthread_self());
265#endif
266 }
267
268 pthread_mutex_unlock(&handle2);
269}
270
271bool QRecursiveMutexPrivate::locked()
272{
273 pthread_mutex_lock(&handle2);
274
275 bool ret;
276 int code = pthread_mutex_trylock(&handle);
277
278 if (code == EBUSY) {
279 ret = TRUE;
280 } else {
281#ifdef QT_CHECK_RANGE
282 if (code)
283 qWarning("Mutex trylock failure: %s", strerror(code));
284#endif
285
286 pthread_mutex_unlock(&handle);
287 ret = FALSE;
288 }
289
290 pthread_mutex_unlock(&handle2);
291
292 return ret;
293}
294
295bool QRecursiveMutexPrivate::trylock()
296{
297 bool ret = TRUE;
298
299 pthread_mutex_lock(&handle2);
300
301 if ( count > 0 && owner == (unsigned long) pthread_self() ) {
302 count++;
303 } else {
304 int code = pthread_mutex_trylock(&handle);
305
306 if (code == EBUSY) {
307 ret = FALSE;
308 } else if (code) {
309#ifdef QT_CHECK_RANGE
310 qWarning("Mutex trylock failure: %s", strerror(code));
311#endif
312 ret = FALSE;
313 } else {
314 count = 1;
315 owner = (unsigned long) pthread_self();
316 }
317 }
318
319 pthread_mutex_unlock(&handle2);
320
321 return ret;
322}
323
324int QRecursiveMutexPrivate::type() const
325{
326 return Q_MUTEX_RECURSIVE;
327}
328
329#endif // !Q_RECURSIVE_MUTEX_TYPE
330
331
332/*!
333 \class QMutex qmutex.h
334 \threadsafe
335 \brief The QMutex class provides access serialization between threads.
336
337 \ingroup thread
338 \ingroup environment
339
340 The purpose of a QMutex is to protect an object, data structure or
341 section of code so that only one thread can access it at a time
342 (This is similar to the Java \c synchronized keyword). For
343 example, say there is a method which prints a message to the user
344 on two lines:
345
346 \code
347 int number = 6;
348
349 void method1()
350 {
351 number *= 5;
352 number /= 4;
353 }
354
355 void method1()
356 {
357 number *= 3;
358 number /= 2;
359 }
360 \endcode
361
362 If these two methods are called in succession, the following happens:
363
364 \code
365 // method1()
366 number *= 5;// number is now 30
367 number /= 4;// number is now 7
368
369 // method2()
370 number *= 3;// nubmer is now 21
371 number /= 2;// number is now 10
372 \endcode
373
374 If these two methods are called simultaneously from two threads then the
375 following sequence could result:
376
377 \code
378 // Thread 1 calls method1()
379 number *= 5;// number is now 30
380
381 // Thread 2 calls method2().
382 //
383 // Most likely Thread 1 has been put to sleep by the operating
384 // system to allow Thread 2 to run.
385 number *= 3;// number is now 90
386 number /= 2;// number is now 45
387
388 // Thread 1 finishes executing.
389 number /= 4;// number is now 11, instead of 10
390 \endcode
391
392 If we add a mutex, we should get the result we want:
393
394 \code
395 QMutex mutex;
396 int number = 6;
397
398 void method1()
399 {
400 mutex.lock();
401 number *= 5;
402 number /= 4;
403 mutex.unlock();
404 }
405
406 void method2()
407 {
408 mutex.lock();
409 number *= 3;
410 number /= 2;
411 mutex.unlock();
412 }
413 \endcode
414
415 Then only one thread can modify \c number at any given time and
416 the result is correct. This is a trivial example, of course, but
417 applies to any other case where things need to happen in a
418 particular sequence.
419
420 When you call lock() in a thread, other threads that try to call
421 lock() in the same place will block until the thread that got the
422 lock calls unlock(). A non-blocking alternative to lock() is
423 tryLock().
424*/
425
426/*!
427 Constructs a new mutex. The mutex is created in an unlocked state.
428 A recursive mutex is created if \a recursive is TRUE; a normal
429 mutex is created if \a recursive is FALSE (the default). With a
430 recursive mutex, a thread can lock the same mutex multiple times
431 and it will not be unlocked until a corresponding number of
432 unlock() calls have been made.
433*/
434QMutex::QMutex(bool recursive)
435{
436#ifndef Q_RECURSIVE_MUTEX_TYPE
437 if ( recursive )
438 d = new QRecursiveMutexPrivate();
439 else
440#endif // !Q_RECURSIVE_MUTEX_TYPE
441 d = new QRealMutexPrivate(recursive);
442}
443
444/*!
445 Destroys the mutex.
446
447 \warning If you destroy a mutex that still holds a lock the
448 resultant behavior is undefined.
449*/
450QMutex::~QMutex()
451{
452 delete d;
453}
454
455/*!
456 Attempt to lock the mutex. If another thread has locked the mutex
457 then this call will \e block until that thread has unlocked it.
458
459 \sa unlock(), locked()
460*/
461void QMutex::lock()
462{
463 d->lock();
464}
465
466/*!
467 Unlocks the mutex. Attempting to unlock a mutex in a different
468 thread to the one that locked it results in an error. Unlocking a
469 mutex that is not locked results in undefined behaviour (varies
470 between different Operating Systems' thread implementations).
471
472 \sa lock(), locked()
473*/
474void QMutex::unlock()
475{
476 d->unlock();
477}
478
479/*!
480 Returns TRUE if the mutex is locked by another thread; otherwise
481 returns FALSE.
482
483 \warning Due to differing implementations of recursive mutexes on
484 various platforms, calling this function from the same thread that
485 previously locked the mutex will return undefined results.
486
487 \sa lock(), unlock()
488*/
489bool QMutex::locked()
490{
491 return d->locked();
492}
493
494/*!
495 Attempt to lock the mutex. If the lock was obtained, this function
496 returns TRUE. If another thread has locked the mutex, this
497 function returns FALSE, instead of waiting for the mutex to become
498 available, i.e. it does not block.
499
500 If the lock was obtained, the mutex must be unlocked with unlock()
501 before another thread can successfully lock it.
502
503 \sa lock(), unlock(), locked()
504*/
505bool QMutex::tryLock()
506{
507 return d->trylock();
508}
509
510/*!
511 \class QMutexLocker qmutex.h
512 \brief The QMutexLocker class simplifies locking and unlocking QMutexes.
513
514 \threadsafe
515
516 \ingroup thread
517 \ingroup environment
518
519 The purpose of QMutexLocker is to simplify QMutex locking and
520 unlocking. Locking and unlocking a QMutex in complex functions and
521 statements or in exception handling code is error prone and
522 difficult to debug. QMutexLocker should be used in such situations
523 to ensure that the state of the mutex is well defined and always
524 locked and unlocked properly.
525
526 QMutexLocker should be created within a function where a QMutex
527 needs to be locked. The mutex is locked when QMutexLocker is
528 created, and unlocked when QMutexLocker is destroyed.
529
530 For example, this complex function locks a QMutex upon entering
531 the function and unlocks the mutex at all the exit points:
532
533 \code
534 int complexFunction( int flag )
535 {
536 mutex.lock();
537
538 int return_value = 0;
539
540 switch ( flag ) {
541 case 0:
542 case 1:
543 {
544 mutex.unlock();
545 return moreComplexFunction( flag );
546 }
547
548 case 2:
549 {
550 int status = anotherFunction();
551 if ( status < 0 ) {
552 mutex.unlock();
553 return -2;
554 }
555 return_value = status + flag;
556 break;
557 }
558
559 default:
560 {
561 if ( flag > 10 ) {
562 mutex.unlock();
563 return -1;
564 }
565 break;
566 }
567 }
568
569 mutex.unlock();
570 return return_value;
571 }
572 \endcode
573
574 This example function will get more complicated as it is
575 developed, which increases the likelihood that errors will occur.
576
577 Using QMutexLocker greatly simplifies the code, and makes it more
578 readable:
579
580 \code
581 int complexFunction( int flag )
582 {
583 QMutexLocker locker( &mutex );
584
585 int return_value = 0;
586
587 switch ( flag ) {
588 case 0:
589 case 1:
590 {
591 return moreComplexFunction( flag );
592 }
593
594 case 2:
595 {
596 int status = anotherFunction();
597 if ( status < 0 )
598 return -2;
599 return_value = status + flag;
600 break;
601 }
602
603 default:
604 {
605 if ( flag > 10 )
606 return -1;
607 break;
608 }
609 }
610
611 return return_value;
612 }
613 \endcode
614
615 Now, the mutex will always be unlocked when the QMutexLocker
616 object is destroyed (when the function returns since \c locker is
617 an auto variable).
618
619 The same principle applies to code that throws and catches
620 exceptions. An exception that is not caught in the function that
621 has locked the mutex has no way of unlocking the mutex before the
622 exception is passed up the stack to the calling function.
623
624 QMutexLocker also provides a mutex() member function that returns
625 the mutex on which the QMutexLocker is operating. This is useful
626 for code that needs access to the mutex, such as
627 QWaitCondition::wait(). For example:
628
629 \code
630 class SignalWaiter
631 {
632 private:
633 QMutexLocker locker;
634
635 public:
636 SignalWaiter( QMutex *mutex )
637 : locker( mutex )
638 {
639 }
640
641 void waitForSignal()
642 {
643 ...
644 ...
645 ...
646
647 while ( ! signalled )
648 waitcondition.wait( locker.mutex() );
649
650 ...
651 ...
652 ...
653 }
654 };
655 \endcode
656
657 \sa QMutex, QWaitCondition
658*/
659
660/*!
661 \fn QMutexLocker::QMutexLocker( QMutex *mutex )
662
663 Constructs a QMutexLocker and locks \a mutex. The mutex will be
664 unlocked when the QMutexLocker is destroyed.
665
666 \sa QMutex::lock()
667*/
668
669/*!
670 \fn QMutexLocker::~QMutexLocker()
671
672 Destroys the QMutexLocker and unlocks the mutex which was locked
673 in the constructor.
674
675 \sa QMutexLocker::QMutexLocker(), QMutex::unlock()
676*/
677
678/*!
679 \fn QMutex *QMutexLocker::mutex() const
680
681 Returns a pointer to the mutex which was locked in the
682 constructor.
683
684 \sa QMutexLocker::QMutexLocker()
685*/
686
687#endif // QT_THREAD_SUPPORT