Qt 6.x
The Qt SDK
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
qsharedmemory_systemv.cpp
Go to the documentation of this file.
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#include "qsharedmemory.h"
5#include "qsharedmemory_p.h"
6
7#include "qtipccommon_p.h"
8
9#include <qdir.h>
10#include <qdebug.h>
11
12#include <errno.h>
13
14#if QT_CONFIG(sysv_shm)
15#include <sys/types.h>
16#include <sys/ipc.h>
17#include <sys/mman.h>
18#include <sys/shm.h>
19#include <sys/stat.h>
20#include <fcntl.h>
21#include <unistd.h>
22
23#include "private/qcore_unix_p.h"
24#if defined(Q_OS_DARWIN)
25#include "private/qcore_mac_p.h"
26#endif
27
29
30using namespace Qt::StringLiterals;
31using namespace QtIpcCommon;
32
33bool QSharedMemorySystemV::runtimeSupportCheck()
34{
35#if defined(Q_OS_DARWIN)
37 return false;
38#endif
39 static const bool result = []() {
40 (void)shmget(IPC_PRIVATE, ~size_t(0), 0); // this will fail
41 return errno != ENOSYS;
42 }();
43 return result;
44}
45
46
47inline void QSharedMemorySystemV::updateNativeKeyFile(const QNativeIpcKey &nativeKey)
48{
49 Q_ASSERT(nativeKeyFile.isEmpty() );
50 if (!nativeKey.nativeKey().isEmpty())
51 nativeKeyFile = QFile::encodeName(nativeKey.nativeKey());
52}
53
59key_t QSharedMemorySystemV::handle(QSharedMemoryPrivate *self)
60{
61 // already made
62 if (unix_key)
63 return unix_key;
64
65 // don't allow making handles on empty keys
66 if (nativeKeyFile.isEmpty())
67 updateNativeKeyFile(self->nativeKey);
68 if (nativeKeyFile.isEmpty()) {
69 self->setError(QSharedMemory::KeyError,
70 QSharedMemory::tr("%1: key is empty")
71 .arg("QSharedMemory::handle:"_L1));
72 return 0;
73 }
74
75 unix_key = ftok(nativeKeyFile, int(self->nativeKey.type()));
76 if (unix_key < 0) {
77 self->setUnixErrorString("QSharedMemory::handle"_L1);
78 unix_key = 0;
79 }
80 return unix_key;
81}
82
83bool QSharedMemorySystemV::cleanHandle(QSharedMemoryPrivate *self)
84{
85 if (unix_key == 0)
86 return true;
87
88 // Get the number of current attachments
89 struct shmid_ds shmid_ds;
90 QByteArray keyfile = std::exchange(nativeKeyFile, QByteArray());
91
92 int id = shmget(unix_key, 0, 0400);
93 unix_key = 0;
94 if (shmctl(id, IPC_STAT, &shmid_ds))
95 return errno != EINVAL;
96
97 // If there are still attachments, keep the keep file and shm
98 if (shmid_ds.shm_nattch != 0)
99 return true;
100
101 if (shmctl(id, IPC_RMID, &shmid_ds) < 0) {
102 if (errno != EINVAL) {
103 self->setUnixErrorString("QSharedMemory::remove"_L1);
104 return false;
105 }
106 };
107
108 // remove file
109 return unlink(keyfile) == 0;
110}
111
112bool QSharedMemorySystemV::create(QSharedMemoryPrivate *self, qsizetype size)
113{
114 // build file if needed
115 bool createdFile = false;
116 updateNativeKeyFile(self->nativeKey);
117 int built = createUnixKeyFile(nativeKeyFile);
118 if (built == -1) {
119 self->setError(QSharedMemory::KeyError,
120 QSharedMemory::tr("%1: unable to make key")
121 .arg("QSharedMemory::handle:"_L1));
122 return false;
123 }
124 if (built == 1) {
125 createdFile = true;
126 }
127
128 // get handle
129 if (!handle(self)) {
130 if (createdFile)
131 unlink(nativeKeyFile);
132 return false;
133 }
134
135 // create
136 if (-1 == shmget(unix_key, size_t(size), 0600 | IPC_CREAT | IPC_EXCL)) {
137 const auto function = "QSharedMemory::create"_L1;
138 switch (errno) {
139 case EINVAL:
140 self->setError(QSharedMemory::InvalidSize,
141 QSharedMemory::tr("%1: system-imposed size restrictions")
142 .arg("QSharedMemory::handle"_L1));
143 break;
144 default:
145 self->setUnixErrorString(function);
146 }
147 if (createdFile && self->error != QSharedMemory::AlreadyExists)
148 unlink(nativeKeyFile);
149 return false;
150 }
151
152 return true;
153}
154
155bool QSharedMemorySystemV::attach(QSharedMemoryPrivate *self, QSharedMemory::AccessMode mode)
156{
157 // grab the shared memory segment id
158 int id = shmget(unix_key, 0, (mode == QSharedMemory::ReadOnly ? 0400 : 0600));
159 if (-1 == id) {
160 self->setUnixErrorString("QSharedMemory::attach (shmget)"_L1);
161 return false;
162 }
163
164 // grab the memory
165 self->memory = shmat(id, nullptr, (mode == QSharedMemory::ReadOnly ? SHM_RDONLY : 0));
166 if (self->memory == MAP_FAILED) {
167 self->memory = nullptr;
168 self->setUnixErrorString("QSharedMemory::attach (shmat)"_L1);
169 return false;
170 }
171
172 // grab the size
173 shmid_ds shmid_ds;
174 if (!shmctl(id, IPC_STAT, &shmid_ds)) {
175 self->size = (qsizetype)shmid_ds.shm_segsz;
176 } else {
177 self->setUnixErrorString("QSharedMemory::attach (shmctl)"_L1);
178 return false;
179 }
180
181 return true;
182}
183
184bool QSharedMemorySystemV::detach(QSharedMemoryPrivate *self)
185{
186 // detach from the memory segment
187 if (shmdt(self->memory) < 0) {
188 const auto function = "QSharedMemory::detach"_L1;
189 switch (errno) {
190 case EINVAL:
191 self->setError(QSharedMemory::NotFound,
192 QSharedMemory::tr("%1: not attached").arg(function));
193 break;
194 default:
195 self->setUnixErrorString(function);
196 }
197 return false;
198 }
199 self->memory = nullptr;
200 self->size = 0;
201
202 return cleanHandle(self);
203}
204
206
207#endif // QT_CONFIG(sysv_shm)
\inmodule QtCore
Definition qbytearray.h:57
static QByteArray encodeName(const QString &fileName)
Converts fileName to an 8-bit encoding that you can use in native APIs.
Definition qfile.h:158
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
Combined button and popup list for selecting options.
QString self
Definition language.cpp:57
bool qt_apple_isSandboxed()
Definition qcore_mac.mm:498
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
GLuint64 GLenum void * handle
GLenum mode
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define MAP_FAILED
SSL_CTX int(*) void arg)
ptrdiff_t qsizetype
Definition qtypes.h:70