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 | |