1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QSHAREDMEMORY_P_H
5#define QSHAREDMEMORY_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include "qsharedmemory.h"
19
20#include <QtCore/qstring.h>
21
22#if QT_CONFIG(sharedmemory)
23#include "qsystemsemaphore.h"
24#include "qtipccommon_p.h"
25#include "private/qobject_p.h"
26
27#if QT_CONFIG(posix_shm)
28# include <sys/mman.h>
29#endif
30#if QT_CONFIG(sysv_shm)
31# include <sys/shm.h>
32#endif
33
34QT_BEGIN_NAMESPACE
35
36class QSharedMemoryPrivate;
37
38#if QT_CONFIG(systemsemaphore)
39/*!
40 Helper class
41 */
42class QSharedMemoryLocker
43{
44
45public:
46 Q_NODISCARD_CTOR QSharedMemoryLocker(QSharedMemory *sharedMemory) : q_sm(sharedMemory)
47 {
48 Q_ASSERT(q_sm);
49 }
50
51 inline ~QSharedMemoryLocker()
52 {
53 if (q_sm)
54 q_sm->unlock();
55 }
56
57 inline bool lock()
58 {
59 if (q_sm && q_sm->lock())
60 return true;
61 q_sm = nullptr;
62 return false;
63 }
64
65private:
66 QSharedMemory *q_sm;
67};
68#endif // QT_CONFIG(systemsemaphore)
69
70class QSharedMemoryPosix
71{
72public:
73 static constexpr bool Enabled = QT_CONFIG(posix_shm);
74 static bool supports(QNativeIpcKey::Type type)
75 { return type == QNativeIpcKey::Type::PosixRealtime; }
76 static bool runtimeSupportCheck();
77
78 bool handle(QSharedMemoryPrivate *self);
79 bool cleanHandle(QSharedMemoryPrivate *self);
80 bool create(QSharedMemoryPrivate *self, qsizetype size);
81 bool attach(QSharedMemoryPrivate *self, QSharedMemory::AccessMode mode);
82 bool detach(QSharedMemoryPrivate *self);
83
84 int hand = -1;
85};
86
87class QSharedMemorySystemV
88{
89public:
90 static constexpr bool Enabled = QT_CONFIG(sysv_shm);
91 static bool supports(QNativeIpcKey::Type type)
92 { return quint16(type) <= 0xff; }
93 static bool runtimeSupportCheck();
94
95#if QT_CONFIG(sysv_sem)
96 key_t handle(QSharedMemoryPrivate *self);
97 bool cleanHandle(QSharedMemoryPrivate *self);
98 bool create(QSharedMemoryPrivate *self, qsizetype size);
99 bool attach(QSharedMemoryPrivate *self, QSharedMemory::AccessMode mode);
100 bool detach(QSharedMemoryPrivate *self);
101
102private:
103 void updateNativeKeyFile(const QNativeIpcKey &nativeKey);
104
105 QByteArray nativeKeyFile;
106 key_t unix_key = 0;
107#endif
108};
109
110class QSharedMemoryWin32
111{
112public:
113#ifdef Q_OS_WIN32
114 static constexpr bool Enabled = true;
115#else
116 static constexpr bool Enabled = false;
117#endif
118 static bool runtimeSupportCheck() { return Enabled; }
119 static bool supports(QNativeIpcKey::Type type)
120 { return type == QNativeIpcKey::Type::Windows; }
121
122 Qt::HANDLE handle(QSharedMemoryPrivate *self);
123 bool cleanHandle(QSharedMemoryPrivate *self);
124 bool create(QSharedMemoryPrivate *self, qsizetype size);
125 bool attach(QSharedMemoryPrivate *self, QSharedMemory::AccessMode mode);
126 bool detach(QSharedMemoryPrivate *self);
127
128 Qt::HANDLE hand = nullptr;
129};
130
131class Q_AUTOTEST_EXPORT QSharedMemoryPrivate : public QObjectPrivate
132{
133 Q_DECLARE_PUBLIC(QSharedMemory)
134
135public:
136 QSharedMemoryPrivate(QNativeIpcKey::Type type) : nativeKey(type)
137 { constructBackend(); }
138 ~QSharedMemoryPrivate();
139
140 void *memory = nullptr;
141 qsizetype size = 0;
142 QNativeIpcKey nativeKey;
143 QString errorString;
144#if QT_CONFIG(systemsemaphore)
145 using SemaphoreAccessMode = QSystemSemaphore::AccessMode;
146 QSystemSemaphore systemSemaphore{ QNativeIpcKey() };
147 bool lockedByMe = false;
148#else
149 enum SemaphoreAccessMode {};
150#endif
151 QSharedMemory::SharedMemoryError error = QSharedMemory::NoError;
152
153 union Backend {
154 Backend() {}
155 ~Backend() {}
156 QSharedMemoryPosix posix;
157 QSharedMemorySystemV sysv;
158 QSharedMemoryWin32 win32;
159 };
160 QtIpcCommon::IpcStorageVariant<&Backend::posix, &Backend::sysv, &Backend::win32> backend;
161
162 void constructBackend();
163 void destructBackend();
164 bool initKey(SemaphoreAccessMode mode);
165
166 template <typename Lambda> auto visit(const Lambda &lambda)
167 {
168 return backend.visit(nativeKey.type(), lambda);
169 }
170
171 bool handle()
172 {
173 return visit(lambda: [&](auto p) { return !!p->handle(this); });
174 }
175 bool cleanHandle()
176 {
177 return visit(lambda: [&](auto p) { return p->cleanHandle(this); });
178 }
179 bool create(qsizetype size)
180 {
181 return visit(lambda: [&](auto p) { return p->create(this, size); });
182 }
183 bool attach(QSharedMemory::AccessMode mode)
184 {
185 return visit(lambda: [&](auto p) { return p->attach(this, mode); });
186 }
187 bool detach()
188 {
189 return visit(lambda: [&](auto p) { return p->detach(this); });
190 }
191
192 inline void setError(QSharedMemory::SharedMemoryError e, const QString &message)
193 { error = e; errorString = message; }
194 void setUnixErrorString(QLatin1StringView function);
195 void setWindowsErrorString(QLatin1StringView function);
196
197#if QT_CONFIG(systemsemaphore)
198 bool tryLocker(QSharedMemoryLocker *locker, const QString &function) {
199 if (!locker->lock()) {
200 errorString = QSharedMemory::tr(s: "%1: unable to lock").arg(a: function);
201 error = QSharedMemory::LockError;
202 return false;
203 }
204 return true;
205 }
206 QNativeIpcKey semaphoreNativeKey() const;
207#endif // QT_CONFIG(systemsemaphore)
208};
209
210QT_END_NAMESPACE
211
212#endif // QT_CONFIG(sharedmemory)
213
214#endif // QSHAREDMEMORY_P_H
215
216

source code of qtbase/src/corelib/ipc/qsharedmemory_p.h