Line data Source code
1 : /****************************************************************************
2 : **
3 : ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 : ** Contact: http://www.qt-project.org/legal
5 : **
6 : ** This file is part of the QtCore module of the Qt Toolkit.
7 : **
8 : ** $QT_BEGIN_LICENSE:LGPL$
9 : ** Commercial License Usage
10 : ** Licensees holding valid commercial Qt licenses may use this file in
11 : ** accordance with the commercial license agreement provided with the
12 : ** Software or, alternatively, in accordance with the terms contained in
13 : ** a written agreement between you and Digia. For licensing terms and
14 : ** conditions see http://qt.digia.com/licensing. For further information
15 : ** use the contact form at http://qt.digia.com/contact-us.
16 : **
17 : ** GNU Lesser General Public License Usage
18 : ** Alternatively, this file may be used under the terms of the GNU Lesser
19 : ** General Public License version 2.1 as published by the Free Software
20 : ** Foundation and appearing in the file LICENSE.LGPL included in the
21 : ** packaging of this file. Please review the following information to
22 : ** ensure the GNU Lesser General Public License version 2.1 requirements
23 : ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 : **
25 : ** In addition, as a special exception, Digia gives you certain additional
26 : ** rights. These rights are described in the Digia Qt LGPL Exception
27 : ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 : **
29 : ** GNU General Public License Usage
30 : ** Alternatively, this file may be used under the terms of the GNU
31 : ** General Public License version 3.0 as published by the Free Software
32 : ** Foundation and appearing in the file LICENSE.GPL included in the
33 : ** packaging of this file. Please review the following information to
34 : ** ensure the GNU General Public License version 3.0 requirements will be
35 : ** met: http://www.gnu.org/copyleft/gpl.html.
36 : **
37 : **
38 : ** $QT_END_LICENSE$
39 : **
40 : ****************************************************************************/
41 :
42 : #ifndef QMUTEX_H
43 : #define QMUTEX_H
44 :
45 : #include <QtCore/qglobal.h>
46 : #include <QtCore/qatomic.h>
47 : #include <new>
48 :
49 : QT_BEGIN_NAMESPACE
50 :
51 :
52 : #if !defined(QT_NO_THREAD) && !defined(Q_QDOC)
53 :
54 : #ifdef Q_OS_LINUX
55 : # define QT_MUTEX_LOCK_NOEXCEPT Q_DECL_NOTHROW
56 : #else
57 : # define QT_MUTEX_LOCK_NOEXCEPT
58 : #endif
59 :
60 : class QMutexData;
61 :
62 : class Q_CORE_EXPORT QBasicMutex
63 : {
64 : public:
65 : inline void lock() QT_MUTEX_LOCK_NOEXCEPT {
66 : if (!fastTryLock())
67 : lockInternal();
68 : }
69 :
70 : inline void unlock() Q_DECL_NOTHROW {
71 : Q_ASSERT(d_ptr.load()); //mutex must be locked
72 : if (!fastTryUnlock())
73 : unlockInternal();
74 : }
75 :
76 : bool tryLock() Q_DECL_NOTHROW {
77 : return fastTryLock();
78 : }
79 :
80 : bool isRecursive(); //### Qt6: mark const
81 :
82 : private:
83 : inline bool fastTryLock() Q_DECL_NOTHROW {
84 : return d_ptr.testAndSetAcquire(0, dummyLocked());
85 : }
86 : inline bool fastTryUnlock() Q_DECL_NOTHROW {
87 : return d_ptr.testAndSetRelease(dummyLocked(), 0);
88 : }
89 : inline bool fastTryLock(QMutexData *¤t) Q_DECL_NOTHROW {
90 : return d_ptr.testAndSetAcquire(0, dummyLocked(), current);
91 : }
92 : inline bool fastTryUnlock(QMutexData *¤t) Q_DECL_NOTHROW {
93 : return d_ptr.testAndSetRelease(dummyLocked(), 0, current);
94 : }
95 :
96 : void lockInternal() QT_MUTEX_LOCK_NOEXCEPT;
97 : bool lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT;
98 : void unlockInternal() Q_DECL_NOTHROW;
99 :
100 : QBasicAtomicPointer<QMutexData> d_ptr;
101 : static inline QMutexData *dummyLocked() {
102 : return reinterpret_cast<QMutexData *>(quintptr(1));
103 : }
104 :
105 : friend class QMutex;
106 : friend class QMutexData;
107 : };
108 :
109 : class Q_CORE_EXPORT QMutex : public QBasicMutex {
110 : public:
111 : enum RecursionMode { NonRecursive, Recursive };
112 : explicit QMutex(RecursionMode mode = NonRecursive);
113 : ~QMutex();
114 :
115 : void lock() QT_MUTEX_LOCK_NOEXCEPT;
116 : bool tryLock(int timeout = 0) QT_MUTEX_LOCK_NOEXCEPT;
117 : void unlock() Q_DECL_NOTHROW;
118 :
119 : using QBasicMutex::isRecursive;
120 :
121 : private:
122 : Q_DISABLE_COPY(QMutex)
123 : friend class QMutexLocker;
124 : };
125 :
126 : class Q_CORE_EXPORT QMutexLocker
127 : {
128 : public:
129 15 : inline explicit QMutexLocker(QBasicMutex *m) QT_MUTEX_LOCK_NOEXCEPT
130 : {
131 15 : Q_ASSERT_X((reinterpret_cast<quintptr>(m) & quintptr(1u)) == quintptr(0),
132 15 : "QMutexLocker", "QMutex pointer is misaligned");
133 15 : val = quintptr(m);
134 15 : if (Q_LIKELY(m)) {
135 : // call QMutex::lock() instead of QBasicMutex::lock()
136 15 : static_cast<QMutex *>(m)->lock();
137 15 : val |= 1;
138 : }
139 15 : }
140 15 : inline ~QMutexLocker() { unlock(); }
141 :
142 15 : inline void unlock() Q_DECL_NOTHROW
143 : {
144 15 : if ((val & quintptr(1u)) == quintptr(1u)) {
145 15 : val &= ~quintptr(1u);
146 15 : mutex()->unlock();
147 : }
148 15 : }
149 :
150 : inline void relock() QT_MUTEX_LOCK_NOEXCEPT
151 : {
152 : if (val) {
153 : if ((val & quintptr(1u)) == quintptr(0u)) {
154 : mutex()->lock();
155 : val |= quintptr(1u);
156 : }
157 : }
158 : }
159 :
160 : #if defined(Q_CC_MSVC)
161 : #pragma warning( push )
162 : #pragma warning( disable : 4312 ) // ignoring the warning from /Wp64
163 : #endif
164 :
165 15 : inline QMutex *mutex() const
166 : {
167 15 : return reinterpret_cast<QMutex *>(val & ~quintptr(1u));
168 : }
169 :
170 : #if defined(Q_CC_MSVC)
171 : #pragma warning( pop )
172 : #endif
173 :
174 : private:
175 : Q_DISABLE_COPY(QMutexLocker)
176 :
177 : quintptr val;
178 : };
179 :
180 : #else // QT_NO_THREAD or Q_QDOC
181 :
182 : class Q_CORE_EXPORT QMutex
183 : {
184 : public:
185 : enum RecursionMode { NonRecursive, Recursive };
186 :
187 : inline explicit QMutex(RecursionMode mode = NonRecursive) { Q_UNUSED(mode); }
188 :
189 : inline void lock() {}
190 : inline bool tryLock(int timeout = 0) { Q_UNUSED(timeout); return true; }
191 : inline void unlock() {}
192 : inline bool isRecursive() { return true; }
193 :
194 : private:
195 : Q_DISABLE_COPY(QMutex)
196 : };
197 :
198 : class Q_CORE_EXPORT QMutexLocker
199 : {
200 : public:
201 : inline explicit QMutexLocker(QMutex *) {}
202 : inline ~QMutexLocker() {}
203 :
204 : inline void unlock() {}
205 : void relock() {}
206 : inline QMutex *mutex() const { return 0; }
207 :
208 : private:
209 : Q_DISABLE_COPY(QMutexLocker)
210 : };
211 :
212 : typedef QMutex QBasicMutex;
213 :
214 : #endif // QT_NO_THREAD or Q_QDOC
215 :
216 : QT_END_NAMESPACE
217 :
218 : #endif // QMUTEX_H
|