1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2016 Intel Corporation.
5** Copyright (C) 2012 Olivier Goffart <ogoffart@woboq.com>
6** Contact: https://www.qt.io/licensing/
7**
8** This file is part of the QtCore module of the Qt Toolkit.
9**
10** $QT_BEGIN_LICENSE:LGPL$
11** Commercial License Usage
12** Licensees holding valid commercial Qt licenses may use this file in
13** accordance with the commercial license agreement provided with the
14** Software or, alternatively, in accordance with the terms contained in
15** a written agreement between you and The Qt Company. For licensing terms
16** and conditions see https://www.qt.io/terms-conditions. For further
17** information use the contact form at https://www.qt.io/contact-us.
18**
19** GNU Lesser General Public License Usage
20** Alternatively, this file may be used under the terms of the GNU Lesser
21** General Public License version 3 as published by the Free Software
22** Foundation and appearing in the file LICENSE.LGPL3 included in the
23** packaging of this file. Please review the following information to
24** ensure the GNU Lesser General Public License version 3 requirements
25** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
26**
27** GNU General Public License Usage
28** Alternatively, this file may be used under the terms of the GNU
29** General Public License version 2.0 or (at your option) the GNU General
30** Public license version 3 or any later version approved by the KDE Free
31** Qt Foundation. The licenses are as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
33** included in the packaging of this file. Please review the following
34** information to ensure the GNU General Public License requirements will
35** be met: https://www.gnu.org/licenses/gpl-2.0.html and
36** https://www.gnu.org/licenses/gpl-3.0.html.
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef QMUTEX_P_H
43#define QMUTEX_P_H
44
45//
46// W A R N I N G
47// -------------
48//
49// This file is not part of the Qt API. It exists for the convenience
50// of qmutex.cpp, qmutex_unix.cpp, and qmutex_win.cpp. This header
51// file may change from version to version without notice, or even be
52// removed.
53//
54// We mean it.
55//
56
57#include <QtCore/private/qglobal_p.h>
58#include <QtCore/qnamespace.h>
59#include <QtCore/qmutex.h>
60#include <QtCore/qatomic.h>
61#include <QtCore/qdeadlinetimer.h>
62
63#if defined(Q_OS_MAC)
64# include <mach/semaphore.h>
65#elif defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
66// use Linux mutexes everywhere except for LSB builds
67# define QT_LINUX_FUTEX
68#elif defined(Q_OS_UNIX)
69# if _POSIX_VERSION-0 >= 200112L || _XOPEN_VERSION-0 >= 600
70# include <semaphore.h>
71# define QT_UNIX_SEMAPHORE
72# endif
73#endif
74
75struct timespec;
76
77QT_BEGIN_NAMESPACE
78
79#if !defined(QT_LINUX_FUTEX)
80class QMutexPrivate
81{
82public:
83 ~QMutexPrivate();
84 QMutexPrivate();
85
86 bool wait(int timeout = -1);
87 void wakeUp() noexcept;
88
89 // Control the lifetime of the privates
90 QAtomicInt refCount;
91 int id;
92
93 bool ref()
94 {
95 Q_ASSERT(refCount.loadRelaxed() >= 0);
96 int c;
97 do {
98 c = refCount.loadRelaxed();
99 if (c == 0)
100 return false;
101 } while (!refCount.testAndSetRelaxed(c, c + 1));
102 Q_ASSERT(refCount.loadRelaxed() >= 0);
103 return true;
104 }
105 void deref()
106 {
107 Q_ASSERT(refCount.loadRelaxed() >= 0);
108 if (!refCount.deref())
109 release();
110 Q_ASSERT(refCount.loadRelaxed() >= 0);
111 }
112 void release();
113 static QMutexPrivate *allocate();
114
115 QAtomicInt waiters; // Number of threads waiting on this mutex. (may be offset by -BigNumber)
116 QAtomicInt possiblyUnlocked; /* Boolean indicating that a timed wait timed out.
117 When it is true, a reference is held.
118 It is there to avoid a race that happens if unlock happens right
119 when the mutex is unlocked.
120 */
121 enum { BigNumber = 0x100000 }; //Must be bigger than the possible number of waiters (number of threads)
122 void derefWaiters(int value) noexcept;
123
124 //platform specific stuff
125#if defined(Q_OS_MAC)
126 semaphore_t mach_semaphore;
127#elif defined(QT_UNIX_SEMAPHORE)
128 sem_t semaphore;
129#elif defined(Q_OS_UNIX)
130 bool wakeup;
131 pthread_mutex_t mutex;
132 pthread_cond_t cond;
133#elif defined(Q_OS_WIN)
134 Qt::HANDLE event;
135#endif
136};
137#endif //QT_LINUX_FUTEX
138
139
140#ifdef Q_OS_UNIX
141// helper functions for qmutex_unix.cpp and qwaitcondition_unix.cpp
142// they are in qwaitcondition_unix.cpp actually
143void qt_initialize_pthread_cond(pthread_cond_t *cond, const char *where);
144void qt_abstime_for_timeout(struct timespec *ts, QDeadlineTimer deadline);
145#endif
146
147QT_END_NAMESPACE
148
149#endif // QMUTEX_P_H
150