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.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#include "qsystemsemaphore.h"
9
10#include <q20memory.h>
11#include <qdebug.h>
12#ifdef Q_OS_WIN
13# include <qt_windows.h>
14#endif
15
16#ifndef MAX_PATH
17# define MAX_PATH PATH_MAX
18#endif
19
21
22#if QT_CONFIG(sharedmemory)
23
24using namespace QtIpcCommon;
25using namespace Qt::StringLiterals;
26
27QSharedMemoryPrivate::~QSharedMemoryPrivate()
28{
29 destructBackend();
30}
31
32inline void QSharedMemoryPrivate::constructBackend()
33{
34 using namespace q20;
35 visit([](auto p) { construct_at(p); });
36}
37
38inline void QSharedMemoryPrivate::destructBackend()
39{
40 visit([](auto p) { std::destroy_at(p); });
41}
42
43#if QT_CONFIG(systemsemaphore)
44inline QNativeIpcKey QSharedMemoryPrivate::semaphoreNativeKey() const
45{
46 if (isIpcSupported(IpcType::SharedMemory, QNativeIpcKey::Type::Windows)
47 && nativeKey.type() == QNativeIpcKey::Type::Windows) {
48 // native keys are plain kernel object names, limited to MAX_PATH
49 auto suffix = "_sem"_L1;
50 QString semkey = nativeKey.nativeKey();
51 semkey.truncate(MAX_PATH - suffix.size() - 1);
52 semkey += suffix;
53 return { semkey, QNativeIpcKey::Type::Windows };
54 }
55
56 // System V and POSIX keys appear to operate in different namespaces, so we
57 // can just use the same native key
58 return nativeKey;
59}
60#endif
61
108QSharedMemory::QSharedMemory(QObject *parent)
109 : QSharedMemory(QNativeIpcKey(), parent)
110{
111}
112
122QSharedMemory::QSharedMemory(const QNativeIpcKey &key, QObject *parent)
123 : QObject(*new QSharedMemoryPrivate(key.type()), parent)
124{
125 setNativeKey(key);
126}
127
135QSharedMemory::QSharedMemory(const QString &key, QObject *parent)
136 : QSharedMemory(legacyNativeKey(key), parent)
137{
138}
139
149QSharedMemory::~QSharedMemory()
150{
151 Q_D(QSharedMemory);
152 if (isAttached())
153 detach();
154 d->cleanHandle();
155}
156
177void QSharedMemory::setKey(const QString &key)
178{
179 setNativeKey(legacyNativeKey(key));
180}
181
222void QSharedMemory::setNativeKey(const QNativeIpcKey &key)
223{
224 Q_D(QSharedMemory);
225 if (key == d->nativeKey && key.isEmpty())
226 return;
227 if (!isKeyTypeSupported(key.type())) {
228 d->setError(KeyError, tr("%1: unsupported key type")
229 .arg("QSharedMemory::setNativeKey"_L1));
230 return;
231 }
232
233 if (isAttached())
234 detach();
235 d->cleanHandle();
236 if (key.type() == d->nativeKey.type()) {
237 // we can reuse the backend
238 d->nativeKey = key;
239 } else {
240 // we must recreate the backend
241 d->destructBackend();
242 d->nativeKey = key;
243 d->constructBackend();
244 }
245}
246
247bool QSharedMemoryPrivate::initKey(SemaphoreAccessMode mode)
248{
249 if (!cleanHandle())
250 return false;
251#if QT_CONFIG(systemsemaphore)
252 const QString legacyKey = QNativeIpcKeyPrivate::legacyKey(nativeKey);
253 const QNativeIpcKey semKey = legacyKey.isEmpty()
254 ? semaphoreNativeKey()
255 : QSystemSemaphore::legacyNativeKey(legacyKey, nativeKey.type());
256 systemSemaphore.setNativeKey(semKey, 1, mode);
257 if (systemSemaphore.error() != QSystemSemaphore::NoError) {
258 QString function = "QSharedMemoryPrivate::initKey"_L1;
259 errorString = QSharedMemory::tr("%1: unable to set key on lock (%2)")
260 .arg(function, systemSemaphore.errorString());
261 switch(systemSemaphore.error()) {
262 case QSystemSemaphore::PermissionDenied:
263 error = QSharedMemory::PermissionDenied;
264 break;
265 case QSystemSemaphore::KeyError:
266 error = QSharedMemory::KeyError;
267 break;
268 case QSystemSemaphore::AlreadyExists:
269 error = QSharedMemory::AlreadyExists;
270 break;
271 case QSystemSemaphore::NotFound:
272 error = QSharedMemory::NotFound;
273 break;
274 case QSystemSemaphore::OutOfResources:
275 error = QSharedMemory::OutOfResources;
276 break;
277 case QSystemSemaphore::UnknownError:
278 default:
279 error = QSharedMemory::UnknownError;
280 break;
281 }
282 return false;
283 }
284#else
285 Q_UNUSED(mode);
286#endif
288 error = QSharedMemory::NoError;
289 return true;
290}
291
303QString QSharedMemory::key() const
304{
305 Q_D(const QSharedMemory);
306 return QNativeIpcKeyPrivate::legacyKey(d->nativeKey);
307}
308
322QString QSharedMemory::nativeKey() const
323{
324 Q_D(const QSharedMemory);
325 return d->nativeKey.nativeKey();
326}
327
341QNativeIpcKey QSharedMemory::nativeIpcKey() const
342{
343 Q_D(const QSharedMemory);
344 return d->nativeKey;
345}
346
357bool QSharedMemory::create(qsizetype size, AccessMode mode)
358{
359 Q_D(QSharedMemory);
360 QLatin1StringView function = "QSharedMemory::create"_L1;
361
362#if QT_CONFIG(systemsemaphore)
363 if (!d->initKey(QSystemSemaphore::Create))
364 return false;
365 QSharedMemoryLocker lock(this);
366 if (!d->nativeKey.isEmpty() && !d->tryLocker(&lock, function))
367 return false;
368#else
369 if (!d->initKey({}))
370 return false;
371#endif
372
373 if (size <= 0) {
374 d->error = QSharedMemory::InvalidSize;
375 d->errorString =
376 QSharedMemory::tr("%1: create size is less then 0").arg(function);
377 return false;
378 }
379
380 if (!d->create(size))
381 return false;
382
383 return d->attach(mode);
384}
385
395qsizetype QSharedMemory::size() const
396{
397 Q_D(const QSharedMemory);
398 return d->size;
399}
400
425bool QSharedMemory::attach(AccessMode mode)
426{
427 Q_D(QSharedMemory);
428
429 if (isAttached() || !d->initKey({}))
430 return false;
431#if QT_CONFIG(systemsemaphore)
432 QSharedMemoryLocker lock(this);
433 if (!d->nativeKey.isEmpty() && !d->tryLocker(&lock, "QSharedMemory::attach"_L1))
434 return false;
435#endif
436
437 if (isAttached() || !d->handle())
438 return false;
439
440 return d->attach(mode);
441}
442
449bool QSharedMemory::isAttached() const
450{
451 Q_D(const QSharedMemory);
452 return (nullptr != d->memory);
453}
454
465bool QSharedMemory::detach()
466{
467 Q_D(QSharedMemory);
468 if (!isAttached())
469 return false;
470
471#if QT_CONFIG(systemsemaphore)
472 QSharedMemoryLocker lock(this);
473 if (!d->nativeKey.isEmpty() && !d->tryLocker(&lock, "QSharedMemory::detach"_L1))
474 return false;
475#endif
476
477 return d->detach();
478}
479
492void *QSharedMemory::data()
493{
494 Q_D(QSharedMemory);
495 return d->memory;
496}
497
510const void *QSharedMemory::constData() const
511{
512 Q_D(const QSharedMemory);
513 return d->memory;
514}
515
519const void *QSharedMemory::data() const
520{
521 Q_D(const QSharedMemory);
522 return d->memory;
523}
524
525#if QT_CONFIG(systemsemaphore)
537bool QSharedMemory::lock()
538{
539 Q_D(QSharedMemory);
540 if (d->lockedByMe) {
541 qWarning("QSharedMemory::lock: already locked");
542 return true;
543 }
544 if (d->systemSemaphore.acquire()) {
545 d->lockedByMe = true;
546 return true;
547 }
548 const auto function = "QSharedMemory::lock"_L1;
549 d->errorString = QSharedMemory::tr("%1: unable to lock").arg(function);
550 d->error = QSharedMemory::LockError;
551 return false;
552}
553
562bool QSharedMemory::unlock()
563{
564 Q_D(QSharedMemory);
565 if (!d->lockedByMe)
566 return false;
567 d->lockedByMe = false;
568 if (d->systemSemaphore.release())
569 return true;
570 const auto function = "QSharedMemory::unlock"_L1;
571 d->errorString = QSharedMemory::tr("%1: unable to unlock").arg(function);
572 d->error = QSharedMemory::LockError;
573 return false;
574}
575#endif // QT_CONFIG(systemsemaphore)
576
612QSharedMemory::SharedMemoryError QSharedMemory::error() const
613{
614 Q_D(const QSharedMemory);
615 return d->error;
616}
617
626QString QSharedMemory::errorString() const
627{
628 Q_D(const QSharedMemory);
629 return d->errorString;
630}
631
632void QSharedMemoryPrivate::setUnixErrorString(QLatin1StringView function)
633{
634 // EINVAL is handled in functions so they can give better error strings
635 switch (errno) {
636 case EACCES:
637 errorString = QSharedMemory::tr("%1: permission denied").arg(function);
638 error = QSharedMemory::PermissionDenied;
639 break;
640 case EEXIST:
641 errorString = QSharedMemory::tr("%1: already exists").arg(function);
642 error = QSharedMemory::AlreadyExists;
643 break;
644 case ENOENT:
645 errorString = QSharedMemory::tr("%1: doesn't exist").arg(function);
646 error = QSharedMemory::NotFound;
647 break;
648 case EMFILE:
649 case ENOMEM:
650 case ENOSPC:
651 errorString = QSharedMemory::tr("%1: out of resources").arg(function);
652 error = QSharedMemory::OutOfResources;
653 break;
654 default:
655 errorString = QSharedMemory::tr("%1: unknown error: %2")
656 .arg(function, qt_error_string(errno));
657 error = QSharedMemory::UnknownError;
658#if defined QSHAREDMEMORY_DEBUG
659 qDebug() << errorString << "key" << key << "errno" << errno << EINVAL;
660#endif
661 }
662}
663
664bool QSharedMemory::isKeyTypeSupported(QNativeIpcKey::Type type)
665{
666 if (!isIpcSupported(IpcType::SharedMemory, type))
667 return false;
668 using Variant = decltype(QSharedMemoryPrivate::backend);
669 return Variant::staticVisit(type, [](auto ptr) {
670 using Impl = std::decay_t<decltype(*ptr)>;
671 return Impl::runtimeSupportCheck();
672 });
673}
674
675QNativeIpcKey QSharedMemory::platformSafeKey(const QString &key, QNativeIpcKey::Type type)
676{
677 return QtIpcCommon::platformSafeKey(key, IpcType::SharedMemory, type);
678}
679
680QNativeIpcKey QSharedMemory::legacyNativeKey(const QString &key, QNativeIpcKey::Type type)
681{
682 return QtIpcCommon::legacyPlatformSafeKey(key, IpcType::SharedMemory, type);
683}
684
685#endif // QT_CONFIG(sharedmemory)
686
688
689#include "moc_qsharedmemory.cpp"
\inmodule QtCore
Definition qobject.h:103
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
void truncate(qsizetype pos)
Truncates the string at the given position index.
Definition qstring.cpp:6319
auto visit(Fn &&fn, QIODevice *socket, Args &&...args)
Combined button and popup list for selecting options.
Q_MULTIMEDIA_EXPORT QString errorString(HRESULT hr)
T * construct_at(T *ptr, Args &&... args)
Definition q20memory.h:41
DBusConnection const char DBusError * error
Q_DECL_COLD_FUNCTION Q_CORE_EXPORT QString qt_error_string(int errorCode=-1)
#define qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
static ControlElement< T > * ptr(QWidget *widget)
GLenum mode
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum type
GLfloat GLfloat p
[1]
#define MAX_PATH
SSL_CTX int void * arg
#define tr(X)
#define Q_UNUSED(x)
ptrdiff_t qsizetype
Definition qtypes.h:165
QReadWriteLock lock
[0]