QSharedMemory/doc: update docs to be more modern
- We don't support HPUX any more, so no need to talk about it - Clarify that it's the QSharedMemory destructor that releases the resources on Unix systems - Explain the System V and POSIX backends and how to detect them - Add a note about Android not being supported. - Add a section about using QFile for shared memory Change-Id: I413ea647c2a5453b8307fffd17174c8083416529 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io> Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
47ab723d82
commit
909112fa52
@ -105,22 +105,34 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key,
|
||||
\li Unix: QSharedMemory "owns" the shared memory segment. When the
|
||||
last thread or process that has an instance of QSharedMemory
|
||||
attached to a particular shared memory segment detaches from the
|
||||
segment by destroying its instance of QSharedMemory, the Unix kernel
|
||||
release the shared memory segment. But if that last thread or
|
||||
segment by destroying its instance of QSharedMemory, the destructor
|
||||
releases the shared memory segment. But if that last thread or
|
||||
process crashes without running the QSharedMemory destructor, the
|
||||
shared memory segment survives the crash.
|
||||
|
||||
\li HP-UX: Only one attach to a shared memory segment is allowed per
|
||||
process. This means that QSharedMemory should not be used across
|
||||
multiple threads in the same process in HP-UX.
|
||||
\li Unix: QSharedMemory can be implemented by one of two different
|
||||
backends, selected at Qt build time: System V or POSIX. Qt defaults to
|
||||
using the System V API if it is available, and POSIX if not. These two
|
||||
backends do not interoperate, so two applications must ensure they use the
|
||||
same one, even if the native key (see setNativeKey()) is the same.
|
||||
|
||||
\li Apple platforms: Sandboxed applications (including apps
|
||||
shipped through the Apple App Store) require the use of POSIX
|
||||
shared memory (instead of System V shared memory), which adds
|
||||
a number of limitations, including:
|
||||
The POSIX backend can be explicitly selected using the
|
||||
\c{-feature-ipc_posix} option to the Qt configure script. If it is enabled,
|
||||
the \c{QT_POSIX_IPC} macro will be defined.
|
||||
|
||||
\li Sandboxed applications on Apple platforms (including apps
|
||||
shipped through the Apple App Store): This environment requires
|
||||
the use of POSIX shared memory (instead of System V shared memory).
|
||||
|
||||
Qt for iOS is built with support for POSIX shared memory out of the box.
|
||||
However, Qt for \macos builds (including those from the Qt installer) default
|
||||
to System V, making them unsuitable for App Store submission if QSharedMemory
|
||||
is needed. See above for instructions to explicitly select the POSIX backend
|
||||
when building Qt.
|
||||
|
||||
In addition, in a sandboxed environment, the following caveats apply:
|
||||
|
||||
\list
|
||||
|
||||
\li The key must be in the form \c {<application group identifier>/<custom identifier>},
|
||||
as documented \l {https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW24}
|
||||
{here} and \l {https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_application-groups}
|
||||
@ -143,11 +155,7 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key,
|
||||
|
||||
\endlist
|
||||
|
||||
Qt for iOS comes with support for POSIX shared memory out of the box.
|
||||
With Qt for \macos an additional configure flag must be added when
|
||||
building Qt to enable the feature. To enable the feature pass
|
||||
\c {-feature-ipc_posix} Note that the pre-built Qt libraries for
|
||||
\macos available through the Qt installer do not include this feature.
|
||||
\li Android: QSharedMemory is not supported.
|
||||
|
||||
\endlist
|
||||
|
||||
@ -162,9 +170,79 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key,
|
||||
\warning QSharedMemory changes the key in a Qt-specific way, unless otherwise
|
||||
specified. Interoperation with non-Qt applications is achieved by first creating
|
||||
a default shared memory with QSharedMemory() and then setting a native key with
|
||||
setNativeKey(). When using native keys, shared memory is not protected against
|
||||
multiple accesses on it (for example, unable to lock()) and a user-defined mechanism
|
||||
setNativeKey(), after ensuring they use the same low-level API (System V or
|
||||
POSIX). When using native keys, shared memory is not protected against multiple
|
||||
accesses on it (for example, unable to lock()) and a user-defined mechanism
|
||||
should be used to achieve such protection.
|
||||
|
||||
\section2 Alternative: Memory-Mapped File
|
||||
|
||||
Another way to share memory between processes is by opening the same file
|
||||
using \l QFile and mapping it into memory using QFile::map() (without
|
||||
specifying the QFileDevice::MapPrivateOption option). Any writes to the
|
||||
mapped segment will be observed by all other processes that have mapped the
|
||||
same file. This solution has the major advantages of being independent of the
|
||||
backend API and of being simpler to interoperate with from non-Qt
|
||||
applications. And since \l{QTemporaryFile} is a \l{QFile}, applications can
|
||||
use that class to achieve clean-up semantics and to create unique shared
|
||||
memory segments too.
|
||||
|
||||
To achieve locking of the shared memory segment, applications will need to
|
||||
deploy their own mechanisms. This can be achieved by using \l
|
||||
QBasicAtomicInteger or \c{std::atomic} in a pre-determined offset in the
|
||||
segment itself. Higher-level locking primitives may be available on some
|
||||
operating systems; for example, on Linux, \c{pthread_mutex_create()} can be
|
||||
passed a flag to indicate that the mutex resides in a shared memory segment.
|
||||
|
||||
A major drawback of using file-backed shared memory is that the operating
|
||||
system will attempt to write the data to permanent storage, possibly causing
|
||||
noticeable performance penalties. To avoid this, applications should locate a
|
||||
RAM-backed filesystem, such as \c{tmpfs} on Linux (see
|
||||
QStorageInfo::fileSystemType()), or pass a flag to the native file-opening
|
||||
function to inform the OS to avoid committing the contents to storage.
|
||||
|
||||
File-backed shared memory must be used with care if another process
|
||||
participating is untrusted. The files may be truncated/shrunk and cause
|
||||
applications accessing memory beyond the file's size to crash.
|
||||
|
||||
\section3 Linux hints on memory-mapped files
|
||||
|
||||
On modern Linux systems, while the \c{/tmp} directory is often a \c{tmpfs}
|
||||
mount point, that is not a requirement. However, the \c{/dev/shm} directory
|
||||
is required to be a \c{tmpfs} and exists for this very purpose. Do note that
|
||||
it is world-readable and writable (like \c{/tmp} and \c{/var/tmp}), so one
|
||||
must be careful of the contents revealed there. Another alternative is to use
|
||||
the XDG Runtime Directory (see QStandardPaths::writableLocation() and
|
||||
\l{QStandardPaths::RuntimeLocation}), which on Linux systems using systemd is
|
||||
a user-specific \c{tmpfs}.
|
||||
|
||||
An even more secure solution is to create a "memfd" using \c{memfd_create(2)}
|
||||
and use interprocess communication to pass the file descriptor, like
|
||||
\l{QDBusUnixFileDescriptor} or by letting the child process of a \l{QProcess}
|
||||
inherit it. "memfds" can also be sealed against being shrunk, so they are
|
||||
safe to be used when communicating with processes with a different privilege
|
||||
level.
|
||||
|
||||
\section3 FreeBSD hints on memory-mapped files
|
||||
|
||||
FreeBSD also has \c{memfd_create(2)} and can pass file descriptors to other
|
||||
processes using the same techniques as Linux. It does not have temporary
|
||||
filesystems mounted by default.
|
||||
|
||||
\section3 Windows hints on memory-mapped files
|
||||
|
||||
On Windows, the application can request the operating system avoid committing
|
||||
the file's contents to permanent storage. This request is performed by
|
||||
passing the \c{FILE_ATTRIBUTE_TEMPORARY} flag in the \c{dwFlagsAndAttributes}
|
||||
\c{CreateFile} Win32 function, the \c{_O_SHORT_LIVED} flag to \c{_open()}
|
||||
low-level function, or by including the modifier "T" to the \c{fopen()} C
|
||||
runtime function.
|
||||
|
||||
There's also a flag to inform the operating system to delete the file when
|
||||
the last handle to it is closed (\c{FILE_FLAG_DELETE_ON_CLOSE},
|
||||
\c{_O_TEMPORARY}, and the "D" modifier), but do note that all processes
|
||||
attempting to open the file must agree on using this flag or not using it. A
|
||||
mismatch will likely cause a sharing violation and failure to open the file.
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
Loading…
Reference in New Issue
Block a user