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