| 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 | #include <errno.h> | 
| 16 |  | 
| 17 | #ifndef MAX_PATH | 
| 18 | #  define MAX_PATH PATH_MAX | 
| 19 | #endif | 
| 20 |  | 
| 21 | QT_BEGIN_NAMESPACE | 
| 22 |  | 
| 23 | #if QT_CONFIG(sharedmemory) | 
| 24 |  | 
| 25 | using namespace QtIpcCommon; | 
| 26 | using namespace Qt::StringLiterals; | 
| 27 |  | 
| 28 | QSharedMemoryPrivate::~QSharedMemoryPrivate() | 
| 29 | { | 
| 30 |     destructBackend(); | 
| 31 | } | 
| 32 |  | 
| 33 | inline void QSharedMemoryPrivate::constructBackend() | 
| 34 | { | 
| 35 |     using namespace q20; | 
| 36 |     visit(lambda: [](auto p) { construct_at(p); }); | 
| 37 | } | 
| 38 |  | 
| 39 | inline void QSharedMemoryPrivate::destructBackend() | 
| 40 | { | 
| 41 |     visit(lambda: [](auto p) { std::destroy_at(p); }); | 
| 42 | } | 
| 43 |  | 
| 44 | #if QT_CONFIG(systemsemaphore) | 
| 45 | inline QNativeIpcKey QSharedMemoryPrivate::semaphoreNativeKey() const | 
| 46 | { | 
| 47 |     if (isIpcSupported(ipcType: IpcType::SharedMemory, type: QNativeIpcKey::Type::Windows) | 
| 48 |             && nativeKey.type() == QNativeIpcKey::Type::Windows) { | 
| 49 |         // native keys are plain kernel object names, limited to MAX_PATH | 
| 50 |         auto suffix = "_sem"_L1 ; | 
| 51 |         QString semkey = nativeKey.nativeKey(); | 
| 52 |         semkey.truncate(MAX_PATH - suffix.size() - 1); | 
| 53 |         semkey += suffix; | 
| 54 |         return { semkey, QNativeIpcKey::Type::Windows }; | 
| 55 |     } | 
| 56 |  | 
| 57 |     // System V and POSIX keys appear to operate in different namespaces, so we | 
| 58 |     // can just use the same native key | 
| 59 |     return nativeKey; | 
| 60 | } | 
| 61 | #endif | 
| 62 |  | 
| 63 | /*! | 
| 64 |   \class QSharedMemory | 
| 65 |   \inmodule QtCore | 
| 66 |   \since 4.4 | 
| 67 |  | 
| 68 |   \brief The QSharedMemory class provides access to a shared memory segment. | 
| 69 |  | 
| 70 |   QSharedMemory provides access to a \l{Shared Memory}{shared memory segment} | 
| 71 |   by multiple threads and processes. Shared memory segments are identified by a | 
| 72 |   key, represented by \l QNativeIpcKey. A key can be created in a | 
| 73 |   cross-platform manner by using platformSafeKey(). | 
| 74 |  | 
| 75 |   One QSharedMemory object must create() the segment and this call specifies | 
| 76 |   the size of the segment. All other processes simply attach() to the segment | 
| 77 |   that must already exist. After either operation is successful, the | 
| 78 |   application may call data() to obtain a pointer to the data. | 
| 79 |  | 
| 80 |   To support non-atomic operations, QSharedMemory provides API to gain | 
| 81 |   exclusive access: you may lock the shared memory with lock() before reading | 
| 82 |   from or writing to the shared memory, but remember to release the lock with | 
| 83 |   unlock() after you are done. | 
| 84 |  | 
| 85 |   By default, QSharedMemory automatically destroys the shared memory segment | 
| 86 |   when the last instance of QSharedMemory is \l{detach()}{detached} from the | 
| 87 |   segment, and no references to the segment remain. | 
| 88 |  | 
| 89 |   For details on the key types, platform-specific limitations, and | 
| 90 |   interoperability with older or non-Qt applications, see the \l{Native IPC | 
| 91 |   Keys} documentation. That includes important information for sandboxed | 
| 92 |   applications on Apple platforms, including all apps obtained via the Apple | 
| 93 |   App Store. | 
| 94 |  | 
| 95 |   \sa {Inter-Process Communication}, QSystemSemaphore | 
| 96 |  */ | 
| 97 |  | 
| 98 | /*! | 
| 99 |   \overload QSharedMemory() | 
| 100 |  | 
| 101 |   Constructs a shared memory object with the given \a parent. The shared memory | 
| 102 |   object's key is not set by the constructor, so the shared memory object does | 
| 103 |   not have an underlying shared memory segment attached. The key must be set | 
| 104 |   with setNativeKey() before create() or attach() can be used. | 
| 105 |  | 
| 106 |   \sa setNativeKey() | 
| 107 |  */ | 
| 108 |  | 
| 109 | QSharedMemory::QSharedMemory(QObject *parent) | 
| 110 |     : QSharedMemory(QNativeIpcKey(), parent) | 
| 111 | { | 
| 112 | } | 
| 113 |  | 
| 114 | /*! | 
| 115 |   \overload | 
| 116 |  | 
| 117 |   Constructs a shared memory object with the given \a parent and with | 
| 118 |   its key set to \a key. Because its key is set, its create() and | 
| 119 |   attach() functions can be called. | 
| 120 |  | 
| 121 |   \sa setNativeKey(), create(), attach() | 
| 122 |  */ | 
| 123 | QSharedMemory::QSharedMemory(const QNativeIpcKey &key, QObject *parent) | 
| 124 |     : QObject(*new QSharedMemoryPrivate(key.type()), parent) | 
| 125 | { | 
| 126 |     setNativeKey(key); | 
| 127 | } | 
| 128 |  | 
| 129 | /*! | 
| 130 |   Constructs a shared memory object with the given \a parent and with | 
| 131 |   the legacy key set to \a key. Because its key is set, its create() and | 
| 132 |   attach() functions can be called. | 
| 133 |  | 
| 134 |   \sa setKey(), create(), attach() | 
| 135 |  */ | 
| 136 | QSharedMemory::QSharedMemory(const QString &key, QObject *parent) | 
| 137 |     : QSharedMemory(legacyNativeKey(key), parent) | 
| 138 | { | 
| 139 | } | 
| 140 |  | 
| 141 | /*! | 
| 142 |   The destructor clears the key, which forces the shared memory object | 
| 143 |   to \l {detach()} {detach} from its underlying shared memory | 
| 144 |   segment. If this shared memory object is the last one connected to | 
| 145 |   the shared memory segment, the detach() operation destroys the | 
| 146 |   shared memory segment. | 
| 147 |  | 
| 148 |   \sa detach(), isAttached() | 
| 149 |  */ | 
| 150 | QSharedMemory::~QSharedMemory() | 
| 151 | { | 
| 152 |     Q_D(QSharedMemory); | 
| 153 |     if (isAttached()) | 
| 154 |         detach(); | 
| 155 |     d->cleanHandle(); | 
| 156 | } | 
| 157 |  | 
| 158 | /*! | 
| 159 |   \overload | 
| 160 |  | 
| 161 |   Sets the legacy \a key for this shared memory object. If \a key is the same | 
| 162 |   as the current key, the function returns without doing anything. Otherwise, | 
| 163 |   if the shared memory object is attached to an underlying shared memory | 
| 164 |   segment, it will \l {detach()} {detach} from it before setting the new key. | 
| 165 |   This function does not do an attach(). | 
| 166 |  | 
| 167 |   You can call key() to retrieve the legacy key. This function is mostly the | 
| 168 |   same as: | 
| 169 |  | 
| 170 |   \code | 
| 171 |     shm.setNativeKey(QSharedMemory::legacyNativeKey(key)); | 
| 172 |   \endcode | 
| 173 |  | 
| 174 |   except that it enables obtaining the legacy key using key(). | 
| 175 |  | 
| 176 |   \sa key(), nativeKey(), isAttached() | 
| 177 | */ | 
| 178 | void QSharedMemory::setKey(const QString &key) | 
| 179 | { | 
| 180 |     setNativeKey(legacyNativeKey(key)); | 
| 181 | } | 
| 182 |  | 
| 183 | /*! | 
| 184 |   \since 4.8 | 
| 185 |   \fn void QSharedMemory::setNativeKey(const QString &key, QNativeIpcKey::Type type) | 
| 186 |  | 
| 187 |   Sets the native, platform specific, \a key for this shared memory object of | 
| 188 |   type \a type (the type parameter has been available since Qt 6.6). If \a key | 
| 189 |   is the same as the current native key, the function returns without doing | 
| 190 |   anything. Otherwise, if the shared memory object is attached to an underlying | 
| 191 |   shared memory segment, it will \l {detach()} {detach} from it before setting | 
| 192 |   the new key. This function does not do an attach(). | 
| 193 |  | 
| 194 |   This function is useful if the native key was shared from another process, | 
| 195 |   though the application must take care to ensure the key type matches what the | 
| 196 |   other process expects. See \l{Native IPC Keys} for more information. | 
| 197 |  | 
| 198 |   Portable native keys can be obtained using platformSafeKey(). | 
| 199 |  | 
| 200 |   You can call nativeKey() to retrieve the native key. | 
| 201 |  | 
| 202 |   \sa nativeKey(), nativeIpcKey(), isAttached() | 
| 203 | */ | 
| 204 |  | 
| 205 | /*! | 
| 206 |   \since 6.6 | 
| 207 |  | 
| 208 |   Sets the native, platform specific, \a key for this shared memory object. If | 
| 209 |   \a key is the same as the current native key, the function returns without | 
| 210 |   doing anything. Otherwise, if the shared memory object is attached to an | 
| 211 |   underlying shared memory segment, it will \l {detach()} {detach} from it | 
| 212 |   before setting the new key. This function does not do an attach(). | 
| 213 |  | 
| 214 |   This function is useful if the native key was shared from another process. | 
| 215 |   See \l{Native IPC Keys} for more information. | 
| 216 |  | 
| 217 |   Portable native keys can be obtained using platformSafeKey(). | 
| 218 |  | 
| 219 |   You can call nativeKey() to retrieve the native key. | 
| 220 |  | 
| 221 |   \sa nativeKey(), nativeIpcKey(), isAttached() | 
| 222 | */ | 
| 223 | void QSharedMemory::setNativeKey(const QNativeIpcKey &key) | 
| 224 | { | 
| 225 |     Q_D(QSharedMemory); | 
| 226 |     if (key == d->nativeKey && key.isEmpty()) | 
| 227 |         return; | 
| 228 |     if (!isKeyTypeSupported(type: key.type())) { | 
| 229 |         d->setError(e: KeyError, message: tr(s: "%1: unsupported key type" ) | 
| 230 |                     .arg(a: "QSharedMemory::setNativeKey"_L1 )); | 
| 231 |         return; | 
| 232 |     } | 
| 233 |  | 
| 234 |     if (isAttached()) | 
| 235 |         detach(); | 
| 236 |     d->cleanHandle(); | 
| 237 |     if (key.type() == d->nativeKey.type()) { | 
| 238 |         // we can reuse the backend | 
| 239 |         d->nativeKey = key; | 
| 240 |     } else { | 
| 241 |         // we must recreate the backend | 
| 242 |         d->destructBackend(); | 
| 243 |         d->nativeKey = key; | 
| 244 |         d->constructBackend(); | 
| 245 |     } | 
| 246 | } | 
| 247 |  | 
| 248 | bool QSharedMemoryPrivate::initKey(SemaphoreAccessMode mode) | 
| 249 | { | 
| 250 |     if (!cleanHandle()) | 
| 251 |         return false; | 
| 252 | #if QT_CONFIG(systemsemaphore) | 
| 253 |     const QString legacyKey = QNativeIpcKeyPrivate::legacyKey(key: nativeKey); | 
| 254 |     const QNativeIpcKey semKey = legacyKey.isEmpty() | 
| 255 |             ? semaphoreNativeKey() | 
| 256 |             : QSystemSemaphore::legacyNativeKey(key: legacyKey, type: nativeKey.type()); | 
| 257 |     systemSemaphore.setNativeKey(key: semKey, initialValue: 1, mode); | 
| 258 |     if (systemSemaphore.error() != QSystemSemaphore::NoError) { | 
| 259 |         QString function = "QSharedMemoryPrivate::initKey"_L1 ; | 
| 260 |         errorString = QSharedMemory::tr(s: "%1: unable to set key on lock (%2)" ) | 
| 261 |                 .arg(args&: function, args: systemSemaphore.errorString()); | 
| 262 |         switch(systemSemaphore.error()) { | 
| 263 |         case QSystemSemaphore::PermissionDenied: | 
| 264 |             error = QSharedMemory::PermissionDenied; | 
| 265 |             break; | 
| 266 |         case QSystemSemaphore::KeyError: | 
| 267 |             error = QSharedMemory::KeyError; | 
| 268 |             break; | 
| 269 |         case QSystemSemaphore::AlreadyExists: | 
| 270 |             error = QSharedMemory::AlreadyExists; | 
| 271 |             break; | 
| 272 |         case QSystemSemaphore::NotFound: | 
| 273 |             error = QSharedMemory::NotFound; | 
| 274 |             break; | 
| 275 |         case QSystemSemaphore::OutOfResources: | 
| 276 |             error = QSharedMemory::OutOfResources; | 
| 277 |             break; | 
| 278 |         case QSystemSemaphore::UnknownError: | 
| 279 |         default: | 
| 280 |             error = QSharedMemory::UnknownError; | 
| 281 |             break; | 
| 282 |         } | 
| 283 |         return false; | 
| 284 |     } | 
| 285 | #else | 
| 286 |     Q_UNUSED(mode); | 
| 287 | #endif | 
| 288 |     errorString = QString(); | 
| 289 |     error = QSharedMemory::NoError; | 
| 290 |     return true; | 
| 291 | } | 
| 292 |  | 
| 293 | /*! | 
| 294 |   Returns the legacy key assigned with setKey() to this shared memory, or a null key | 
| 295 |   if no key has been assigned, or if the segment is using a nativeKey(). The | 
| 296 |   key is the identifier used by Qt applications to identify the shared memory | 
| 297 |   segment. | 
| 298 |  | 
| 299 |   You can find the native, platform specific, key used by the operating system | 
| 300 |   by calling nativeKey(). | 
| 301 |  | 
| 302 |   \sa setKey(), setNativeKey() | 
| 303 |  */ | 
| 304 | QString QSharedMemory::key() const | 
| 305 | { | 
| 306 |     Q_D(const QSharedMemory); | 
| 307 |     return QNativeIpcKeyPrivate::legacyKey(key: d->nativeKey); | 
| 308 | } | 
| 309 |  | 
| 310 | /*! | 
| 311 |   \since 4.8 | 
| 312 |  | 
| 313 |   Returns the native, platform specific, key for this shared memory object. The | 
| 314 |   native key is the identifier used by the operating system to identify the | 
| 315 |   shared memory segment. | 
| 316 |  | 
| 317 |   You can use the native key to access shared memory segments that have not | 
| 318 |   been created by Qt, or to grant shared memory access to non-Qt applications. | 
| 319 |   See \l{Native IPC Keys} for more information. | 
| 320 |  | 
| 321 |   \sa setNativeKey(), nativeIpcKey() | 
| 322 | */ | 
| 323 | QString QSharedMemory::nativeKey() const | 
| 324 | { | 
| 325 |     Q_D(const QSharedMemory); | 
| 326 |     return d->nativeKey.nativeKey(); | 
| 327 | } | 
| 328 |  | 
| 329 | /*! | 
| 330 |   \since 6.6 | 
| 331 |  | 
| 332 |   Returns the key type for this shared memory object. The key type complements | 
| 333 |   the nativeKey() as the identifier used by the operating system to identify | 
| 334 |   the shared memory segment. | 
| 335 |  | 
| 336 |   You can use the native key to access shared memory segments that have not | 
| 337 |   been created by Qt, or to grant shared memory access to non-Qt applications. | 
| 338 |   See \l{Native IPC Keys} for more information. | 
| 339 |  | 
| 340 |   \sa nativeKey(), setNativeKey() | 
| 341 | */ | 
| 342 | QNativeIpcKey QSharedMemory::nativeIpcKey() const | 
| 343 | { | 
| 344 |     Q_D(const QSharedMemory); | 
| 345 |     return d->nativeKey; | 
| 346 | } | 
| 347 |  | 
| 348 | /*! | 
| 349 |   Creates a shared memory segment of \a size bytes with the key passed to the | 
| 350 |   constructor or set with setNativeKey(), then attaches to | 
| 351 |   the new shared memory segment with the given access \a mode and returns | 
| 352 |   \tt true. If a shared memory segment identified by the key already exists, | 
| 353 |   the attach operation is not performed and \tt false is returned. When the | 
| 354 |   return value is \tt false, call error() to determine which error occurred. | 
| 355 |  | 
| 356 |   \sa error() | 
| 357 |  */ | 
| 358 | bool QSharedMemory::create(qsizetype size, AccessMode mode) | 
| 359 | { | 
| 360 |     Q_D(QSharedMemory); | 
| 361 |     QLatin1StringView function = "QSharedMemory::create"_L1 ; | 
| 362 |  | 
| 363 | #if QT_CONFIG(systemsemaphore) | 
| 364 |     if (!d->initKey(mode: QSystemSemaphore::Create)) | 
| 365 |         return false; | 
| 366 |     QSharedMemoryLocker lock(this); | 
| 367 |     if (!d->nativeKey.isEmpty() && !d->tryLocker(locker: &lock, function)) | 
| 368 |         return false; | 
| 369 | #else | 
| 370 |     if (!d->initKey({})) | 
| 371 |         return false; | 
| 372 | #endif | 
| 373 |  | 
| 374 |     if (size <= 0) { | 
| 375 |         d->error = QSharedMemory::InvalidSize; | 
| 376 |         d->errorString = | 
| 377 |             QSharedMemory::tr(s: "%1: create size is less then 0" ).arg(a: function); | 
| 378 |         return false; | 
| 379 |     } | 
| 380 |  | 
| 381 |     if (!d->create(sz: size)) | 
| 382 |         return false; | 
| 383 |  | 
| 384 |     return d->attach(mode); | 
| 385 | } | 
| 386 |  | 
| 387 | /*! | 
| 388 |   Returns the size of the attached shared memory segment. If no shared | 
| 389 |   memory segment is attached, 0 is returned. | 
| 390 |  | 
| 391 |   \note The size of the segment may be larger than the requested size that was | 
| 392 |   passed to create(). | 
| 393 |  | 
| 394 |   \sa create(), attach() | 
| 395 |  */ | 
| 396 | qsizetype QSharedMemory::size() const | 
| 397 | { | 
| 398 |     Q_D(const QSharedMemory); | 
| 399 |     return d->size; | 
| 400 | } | 
| 401 |  | 
| 402 | /*! | 
| 403 |   \enum QSharedMemory::AccessMode | 
| 404 |  | 
| 405 |   \value ReadOnly The shared memory segment is read-only. Writing to | 
| 406 |   the shared memory segment is not allowed. An attempt to write to a | 
| 407 |   shared memory segment created with ReadOnly causes the program to | 
| 408 |   abort. | 
| 409 |  | 
| 410 |   \value ReadWrite Reading and writing the shared memory segment are | 
| 411 |   both allowed. | 
| 412 | */ | 
| 413 |  | 
| 414 | /*! | 
| 415 |   Attempts to attach the process to the shared memory segment | 
| 416 |   identified by the key that was passed to the constructor or to a | 
| 417 |   call to setNativeKey(). The access \a mode is \l {QSharedMemory::} | 
| 418 |   {ReadWrite} by default. It can also be \l {QSharedMemory::} | 
| 419 |   {ReadOnly}. Returns \c true if the attach operation is successful. If | 
| 420 |   false is returned, call error() to determine which error occurred. | 
| 421 |   After attaching the shared memory segment, a pointer to the shared | 
| 422 |   memory can be obtained by calling data(). | 
| 423 |  | 
| 424 |   \sa isAttached(), detach(), create() | 
| 425 |  */ | 
| 426 | bool QSharedMemory::attach(AccessMode mode) | 
| 427 | { | 
| 428 |     Q_D(QSharedMemory); | 
| 429 |  | 
| 430 |     if (isAttached() || !d->initKey(mode: {})) | 
| 431 |         return false; | 
| 432 | #if QT_CONFIG(systemsemaphore) | 
| 433 |     QSharedMemoryLocker lock(this); | 
| 434 |     if (!d->nativeKey.isEmpty() && !d->tryLocker(locker: &lock, function: "QSharedMemory::attach"_L1 )) | 
| 435 |         return false; | 
| 436 | #endif | 
| 437 |  | 
| 438 |     if (isAttached() || !d->handle()) | 
| 439 |         return false; | 
| 440 |  | 
| 441 |     return d->attach(mode); | 
| 442 | } | 
| 443 |  | 
| 444 | /*! | 
| 445 |   Returns \c true if this process is attached to the shared memory | 
| 446 |   segment. | 
| 447 |  | 
| 448 |   \sa attach(), detach() | 
| 449 |  */ | 
| 450 | bool QSharedMemory::isAttached() const | 
| 451 | { | 
| 452 |     Q_D(const QSharedMemory); | 
| 453 |     return (nullptr != d->memory); | 
| 454 | } | 
| 455 |  | 
| 456 | /*! | 
| 457 |   Detaches the process from the shared memory segment. If this was the | 
| 458 |   last process attached to the shared memory segment, then the shared | 
| 459 |   memory segment is released by the system, i.e., the contents are | 
| 460 |   destroyed. The function returns \c true if it detaches the shared | 
| 461 |   memory segment. If it returns \c false, it usually means the segment | 
| 462 |   either isn't attached, or it is locked by another process. | 
| 463 |  | 
| 464 |   \sa attach(), isAttached() | 
| 465 |  */ | 
| 466 | bool QSharedMemory::detach() | 
| 467 | { | 
| 468 |     Q_D(QSharedMemory); | 
| 469 |     if (!isAttached()) | 
| 470 |         return false; | 
| 471 |  | 
| 472 | #if QT_CONFIG(systemsemaphore) | 
| 473 |     QSharedMemoryLocker lock(this); | 
| 474 |     if (!d->nativeKey.isEmpty() && !d->tryLocker(locker: &lock, function: "QSharedMemory::detach"_L1 )) | 
| 475 |         return false; | 
| 476 | #endif | 
| 477 |  | 
| 478 |     return d->detach(); | 
| 479 | } | 
| 480 |  | 
| 481 | /*! | 
| 482 |   Returns a pointer to the contents of the shared memory segment, if one is | 
| 483 |   attached. Otherwise it returns null. The value returned by this function will | 
| 484 |   not change until a \l {detach()}{detach} happens, so it is safe to store this | 
| 485 |   pointer. | 
| 486 |  | 
| 487 |   If the memory operations are not atomic, you may lock the shared memory with | 
| 488 |   lock() before reading from or writing, but remember to release the lock with | 
| 489 |   unlock() after you are done. | 
| 490 |  | 
| 491 |   \sa attach() | 
| 492 |  */ | 
| 493 | void *QSharedMemory::data() | 
| 494 | { | 
| 495 |     Q_D(QSharedMemory); | 
| 496 |     return d->memory; | 
| 497 | } | 
| 498 |  | 
| 499 | /*! | 
| 500 |   Returns a const pointer to the contents of the shared memory segment, if one | 
| 501 |   is attached. Otherwise it returns null. The value returned by this function | 
| 502 |   will not change until a \l {detach()}{detach} happens, so it is safe to store | 
| 503 |   this pointer. | 
| 504 |  | 
| 505 |   If the memory operations are not atomic, you may lock the shared memory with | 
| 506 |   lock() before reading from or writing, but remember to release the lock with | 
| 507 |   unlock() after you are done. | 
| 508 |  | 
| 509 |   \sa attach(), create() | 
| 510 |  */ | 
| 511 | const void *QSharedMemory::constData() const | 
| 512 | { | 
| 513 |     Q_D(const QSharedMemory); | 
| 514 |     return d->memory; | 
| 515 | } | 
| 516 |  | 
| 517 | /*! | 
| 518 |   \overload data() | 
| 519 |  */ | 
| 520 | const void *QSharedMemory::data() const | 
| 521 | { | 
| 522 |     Q_D(const QSharedMemory); | 
| 523 |     return d->memory; | 
| 524 | } | 
| 525 |  | 
| 526 | #if QT_CONFIG(systemsemaphore) | 
| 527 | /*! | 
| 528 |   This is a semaphore that locks the shared memory segment for access | 
| 529 |   by this process and returns \c true. If another process has locked the | 
| 530 |   segment, this function blocks until the lock is released. Then it | 
| 531 |   acquires the lock and returns \c true. If this function returns \c false, | 
| 532 |   it means that you have ignored a false return from create() or attach(), | 
| 533 |   that you have set the key with setNativeKey() or that | 
| 534 |   QSystemSemaphore::acquire() failed due to an unknown system error. | 
| 535 |  | 
| 536 |   \sa unlock(), data(), QSystemSemaphore::acquire() | 
| 537 |  */ | 
| 538 | bool QSharedMemory::lock() | 
| 539 | { | 
| 540 |     Q_D(QSharedMemory); | 
| 541 |     if (d->lockedByMe) { | 
| 542 |         qWarning(msg: "QSharedMemory::lock: already locked" ); | 
| 543 |         return true; | 
| 544 |     } | 
| 545 |     if (d->systemSemaphore.acquire()) { | 
| 546 |         d->lockedByMe = true; | 
| 547 |         return true; | 
| 548 |     } | 
| 549 |     const auto function = "QSharedMemory::lock"_L1 ; | 
| 550 |     d->errorString = QSharedMemory::tr(s: "%1: unable to lock" ).arg(a: function); | 
| 551 |     d->error = QSharedMemory::LockError; | 
| 552 |     return false; | 
| 553 | } | 
| 554 |  | 
| 555 | /*! | 
| 556 |   Releases the lock on the shared memory segment and returns \c true, if | 
| 557 |   the lock is currently held by this process. If the segment is not | 
| 558 |   locked, or if the lock is held by another process, nothing happens | 
| 559 |   and false is returned. | 
| 560 |  | 
| 561 |   \sa lock() | 
| 562 |  */ | 
| 563 | bool QSharedMemory::unlock() | 
| 564 | { | 
| 565 |     Q_D(QSharedMemory); | 
| 566 |     if (!d->lockedByMe) | 
| 567 |         return false; | 
| 568 |     d->lockedByMe = false; | 
| 569 |     if (d->systemSemaphore.release()) | 
| 570 |         return true; | 
| 571 |     const auto function = "QSharedMemory::unlock"_L1 ; | 
| 572 |     d->errorString = QSharedMemory::tr(s: "%1: unable to unlock" ).arg(a: function); | 
| 573 |     d->error = QSharedMemory::LockError; | 
| 574 |     return false; | 
| 575 | } | 
| 576 | #endif // QT_CONFIG(systemsemaphore) | 
| 577 |  | 
| 578 | /*! | 
| 579 |   \enum QSharedMemory::SharedMemoryError | 
| 580 |  | 
| 581 |   \value NoError No error occurred. | 
| 582 |  | 
| 583 |   \value PermissionDenied The operation failed because the caller | 
| 584 |   didn't have the required permissions. | 
| 585 |  | 
| 586 |   \value InvalidSize A create operation failed because the requested | 
| 587 |   size was invalid. | 
| 588 |  | 
| 589 |   \value KeyError The operation failed because of an invalid key. | 
| 590 |  | 
| 591 |   \value AlreadyExists A create() operation failed because a shared | 
| 592 |   memory segment with the specified key already existed. | 
| 593 |  | 
| 594 |   \value NotFound An attach() failed because a shared memory segment | 
| 595 |   with the specified key could not be found. | 
| 596 |  | 
| 597 |   \value LockError The attempt to lock() the shared memory segment | 
| 598 |   failed because create() or attach() failed and returned false, or | 
| 599 |   because a system error occurred in QSystemSemaphore::acquire(). | 
| 600 |  | 
| 601 |   \value OutOfResources A create() operation failed because there was | 
| 602 |   not enough memory available to fill the request. | 
| 603 |  | 
| 604 |   \value UnknownError Something else happened and it was bad. | 
| 605 | */ | 
| 606 |  | 
| 607 | /*! | 
| 608 |   Returns a value indicating whether an error occurred, and, if so, | 
| 609 |   which error it was. | 
| 610 |  | 
| 611 |   \sa errorString() | 
| 612 |  */ | 
| 613 | QSharedMemory::SharedMemoryError QSharedMemory::error() const | 
| 614 | { | 
| 615 |     Q_D(const QSharedMemory); | 
| 616 |     return d->error; | 
| 617 | } | 
| 618 |  | 
| 619 | /*! | 
| 620 |   Returns a text description of the last error that occurred. If | 
| 621 |   error() returns an \l {QSharedMemory::SharedMemoryError} {error | 
| 622 |   value}, call this function to get a text string that describes the | 
| 623 |   error. | 
| 624 |  | 
| 625 |   \sa error() | 
| 626 |  */ | 
| 627 | QString QSharedMemory::errorString() const | 
| 628 | { | 
| 629 |     Q_D(const QSharedMemory); | 
| 630 |     return d->errorString; | 
| 631 | } | 
| 632 |  | 
| 633 | void QSharedMemoryPrivate::setUnixErrorString(QLatin1StringView function) | 
| 634 | { | 
| 635 |     // EINVAL is handled in functions so they can give better error strings | 
| 636 |     switch (errno) { | 
| 637 |     case EACCES: | 
| 638 |         errorString = QSharedMemory::tr(s: "%1: permission denied" ).arg(a: function); | 
| 639 |         error = QSharedMemory::PermissionDenied; | 
| 640 |         break; | 
| 641 |     case EEXIST: | 
| 642 |         errorString = QSharedMemory::tr(s: "%1: already exists" ).arg(a: function); | 
| 643 |         error = QSharedMemory::AlreadyExists; | 
| 644 |         break; | 
| 645 |     case ENOENT: | 
| 646 |         errorString = QSharedMemory::tr(s: "%1: doesn't exist" ).arg(a: function); | 
| 647 |         error = QSharedMemory::NotFound; | 
| 648 |         break; | 
| 649 |     case EMFILE: | 
| 650 |     case ENOMEM: | 
| 651 |     case ENOSPC: | 
| 652 |         errorString = QSharedMemory::tr(s: "%1: out of resources" ).arg(a: function); | 
| 653 |         error = QSharedMemory::OutOfResources; | 
| 654 |         break; | 
| 655 |     default: | 
| 656 |         errorString = QSharedMemory::tr(s: "%1: unknown error: %2" ) | 
| 657 |                 .arg(args&: function, args: qt_error_string(errno)); | 
| 658 |         error = QSharedMemory::UnknownError; | 
| 659 | #if defined QSHAREDMEMORY_DEBUG | 
| 660 |         qDebug() << errorString << "key"  << key << "errno"  << errno << EINVAL; | 
| 661 | #endif | 
| 662 |     } | 
| 663 | } | 
| 664 |  | 
| 665 | bool QSharedMemory::isKeyTypeSupported(QNativeIpcKey::Type type) | 
| 666 | { | 
| 667 |     if (!isIpcSupported(ipcType: IpcType::SharedMemory, type)) | 
| 668 |         return false; | 
| 669 |     using Variant = decltype(QSharedMemoryPrivate::backend); | 
| 670 |     return Variant::staticVisit(keyType: type, lambda: [](auto ptr) { | 
| 671 |         using Impl = std::decay_t<decltype(*ptr)>; | 
| 672 |         return Impl::runtimeSupportCheck(); | 
| 673 |     }); | 
| 674 | } | 
| 675 |  | 
| 676 | QNativeIpcKey QSharedMemory::platformSafeKey(const QString &key, QNativeIpcKey::Type type) | 
| 677 | { | 
| 678 |     return QtIpcCommon::platformSafeKey(key, ipcType: IpcType::SharedMemory, type); | 
| 679 | } | 
| 680 |  | 
| 681 | QNativeIpcKey QSharedMemory::legacyNativeKey(const QString &key, QNativeIpcKey::Type type) | 
| 682 | { | 
| 683 |     return QtIpcCommon::legacyPlatformSafeKey(key, ipcType: IpcType::SharedMemory, type); | 
| 684 | } | 
| 685 |  | 
| 686 | #endif // QT_CONFIG(sharedmemory) | 
| 687 |  | 
| 688 | QT_END_NAMESPACE | 
| 689 |  | 
| 690 | #include "moc_qsharedmemory.cpp" | 
| 691 |  |