Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qsharedmemory_posix.cpp
Go to the documentation of this file.
1// Copyright (C) 2015 Konstantin Ritt <ritt.ks@gmail.com>
2// Copyright (C) 2016 The Qt Company Ltd.
3// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig <tobias.koenig@kdab.com>
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5
6#include "qsharedmemory.h"
7#include "qsharedmemory_p.h"
8#include "qtipccommon_p.h"
9#include <qfile.h>
10
11#include <errno.h>
12
13#if QT_CONFIG(posix_shm)
14#include <sys/types.h>
15#include <sys/mman.h>
16#include <sys/stat.h>
17#include <fcntl.h>
18#include <unistd.h>
19
20#include "private/qcore_unix_p.h"
21
22#ifndef O_CLOEXEC
23# define O_CLOEXEC 0
24#endif
25
27
28using namespace Qt::StringLiterals;
29using namespace QtIpcCommon;
30
31bool QSharedMemoryPosix::runtimeSupportCheck()
32{
33 static const bool result = []() {
34 (void)shm_open("", 0, 0); // this WILL fail
35 return errno != ENOSYS;
36 }();
37 return result;
38}
39
40bool QSharedMemoryPosix::handle(QSharedMemoryPrivate *self)
41{
42 // don't allow making handles on empty keys
43 if (self->nativeKey.isEmpty()) {
44 self->setError(QSharedMemory::KeyError,
45 QSharedMemory::tr("%1: key is empty").arg("QSharedMemory::handle"_L1));
46 return false;
47 }
48
49 return true;
50}
51
52bool QSharedMemoryPosix::cleanHandle(QSharedMemoryPrivate *)
53{
54 if (hand != -1)
55 qt_safe_close(hand);
56 hand = -1;
57
58 return true;
59}
60
61bool QSharedMemoryPosix::create(QSharedMemoryPrivate *self, qsizetype size)
62{
63 if (!handle(self))
64 return false;
65
66 const QByteArray shmName = QFile::encodeName(self->nativeKey.nativeKey());
67
68 int fd;
69 EINTR_LOOP(fd, ::shm_open(shmName.constData(), O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0600));
70 if (fd == -1) {
71 const int errorNumber = errno;
72 const auto function = "QSharedMemory::attach (shm_open)"_L1;
73 switch (errorNumber) {
74 case EINVAL:
75 self->setError(QSharedMemory::KeyError,
76 QSharedMemory::tr("%1: bad name").arg(function));
77 break;
78 default:
79 self->setUnixErrorString(function);
80 }
81 return false;
82 }
83
84 // the size may only be set once
85 int ret;
86 EINTR_LOOP(ret, QT_FTRUNCATE(fd, size));
87 if (ret == -1) {
88 self->setUnixErrorString("QSharedMemory::create (ftruncate)"_L1);
90 return false;
91 }
92
94
95 return true;
96}
97
98bool QSharedMemoryPosix::attach(QSharedMemoryPrivate *self, QSharedMemory::AccessMode mode)
99{
100 const QByteArray shmName = QFile::encodeName(self->nativeKey.nativeKey());
101
102 const int oflag = (mode == QSharedMemory::ReadOnly ? O_RDONLY : O_RDWR);
103 const mode_t omode = (mode == QSharedMemory::ReadOnly ? 0400 : 0600);
104
105 EINTR_LOOP(hand, ::shm_open(shmName.constData(), oflag | O_CLOEXEC, omode));
106 if (hand == -1) {
107 const int errorNumber = errno;
108 const auto function = "QSharedMemory::attach (shm_open)"_L1;
109 switch (errorNumber) {
110 case EINVAL:
111 self->setError(QSharedMemory::KeyError,
112 QSharedMemory::tr("%1: bad name").arg(function));
113 break;
114 default:
115 self->setUnixErrorString(function);
116 }
117 hand = -1;
118 return false;
119 }
120
121 // grab the size
122 QT_STATBUF st;
123 if (QT_FSTAT(hand, &st) == -1) {
124 self->setUnixErrorString("QSharedMemory::attach (fstat)"_L1);
125 cleanHandle(self);
126 return false;
127 }
128 self->size = qsizetype(st.st_size);
129
130 // grab the memory
131 const int mprot = (mode == QSharedMemory::ReadOnly ? PROT_READ : PROT_READ | PROT_WRITE);
132 self->memory = QT_MMAP(0, size_t(self->size), mprot, MAP_SHARED, hand, 0);
133 if (self->memory == MAP_FAILED || !self->memory) {
134 self->setUnixErrorString("QSharedMemory::attach (mmap)"_L1);
135 cleanHandle(self);
136 self->memory = 0;
137 self->size = 0;
138 return false;
139 }
140
141#ifdef F_ADD_SEALS
142 // Make sure the shared memory region will not shrink
143 // otherwise someone could cause SIGBUS on us.
144 // (see http://lwn.net/Articles/594919/)
145 fcntl(hand, F_ADD_SEALS, F_SEAL_SHRINK);
146#endif
147
148 return true;
149}
150
151bool QSharedMemoryPosix::detach(QSharedMemoryPrivate *self)
152{
153 // detach from the memory segment
154 if (::munmap(self->memory, size_t(self->size)) == -1) {
155 self->setUnixErrorString("QSharedMemory::detach (munmap)"_L1);
156 return false;
157 }
158 self->memory = 0;
159 self->size = 0;
160
161#ifdef Q_OS_QNX
162 // On QNX the st_nlink field of struct stat contains the number of
163 // active shm_open() connections to the shared memory file, so we
164 // can use it to automatically clean up the file once the last
165 // user has detached from it.
166
167 // get the number of current attachments
168 int shm_nattch = 0;
169 QT_STATBUF st;
170 if (QT_FSTAT(hand, &st) == 0) {
171 // subtract 2 from linkcount: one for our own open and one for the dir entry
172 shm_nattch = st.st_nlink - 2;
173 }
174
175 cleanHandle(self);
176
177 // if there are no attachments then unlink the shared memory
178 if (shm_nattch == 0) {
179 const QByteArray shmName = QFile::encodeName(self->nativeKey.nativeKey());
180 if (::shm_unlink(shmName.constData()) == -1 && errno != ENOENT)
181 self->setUnixErrorString("QSharedMemory::detach (shm_unlink)"_L1);
182 }
183#else
184 // On non-QNX systems (tested Linux and Haiku), the st_nlink field is always 1,
185 // so we'll simply leak the shared memory files.
186 cleanHandle(self);
187#endif
188
189 return true;
190}
191
193
194#endif // QT_CONFIG(posix_shm)
\inmodule QtCore
Definition qbytearray.h:57
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
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
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
Combined button and popup list for selecting options.
QString self
Definition language.cpp:57
#define EINTR_LOOP(var, cmd)
static int qt_safe_close(int fd)
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
return ret
GLuint64 GLenum void * handle
GLenum mode
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint64 GLenum GLint fd
GLuint64EXT * result
[6]
#define MAP_FAILED
SSL_CTX int(*) void arg)
ptrdiff_t qsizetype
Definition qtypes.h:70