Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
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(sharedmemory)
15#if QT_CONFIG(sysv_shm)
16#include <sys/types.h>
17#include <sys/ipc.h>
18#include <sys/mman.h>
19#include <sys/shm.h>
20#include <sys/stat.h>
21#include <fcntl.h>
22#include <unistd.h>
23
24#include "private/qcore_unix_p.h"
25#if defined(Q_OS_DARWIN)
26#include "private/qcore_mac_p.h"
27#endif
28
30
31using namespace Qt::StringLiterals;
32using namespace QtIpcCommon;
33
34bool QSharedMemorySystemV::runtimeSupportCheck()
35{
36#if defined(Q_OS_DARWIN)
38 return false;
39#endif
40 static const bool result = []() {
41 (void)shmget(IPC_PRIVATE, ~size_t(0), 0); // this will fail
42 return errno != ENOSYS;
43 }();
44 return result;
45}
46
47
48inline void QSharedMemorySystemV::updateNativeKeyFile(const QNativeIpcKey &nativeKey)
49{
50 Q_ASSERT(nativeKeyFile.isEmpty() );
51 if (!nativeKey.nativeKey().isEmpty())
52 nativeKeyFile = QFile::encodeName(nativeKey.nativeKey());
53}
54
60key_t QSharedMemorySystemV::handle(QSharedMemoryPrivate *self)
61{
62 // already made
63 if (unix_key)
64 return unix_key;
65
66 // don't allow making handles on empty keys
67 if (nativeKeyFile.isEmpty())
68 updateNativeKeyFile(self->nativeKey);
69 if (nativeKeyFile.isEmpty()) {
70 self->setError(QSharedMemory::KeyError,
71 QSharedMemory::tr("%1: key is empty")
72 .arg("QSharedMemory::handle:"_L1));
73 return 0;
74 }
75
76 unix_key = ftok(nativeKeyFile, int(self->nativeKey.type()));
77 if (unix_key < 0) {
78 self->setUnixErrorString("QSharedMemory::handle"_L1);
79 nativeKeyFile.clear();
80 unix_key = 0;
81 }
82 return unix_key;
83}
84
85bool QSharedMemorySystemV::cleanHandle(QSharedMemoryPrivate *self)
86{
87 if (unix_key == 0)
88 return true;
89
90 // Get the number of current attachments
91 struct shmid_ds shmid_ds;
92 QByteArray keyfile = std::exchange(nativeKeyFile, QByteArray());
93
94 int id = shmget(unix_key, 0, 0400);
95 unix_key = 0;
96 if (shmctl(id, IPC_STAT, &shmid_ds))
97 return errno != EINVAL;
98
99 // If there are still attachments, keep the keep file and shm
100 if (shmid_ds.shm_nattch != 0)
101 return true;
102
103 if (shmctl(id, IPC_RMID, &shmid_ds) < 0) {
104 if (errno != EINVAL) {
105 self->setUnixErrorString("QSharedMemory::remove"_L1);
106 return false;
107 }
108 };
109
110 // remove file
111 return unlink(keyfile) == 0;
112}
113
114bool QSharedMemorySystemV::create(QSharedMemoryPrivate *self, qsizetype size)
115{
116 // build file if needed
117 bool createdFile = false;
118 updateNativeKeyFile(self->nativeKey);
119 int built = createUnixKeyFile(nativeKeyFile);
120 if (built == -1) {
121 self->setError(QSharedMemory::KeyError,
122 QSharedMemory::tr("%1: unable to make key")
123 .arg("QSharedMemory::handle:"_L1));
124 return false;
125 }
126 if (built == 1) {
127 createdFile = true;
128 }
129
130 // get handle
131 if (!handle(self)) {
132 if (createdFile)
133 unlink(nativeKeyFile);
134 return false;
135 }
136
137 // create
138 if (-1 == shmget(unix_key, size_t(size), 0600 | IPC_CREAT | IPC_EXCL)) {
139 const auto function = "QSharedMemory::create"_L1;
140 switch (errno) {
141 case EINVAL:
142 self->setError(QSharedMemory::InvalidSize,
143 QSharedMemory::tr("%1: system-imposed size restrictions")
144 .arg("QSharedMemory::handle"_L1));
145 break;
146 default:
147 self->setUnixErrorString(function);
148 }
149 if (createdFile && self->error != QSharedMemory::AlreadyExists)
150 unlink(nativeKeyFile);
151 return false;
152 }
153
154 return true;
155}
156
157bool QSharedMemorySystemV::attach(QSharedMemoryPrivate *self, QSharedMemory::AccessMode mode)
158{
159 // grab the shared memory segment id
160 int id = shmget(unix_key, 0, (mode == QSharedMemory::ReadOnly ? 0400 : 0600));
161 if (-1 == id) {
162 self->setUnixErrorString("QSharedMemory::attach (shmget)"_L1);
163 unix_key = 0;
164 nativeKeyFile.clear();
165 return false;
166 }
167
168 // grab the memory
169 self->memory = shmat(id, nullptr, (mode == QSharedMemory::ReadOnly ? SHM_RDONLY : 0));
170 if (self->memory == MAP_FAILED) {
171 self->memory = nullptr;
172 self->setUnixErrorString("QSharedMemory::attach (shmat)"_L1);
173 return false;
174 }
175
176 // grab the size
177 shmid_ds shmid_ds;
178 if (!shmctl(id, IPC_STAT, &shmid_ds)) {
179 self->size = (qsizetype)shmid_ds.shm_segsz;
180 } else {
181 self->setUnixErrorString("QSharedMemory::attach (shmctl)"_L1);
182 return false;
183 }
184
185 return true;
186}
187
188bool QSharedMemorySystemV::detach(QSharedMemoryPrivate *self)
189{
190 // detach from the memory segment
191 if (shmdt(self->memory) < 0) {
192 const auto function = "QSharedMemory::detach"_L1;
193 switch (errno) {
194 case EINVAL:
195 self->setError(QSharedMemory::NotFound,
196 QSharedMemory::tr("%1: not attached").arg(function));
197 break;
198 default:
199 self->setUnixErrorString(function);
200 }
201 return false;
202 }
203 self->memory = nullptr;
204 self->size = 0;
205
206 return cleanHandle(self);
207}
208
210
211#endif // QT_CONFIG(sysv_shm)
212#endif // QT_CONFIG(sharedmemory)
\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
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1252
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
Combined button and popup list for selecting options.
QString self
Definition language.cpp:58
bool qt_apple_isSandboxed()
Definition qcore_mac.mm:499
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
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
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:165