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_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(sharedmemory)
14#if QT_CONFIG(posix_shm)
15#include <sys/types.h>
16#include <sys/mman.h>
17#include <sys/stat.h>
18#include <fcntl.h>
19#include <unistd.h>
20
21#include "private/qcore_unix_p.h"
22
23#ifndef O_CLOEXEC
24# define O_CLOEXEC 0
25#endif
26
28
29using namespace Qt::StringLiterals;
30using namespace QtIpcCommon;
31
32bool QSharedMemoryPosix::runtimeSupportCheck()
33{
34 static const bool result = []() {
35 (void)shm_open("", 0, 0); // this WILL fail
36 return errno != ENOSYS;
37 }();
38 return result;
39}
40
41bool QSharedMemoryPosix::handle(QSharedMemoryPrivate *self)
42{
43 // don't allow making handles on empty keys
44 if (self->nativeKey.isEmpty()) {
45 self->setError(QSharedMemory::KeyError,
46 QSharedMemory::tr("%1: key is empty").arg("QSharedMemory::handle"_L1));
47 return false;
48 }
49
50 return true;
51}
52
53bool QSharedMemoryPosix::cleanHandle(QSharedMemoryPrivate *)
54{
55 if (hand != -1)
56 qt_safe_close(hand);
57 hand = -1;
58
59 return true;
60}
61
62bool QSharedMemoryPosix::create(QSharedMemoryPrivate *self, qsizetype size)
63{
64 if (!handle(self))
65 return false;
66
67 const QByteArray shmName = QFile::encodeName(self->nativeKey.nativeKey());
68
69 int fd;
70 QT_EINTR_LOOP(fd, ::shm_open(shmName.constData(), O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0600));
71 if (fd == -1) {
72 const int errorNumber = errno;
73 const auto function = "QSharedMemory::attach (shm_open)"_L1;
74 switch (errorNumber) {
75 case EINVAL:
76 self->setError(QSharedMemory::KeyError,
77 QSharedMemory::tr("%1: bad name").arg(function));
78 break;
79 default:
80 self->setUnixErrorString(function);
81 }
82 return false;
83 }
84
85 // the size may only be set once
86 int ret;
87 QT_EINTR_LOOP(ret, QT_FTRUNCATE(fd, size));
88 if (ret == -1) {
89 self->setUnixErrorString("QSharedMemory::create (ftruncate)"_L1);
91 return false;
92 }
93
95
96 return true;
97}
98
99bool QSharedMemoryPosix::attach(QSharedMemoryPrivate *self, QSharedMemory::AccessMode mode)
100{
101 const QByteArray shmName = QFile::encodeName(self->nativeKey.nativeKey());
102
103 const int oflag = (mode == QSharedMemory::ReadOnly ? O_RDONLY : O_RDWR);
104 const mode_t omode = (mode == QSharedMemory::ReadOnly ? 0400 : 0600);
105
106 QT_EINTR_LOOP(hand, ::shm_open(shmName.constData(), oflag | O_CLOEXEC, omode));
107 if (hand == -1) {
108 const int errorNumber = errno;
109 const auto function = "QSharedMemory::attach (shm_open)"_L1;
110 switch (errorNumber) {
111 case EINVAL:
112 self->setError(QSharedMemory::KeyError,
113 QSharedMemory::tr("%1: bad name").arg(function));
114 break;
115 default:
116 self->setUnixErrorString(function);
117 }
118 hand = -1;
119 return false;
120 }
121
122 // grab the size
123 QT_STATBUF st;
124 if (QT_FSTAT(hand, &st) == -1) {
125 self->setUnixErrorString("QSharedMemory::attach (fstat)"_L1);
126 cleanHandle(self);
127 return false;
128 }
129 self->size = qsizetype(st.st_size);
130
131 // grab the memory
132 const int mprot = (mode == QSharedMemory::ReadOnly ? PROT_READ : PROT_READ | PROT_WRITE);
133 self->memory = QT_MMAP(0, size_t(self->size), mprot, MAP_SHARED, hand, 0);
134 if (self->memory == MAP_FAILED || !self->memory) {
135 self->setUnixErrorString("QSharedMemory::attach (mmap)"_L1);
136 cleanHandle(self);
137 self->memory = 0;
138 self->size = 0;
139 return false;
140 }
141
142#ifdef F_ADD_SEALS
143 // Make sure the shared memory region will not shrink
144 // otherwise someone could cause SIGBUS on us.
145 // (see http://lwn.net/Articles/594919/)
146 fcntl(hand, F_ADD_SEALS, F_SEAL_SHRINK);
147#endif
148
149 return true;
150}
151
152bool QSharedMemoryPosix::detach(QSharedMemoryPrivate *self)
153{
154 // detach from the memory segment
155 if (::munmap(self->memory, size_t(self->size)) == -1) {
156 self->setUnixErrorString("QSharedMemory::detach (munmap)"_L1);
157 return false;
158 }
159 self->memory = 0;
160 self->size = 0;
161
162#ifdef Q_OS_QNX
163 // On QNX the st_nlink field of struct stat contains the number of
164 // active shm_open() connections to the shared memory file, so we
165 // can use it to automatically clean up the file once the last
166 // user has detached from it.
167
168 // get the number of current attachments
169 int shm_nattch = 0;
170 QT_STATBUF st;
171 if (QT_FSTAT(hand, &st) == 0) {
172 // subtract 2 from linkcount: one for our own open and one for the dir entry
173 shm_nattch = st.st_nlink - 2;
174 }
175
176 cleanHandle(self);
177
178 // if there are no attachments then unlink the shared memory
179 if (shm_nattch == 0) {
180 const QByteArray shmName = QFile::encodeName(self->nativeKey.nativeKey());
181 if (::shm_unlink(shmName.constData()) == -1 && errno != ENOENT)
182 self->setUnixErrorString("QSharedMemory::detach (shm_unlink)"_L1);
183 }
184#else
185 // On non-QNX systems (tested Linux and Haiku), the st_nlink field is always 1,
186 // so we'll simply leak the shared memory files.
187 cleanHandle(self);
188#endif
189
190 return true;
191}
192
194
195#endif // QT_CONFIG(posix_shm)
196#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
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
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
#define QT_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
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:165