Qt 6.x
The Qt SDK
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
128#if QT_DEPRECATED_SINCE(6, 10)
140QSharedMemory::QSharedMemory(const QString &key, QObject *parent)
141 : QSharedMemory(legacyNativeKey(key), parent)
142{
143 d_func()->legacyKey = key;
144}
145#endif
146
156QSharedMemory::~QSharedMemory()
157{
158 Q_D(QSharedMemory);
159 if (isAttached())
160 detach();
161 d->cleanHandle();
162}
163
164#if QT_DEPRECATED_SINCE(6, 10)
186void QSharedMemory::setKey(const QString &key)
187{
188 Q_D(QSharedMemory);
189 setNativeKey(legacyNativeKey(key));
190 d->legacyKey = key;
191}
192#endif
193
234void QSharedMemory::setNativeKey(const QNativeIpcKey &key)
235{
236 Q_D(QSharedMemory);
237 if (key == d->nativeKey && key.isEmpty())
238 return;
239 if (!isKeyTypeSupported(key.type())) {
240 d->setError(KeyError, tr("%1: unsupported key type")
241 .arg("QSharedMemory::setNativeKey"_L1));
242 return;
243 }
244
245 if (isAttached())
246 detach();
247 d->cleanHandle();
248 d->legacyKey = QString();
249 if (key.type() == d->nativeKey.type()) {
250 // we can reuse the backend
251 d->nativeKey = key;
252 } else {
253 // we must recreate the backend
254 d->destructBackend();
255 d->nativeKey = key;
256 d->constructBackend();
257 }
258}
259
260bool QSharedMemoryPrivate::initKey(SemaphoreAccessMode mode)
261{
262 if (!cleanHandle())
263 return false;
264#if QT_CONFIG(systemsemaphore)
265 systemSemaphore.setNativeKey(semaphoreNativeKey(), 1, mode);
266 if (systemSemaphore.error() != QSystemSemaphore::NoError) {
267 QString function = "QSharedMemoryPrivate::initKey"_L1;
268 errorString = QSharedMemory::tr("%1: unable to set key on lock (%2)")
269 .arg(function, systemSemaphore.errorString());
270 switch(systemSemaphore.error()) {
271 case QSystemSemaphore::PermissionDenied:
272 error = QSharedMemory::PermissionDenied;
273 break;
274 case QSystemSemaphore::KeyError:
275 error = QSharedMemory::KeyError;
276 break;
277 case QSystemSemaphore::AlreadyExists:
278 error = QSharedMemory::AlreadyExists;
279 break;
280 case QSystemSemaphore::NotFound:
281 error = QSharedMemory::NotFound;
282 break;
283 case QSystemSemaphore::OutOfResources:
284 error = QSharedMemory::OutOfResources;
285 break;
286 case QSystemSemaphore::UnknownError:
287 default:
288 error = QSharedMemory::UnknownError;
289 break;
290 }
291 return false;
292 }
293#else
294 Q_UNUSED(mode);
295#endif
297 error = QSharedMemory::NoError;
298 return true;
299}
300
301#if QT_DEPRECATED_SINCE(6, 10)
314QString QSharedMemory::key() const
315{
316 Q_D(const QSharedMemory);
317 return d->legacyKey;
318}
319#endif
320
334QString QSharedMemory::nativeKey() const
335{
336 Q_D(const QSharedMemory);
337 return d->nativeKey.nativeKey();
338}
339
353QNativeIpcKey QSharedMemory::nativeIpcKey() const
354{
355 Q_D(const QSharedMemory);
356 return d->nativeKey;
357}
358
369bool QSharedMemory::create(qsizetype size, AccessMode mode)
370{
371 Q_D(QSharedMemory);
372 QLatin1StringView function = "QSharedMemory::create"_L1;
373
374#if QT_CONFIG(systemsemaphore)
375 if (!d->initKey(QSystemSemaphore::Create))
376 return false;
377 QSharedMemoryLocker lock(this);
378 if (!d->nativeKey.isEmpty() && !d->tryLocker(&lock, function))
379 return false;
380#else
381 if (!d->initKey({}))
382 return false;
383#endif
384
385 if (size <= 0) {
386 d->error = QSharedMemory::InvalidSize;
387 d->errorString =
388 QSharedMemory::tr("%1: create size is less then 0").arg(function);
389 return false;
390 }
391
392 if (!d->create(size))
393 return false;
394
395 return d->attach(mode);
396}
397
407qsizetype QSharedMemory::size() const
408{
409 Q_D(const QSharedMemory);
410 return d->size;
411}
412
437bool QSharedMemory::attach(AccessMode mode)
438{
439 Q_D(QSharedMemory);
440
441 if (isAttached() || !d->initKey({}))
442 return false;
443#if QT_CONFIG(systemsemaphore)
444 QSharedMemoryLocker lock(this);
445 if (!d->nativeKey.isEmpty() && !d->tryLocker(&lock, "QSharedMemory::attach"_L1))
446 return false;
447#endif
448
449 if (isAttached() || !d->handle())
450 return false;
451
452 return d->attach(mode);
453}
454
461bool QSharedMemory::isAttached() const
462{
463 Q_D(const QSharedMemory);
464 return (nullptr != d->memory);
465}
466
477bool QSharedMemory::detach()
478{
479 Q_D(QSharedMemory);
480 if (!isAttached())
481 return false;
482
483#if QT_CONFIG(systemsemaphore)
484 QSharedMemoryLocker lock(this);
485 if (!d->nativeKey.isEmpty() && !d->tryLocker(&lock, "QSharedMemory::detach"_L1))
486 return false;
487#endif
488
489 return d->detach();
490}
491
504void *QSharedMemory::data()
505{
506 Q_D(QSharedMemory);
507 return d->memory;
508}
509
522const void *QSharedMemory::constData() const
523{
524 Q_D(const QSharedMemory);
525 return d->memory;
526}
527
531const void *QSharedMemory::data() const
532{
533 Q_D(const QSharedMemory);
534 return d->memory;
535}
536
537#if QT_CONFIG(systemsemaphore)
549bool QSharedMemory::lock()
550{
551 Q_D(QSharedMemory);
552 if (d->lockedByMe) {
553 qWarning("QSharedMemory::lock: already locked");
554 return true;
555 }
556 if (d->systemSemaphore.acquire()) {
557 d->lockedByMe = true;
558 return true;
559 }
560 const auto function = "QSharedMemory::lock"_L1;
561 d->errorString = QSharedMemory::tr("%1: unable to lock").arg(function);
562 d->error = QSharedMemory::LockError;
563 return false;
564}
565
574bool QSharedMemory::unlock()
575{
576 Q_D(QSharedMemory);
577 if (!d->lockedByMe)
578 return false;
579 d->lockedByMe = false;
580 if (d->systemSemaphore.release())
581 return true;
582 const auto function = "QSharedMemory::unlock"_L1;
583 d->errorString = QSharedMemory::tr("%1: unable to unlock").arg(function);
584 d->error = QSharedMemory::LockError;
585 return false;
586}
587#endif // QT_CONFIG(systemsemaphore)
588
624QSharedMemory::SharedMemoryError QSharedMemory::error() const
625{
626 Q_D(const QSharedMemory);
627 return d->error;
628}
629
638QString QSharedMemory::errorString() const
639{
640 Q_D(const QSharedMemory);
641 return d->errorString;
642}
643
644void QSharedMemoryPrivate::setUnixErrorString(QLatin1StringView function)
645{
646 // EINVAL is handled in functions so they can give better error strings
647 switch (errno) {
648 case EACCES:
649 errorString = QSharedMemory::tr("%1: permission denied").arg(function);
650 error = QSharedMemory::PermissionDenied;
651 break;
652 case EEXIST:
653 errorString = QSharedMemory::tr("%1: already exists").arg(function);
654 error = QSharedMemory::AlreadyExists;
655 break;
656 case ENOENT:
657 errorString = QSharedMemory::tr("%1: doesn't exist").arg(function);
658 error = QSharedMemory::NotFound;
659 break;
660 case EMFILE:
661 case ENOMEM:
662 case ENOSPC:
663 errorString = QSharedMemory::tr("%1: out of resources").arg(function);
664 error = QSharedMemory::OutOfResources;
665 break;
666 default:
667 errorString = QSharedMemory::tr("%1: unknown error: %2")
668 .arg(function, qt_error_string(errno));
669 error = QSharedMemory::UnknownError;
670#if defined QSHAREDMEMORY_DEBUG
671 qDebug() << errorString << "key" << key << "errno" << errno << EINVAL;
672#endif
673 }
674}
675
676bool QSharedMemory::isKeyTypeSupported(QNativeIpcKey::Type type)
677{
678 if (!isIpcSupported(IpcType::SharedMemory, type))
679 return false;
680 using Variant = decltype(QSharedMemoryPrivate::backend);
681 return Variant::staticVisit(type, [](auto ptr) {
682 using Impl = std::decay_t<decltype(*ptr)>;
683 return Impl::runtimeSupportCheck();
684 });
685}
686
687QNativeIpcKey QSharedMemory::platformSafeKey(const QString &key, QNativeIpcKey::Type type)
688{
689 return { QtIpcCommon::platformSafeKey(key, IpcType::SharedMemory, type), type };
690}
691
692QNativeIpcKey QSharedMemory::legacyNativeKey(const QString &key, QNativeIpcKey::Type type)
693{
694 return { legacyPlatformSafeKey(key, IpcType::SharedMemory, type), type };
695}
696
697#endif // QT_CONFIG(sharedmemory)
698
700
701#include "moc_qsharedmemory.cpp"
\inmodule QtCore
Definition qobject.h:90
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
void truncate(qsizetype pos)
Truncates the string at the given position index.
Definition qstring.cpp:6159
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
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 DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
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:160
#define qWarning
Definition qlogging.h:162
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:70
QReadWriteLock lock
[0]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent