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 | /*! |
129 | Constructs a shared memory object with the given \a parent and with |
130 | the legacy key set to \a key. Because its key is set, its create() and |
131 | attach() functions can be called. |
132 | |
133 | \sa setKey(), create(), attach() |
134 | */ |
135 | QSharedMemory::QSharedMemory(const QString &key, QObject *parent) |
136 | : QSharedMemory(legacyNativeKey(key), parent) |
137 | { |
138 | } |
139 | |
140 | /*! |
141 | The destructor clears the key, which forces the shared memory object |
142 | to \l {detach()} {detach} from its underlying shared memory |
143 | segment. If this shared memory object is the last one connected to |
144 | the shared memory segment, the detach() operation destroys the |
145 | shared memory segment. |
146 | |
147 | \sa detach(), isAttached() |
148 | */ |
149 | QSharedMemory::~QSharedMemory() |
150 | { |
151 | Q_D(QSharedMemory); |
152 | if (isAttached()) |
153 | detach(); |
154 | d->cleanHandle(); |
155 | } |
156 | |
157 | /*! |
158 | \overload |
159 | |
160 | Sets the legacy \a key for this shared memory object. If \a key is the same |
161 | as the current key, the function returns without doing anything. Otherwise, |
162 | if the shared memory object is attached to an underlying shared memory |
163 | segment, it will \l {detach()} {detach} from it before setting the new key. |
164 | This function does not do an attach(). |
165 | |
166 | You can call key() to retrieve the legacy key. This function is mostly the |
167 | same as: |
168 | |
169 | \code |
170 | shm.setNativeKey(QSharedMemory::legacyNativeKey(key)); |
171 | \endcode |
172 | |
173 | except that it enables obtaining the legacy key using key(). |
174 | |
175 | \sa key(), nativeKey(), isAttached() |
176 | */ |
177 | void QSharedMemory::setKey(const QString &key) |
178 | { |
179 | setNativeKey(legacyNativeKey(key)); |
180 | } |
181 | |
182 | /*! |
183 | \since 4.8 |
184 | \fn void QSharedMemory::setNativeKey(const QString &key, QNativeIpcKey::Type type) |
185 | |
186 | Sets the native, platform specific, \a key for this shared memory object of |
187 | type \a type (the type parameter has been available since Qt 6.6). If \a key |
188 | is the same as the current native key, the function returns without doing |
189 | anything. Otherwise, if the shared memory object is attached to an underlying |
190 | shared memory segment, it will \l {detach()} {detach} from it before setting |
191 | the new key. This function does not do an attach(). |
192 | |
193 | This function is useful if the native key was shared from another process, |
194 | though the application must take care to ensure the key type matches what the |
195 | other process expects. See \l{Native IPC Keys} for more information. |
196 | |
197 | Portable native keys can be obtained using platformSafeKey(). |
198 | |
199 | You can call nativeKey() to retrieve the native key. |
200 | |
201 | \sa nativeKey(), nativeIpcKey(), isAttached() |
202 | */ |
203 | |
204 | /*! |
205 | \since 6.6 |
206 | |
207 | Sets the native, platform specific, \a key for this shared memory object. If |
208 | \a key is the same as the current native key, the function returns without |
209 | doing anything. Otherwise, if the shared memory object is attached to an |
210 | underlying shared memory segment, it will \l {detach()} {detach} from it |
211 | before setting the new key. This function does not do an attach(). |
212 | |
213 | This function is useful if the native key was shared from another process. |
214 | See \l{Native IPC Keys} for more information. |
215 | |
216 | Portable native keys can be obtained using platformSafeKey(). |
217 | |
218 | You can call nativeKey() to retrieve the native key. |
219 | |
220 | \sa nativeKey(), nativeIpcKey(), isAttached() |
221 | */ |
222 | void QSharedMemory::setNativeKey(const QNativeIpcKey &key) |
223 | { |
224 | Q_D(QSharedMemory); |
225 | if (key == d->nativeKey && key.isEmpty()) |
226 | return; |
227 | if (!isKeyTypeSupported(type: key.type())) { |
228 | d->setError(e: KeyError, message: tr(s: "%1: unsupported key type" ) |
229 | .arg(a: "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 | |
247 | bool QSharedMemoryPrivate::initKey(SemaphoreAccessMode mode) |
248 | { |
249 | if (!cleanHandle()) |
250 | return false; |
251 | #if QT_CONFIG(systemsemaphore) |
252 | const QString legacyKey = QNativeIpcKeyPrivate::legacyKey(key: nativeKey); |
253 | const QNativeIpcKey semKey = legacyKey.isEmpty() |
254 | ? semaphoreNativeKey() |
255 | : QSystemSemaphore::legacyNativeKey(key: legacyKey, type: nativeKey.type()); |
256 | systemSemaphore.setNativeKey(key: semKey, initialValue: 1, mode); |
257 | if (systemSemaphore.error() != QSystemSemaphore::NoError) { |
258 | QString function = "QSharedMemoryPrivate::initKey"_L1 ; |
259 | errorString = QSharedMemory::tr(s: "%1: unable to set key on lock (%2)" ) |
260 | .arg(args&: function, args: 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 |
287 | errorString = QString(); |
288 | error = QSharedMemory::NoError; |
289 | return true; |
290 | } |
291 | |
292 | /*! |
293 | Returns the legacy key assigned with setKey() to this shared memory, or a null key |
294 | if no key has been assigned, or if the segment is using a nativeKey(). The |
295 | key is the identifier used by Qt applications to identify the shared memory |
296 | segment. |
297 | |
298 | You can find the native, platform specific, key used by the operating system |
299 | by calling nativeKey(). |
300 | |
301 | \sa setKey(), setNativeKey() |
302 | */ |
303 | QString QSharedMemory::key() const |
304 | { |
305 | Q_D(const QSharedMemory); |
306 | return QNativeIpcKeyPrivate::legacyKey(key: d->nativeKey); |
307 | } |
308 | |
309 | /*! |
310 | \since 4.8 |
311 | |
312 | Returns the native, platform specific, key for this shared memory object. The |
313 | native key is the identifier used by the operating system to identify the |
314 | shared memory segment. |
315 | |
316 | You can use the native key to access shared memory segments that have not |
317 | been created by Qt, or to grant shared memory access to non-Qt applications. |
318 | See \l{Native IPC Keys} for more information. |
319 | |
320 | \sa setNativeKey(), nativeIpcKey() |
321 | */ |
322 | QString QSharedMemory::nativeKey() const |
323 | { |
324 | Q_D(const QSharedMemory); |
325 | return d->nativeKey.nativeKey(); |
326 | } |
327 | |
328 | /*! |
329 | \since 6.6 |
330 | |
331 | Returns the key type for this shared memory object. The key type complements |
332 | the nativeKey() as the identifier used by the operating system to identify |
333 | the shared memory segment. |
334 | |
335 | You can use the native key to access shared memory segments that have not |
336 | been created by Qt, or to grant shared memory access to non-Qt applications. |
337 | See \l{Native IPC Keys} for more information. |
338 | |
339 | \sa nativeKey(), setNativeKey() |
340 | */ |
341 | QNativeIpcKey QSharedMemory::nativeIpcKey() const |
342 | { |
343 | Q_D(const QSharedMemory); |
344 | return d->nativeKey; |
345 | } |
346 | |
347 | /*! |
348 | Creates a shared memory segment of \a size bytes with the key passed to the |
349 | constructor or set with setNativeKey(), then attaches to |
350 | the new shared memory segment with the given access \a mode and returns |
351 | \tt true. If a shared memory segment identified by the key already exists, |
352 | the attach operation is not performed and \tt false is returned. When the |
353 | return value is \tt false, call error() to determine which error occurred. |
354 | |
355 | \sa error() |
356 | */ |
357 | bool 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(mode: QSystemSemaphore::Create)) |
364 | return false; |
365 | QSharedMemoryLocker lock(this); |
366 | if (!d->nativeKey.isEmpty() && !d->tryLocker(locker: &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(s: "%1: create size is less then 0" ).arg(a: function); |
377 | return false; |
378 | } |
379 | |
380 | if (!d->create(sz: size)) |
381 | return false; |
382 | |
383 | return d->attach(mode); |
384 | } |
385 | |
386 | /*! |
387 | Returns the size of the attached shared memory segment. If no shared |
388 | memory segment is attached, 0 is returned. |
389 | |
390 | \note The size of the segment may be larger than the requested size that was |
391 | passed to create(). |
392 | |
393 | \sa create(), attach() |
394 | */ |
395 | qsizetype QSharedMemory::size() const |
396 | { |
397 | Q_D(const QSharedMemory); |
398 | return d->size; |
399 | } |
400 | |
401 | /*! |
402 | \enum QSharedMemory::AccessMode |
403 | |
404 | \value ReadOnly The shared memory segment is read-only. Writing to |
405 | the shared memory segment is not allowed. An attempt to write to a |
406 | shared memory segment created with ReadOnly causes the program to |
407 | abort. |
408 | |
409 | \value ReadWrite Reading and writing the shared memory segment are |
410 | both allowed. |
411 | */ |
412 | |
413 | /*! |
414 | Attempts to attach the process to the shared memory segment |
415 | identified by the key that was passed to the constructor or to a |
416 | call to setNativeKey(). The access \a mode is \l {QSharedMemory::} |
417 | {ReadWrite} by default. It can also be \l {QSharedMemory::} |
418 | {ReadOnly}. Returns \c true if the attach operation is successful. If |
419 | false is returned, call error() to determine which error occurred. |
420 | After attaching the shared memory segment, a pointer to the shared |
421 | memory can be obtained by calling data(). |
422 | |
423 | \sa isAttached(), detach(), create() |
424 | */ |
425 | bool QSharedMemory::attach(AccessMode mode) |
426 | { |
427 | Q_D(QSharedMemory); |
428 | |
429 | if (isAttached() || !d->initKey(mode: {})) |
430 | return false; |
431 | #if QT_CONFIG(systemsemaphore) |
432 | QSharedMemoryLocker lock(this); |
433 | if (!d->nativeKey.isEmpty() && !d->tryLocker(locker: &lock, function: "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 | |
443 | /*! |
444 | Returns \c true if this process is attached to the shared memory |
445 | segment. |
446 | |
447 | \sa attach(), detach() |
448 | */ |
449 | bool QSharedMemory::isAttached() const |
450 | { |
451 | Q_D(const QSharedMemory); |
452 | return (nullptr != d->memory); |
453 | } |
454 | |
455 | /*! |
456 | Detaches the process from the shared memory segment. If this was the |
457 | last process attached to the shared memory segment, then the shared |
458 | memory segment is released by the system, i.e., the contents are |
459 | destroyed. The function returns \c true if it detaches the shared |
460 | memory segment. If it returns \c false, it usually means the segment |
461 | either isn't attached, or it is locked by another process. |
462 | |
463 | \sa attach(), isAttached() |
464 | */ |
465 | bool 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(locker: &lock, function: "QSharedMemory::detach"_L1 )) |
474 | return false; |
475 | #endif |
476 | |
477 | return d->detach(); |
478 | } |
479 | |
480 | /*! |
481 | Returns a pointer to the contents of the shared memory segment, if one is |
482 | attached. Otherwise it returns null. The value returned by this function will |
483 | not change until a \l {detach()}{detach} happens, so it is safe to store this |
484 | pointer. |
485 | |
486 | If the memory operations are not atomic, you may lock the shared memory with |
487 | lock() before reading from or writing, but remember to release the lock with |
488 | unlock() after you are done. |
489 | |
490 | \sa attach() |
491 | */ |
492 | void *QSharedMemory::data() |
493 | { |
494 | Q_D(QSharedMemory); |
495 | return d->memory; |
496 | } |
497 | |
498 | /*! |
499 | Returns a const pointer to the contents of the shared memory segment, if one |
500 | is attached. Otherwise it returns null. The value returned by this function |
501 | will not change until a \l {detach()}{detach} happens, so it is safe to store |
502 | this pointer. |
503 | |
504 | If the memory operations are not atomic, you may lock the shared memory with |
505 | lock() before reading from or writing, but remember to release the lock with |
506 | unlock() after you are done. |
507 | |
508 | \sa attach(), create() |
509 | */ |
510 | const void *QSharedMemory::constData() const |
511 | { |
512 | Q_D(const QSharedMemory); |
513 | return d->memory; |
514 | } |
515 | |
516 | /*! |
517 | \overload data() |
518 | */ |
519 | const void *QSharedMemory::data() const |
520 | { |
521 | Q_D(const QSharedMemory); |
522 | return d->memory; |
523 | } |
524 | |
525 | #if QT_CONFIG(systemsemaphore) |
526 | /*! |
527 | This is a semaphore that locks the shared memory segment for access |
528 | by this process and returns \c true. If another process has locked the |
529 | segment, this function blocks until the lock is released. Then it |
530 | acquires the lock and returns \c true. If this function returns \c false, |
531 | it means that you have ignored a false return from create() or attach(), |
532 | that you have set the key with setNativeKey() or that |
533 | QSystemSemaphore::acquire() failed due to an unknown system error. |
534 | |
535 | \sa unlock(), data(), QSystemSemaphore::acquire() |
536 | */ |
537 | bool QSharedMemory::lock() |
538 | { |
539 | Q_D(QSharedMemory); |
540 | if (d->lockedByMe) { |
541 | qWarning(msg: "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(s: "%1: unable to lock" ).arg(a: function); |
550 | d->error = QSharedMemory::LockError; |
551 | return false; |
552 | } |
553 | |
554 | /*! |
555 | Releases the lock on the shared memory segment and returns \c true, if |
556 | the lock is currently held by this process. If the segment is not |
557 | locked, or if the lock is held by another process, nothing happens |
558 | and false is returned. |
559 | |
560 | \sa lock() |
561 | */ |
562 | bool 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(s: "%1: unable to unlock" ).arg(a: function); |
572 | d->error = QSharedMemory::LockError; |
573 | return false; |
574 | } |
575 | #endif // QT_CONFIG(systemsemaphore) |
576 | |
577 | /*! |
578 | \enum QSharedMemory::SharedMemoryError |
579 | |
580 | \value NoError No error occurred. |
581 | |
582 | \value PermissionDenied The operation failed because the caller |
583 | didn't have the required permissions. |
584 | |
585 | \value InvalidSize A create operation failed because the requested |
586 | size was invalid. |
587 | |
588 | \value KeyError The operation failed because of an invalid key. |
589 | |
590 | \value AlreadyExists A create() operation failed because a shared |
591 | memory segment with the specified key already existed. |
592 | |
593 | \value NotFound An attach() failed because a shared memory segment |
594 | with the specified key could not be found. |
595 | |
596 | \value LockError The attempt to lock() the shared memory segment |
597 | failed because create() or attach() failed and returned false, or |
598 | because a system error occurred in QSystemSemaphore::acquire(). |
599 | |
600 | \value OutOfResources A create() operation failed because there was |
601 | not enough memory available to fill the request. |
602 | |
603 | \value UnknownError Something else happened and it was bad. |
604 | */ |
605 | |
606 | /*! |
607 | Returns a value indicating whether an error occurred, and, if so, |
608 | which error it was. |
609 | |
610 | \sa errorString() |
611 | */ |
612 | QSharedMemory::SharedMemoryError QSharedMemory::error() const |
613 | { |
614 | Q_D(const QSharedMemory); |
615 | return d->error; |
616 | } |
617 | |
618 | /*! |
619 | Returns a text description of the last error that occurred. If |
620 | error() returns an \l {QSharedMemory::SharedMemoryError} {error |
621 | value}, call this function to get a text string that describes the |
622 | error. |
623 | |
624 | \sa error() |
625 | */ |
626 | QString QSharedMemory::errorString() const |
627 | { |
628 | Q_D(const QSharedMemory); |
629 | return d->errorString; |
630 | } |
631 | |
632 | void 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(s: "%1: permission denied" ).arg(a: function); |
638 | error = QSharedMemory::PermissionDenied; |
639 | break; |
640 | case EEXIST: |
641 | errorString = QSharedMemory::tr(s: "%1: already exists" ).arg(a: function); |
642 | error = QSharedMemory::AlreadyExists; |
643 | break; |
644 | case ENOENT: |
645 | errorString = QSharedMemory::tr(s: "%1: doesn't exist" ).arg(a: function); |
646 | error = QSharedMemory::NotFound; |
647 | break; |
648 | case EMFILE: |
649 | case ENOMEM: |
650 | case ENOSPC: |
651 | errorString = QSharedMemory::tr(s: "%1: out of resources" ).arg(a: function); |
652 | error = QSharedMemory::OutOfResources; |
653 | break; |
654 | default: |
655 | errorString = QSharedMemory::tr(s: "%1: unknown error: %2" ) |
656 | .arg(args&: function, args: 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 | |
664 | bool QSharedMemory::isKeyTypeSupported(QNativeIpcKey::Type type) |
665 | { |
666 | if (!isIpcSupported(ipcType: IpcType::SharedMemory, type)) |
667 | return false; |
668 | using Variant = decltype(QSharedMemoryPrivate::backend); |
669 | return Variant::staticVisit(keyType: type, lambda: [](auto ptr) { |
670 | using Impl = std::decay_t<decltype(*ptr)>; |
671 | return Impl::runtimeSupportCheck(); |
672 | }); |
673 | } |
674 | |
675 | QNativeIpcKey QSharedMemory::platformSafeKey(const QString &key, QNativeIpcKey::Type type) |
676 | { |
677 | return QtIpcCommon::platformSafeKey(key, ipcType: IpcType::SharedMemory, type); |
678 | } |
679 | |
680 | QNativeIpcKey QSharedMemory::legacyNativeKey(const QString &key, QNativeIpcKey::Type type) |
681 | { |
682 | return QtIpcCommon::legacyPlatformSafeKey(key, ipcType: IpcType::SharedMemory, type); |
683 | } |
684 | |
685 | #endif // QT_CONFIG(sharedmemory) |
686 | |
687 | QT_END_NAMESPACE |
688 | |
689 | #include "moc_qsharedmemory.cpp" |
690 | |