Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
ipc.qdoc
Go to the documentation of this file.
1// Copyright (C) 2022 Intel Corporation.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
3
4/*!
5 \page ipc.html
6 \title Inter-Process Communication
7 \ingroup groups
8 \ingroup frameworks-technologies
9 \keyword ipc
10
11 \brief An overview of Qt's inter-process communication functionality
12
13 Qt supports many ways of communicating with other processes running in the
14 same system or in different systems. There are basically three types of
15 inter-process communication mechanisms:
16
17 \list 1
18 \li Synchronization primitives
19 \li Exchanging of arbitrary byte-level data
20 \li Passing structured messages
21 \endlist
22
23 \section1 Synchronization primitives
24
25 Qt only provides one class for explicit inter-process synchronization:
26 \l{QSystemSemaphore}. A QSystemSemaphore is like a \l{QSemaphore} that is
27 accessible by multiple processes in the same system. It is globally
28 identified by a "key", which in Qt is represented by the \l{QNativeIpcKey}
29 class. Additionally, depending on the OS, Qt may support multiple different
30 backends for sharing memory; see the \l{Native IPC Keys} documentation for
31 more information and limitations.
32
33 It is possible to use regular thread-synchronization primitives such as
34 mutexes, wait conditions, and read-write locks, located in memory that is
35 shared between processes. Qt does not provide any class to support this,
36 but applications can use low-level operations on certain operating systems.
37
38 Other Qt classes may be used to provide higher-level locking, like
39 \l{QLockFile}, or by acquiring a unique, system-wide resource. Such
40 techniques include \l{QTcpServer}{TCP} or \l{QUdpSocket}{UDP} ports or
41 well-known names in \l{QDBusConnection::registerService}{D-Bus}.
42
43 \section1 Byte-level data sharing
44
45 Using byte-level data, applications can implement any communication
46 protocol they may choose. Sharing of byte data can be stream-oriented
47 (serialized) or can allow random access (a similar condition to
48 QFileDevice::isSequential()).
49
50 For serial communication, Qt provides a number of different classes and
51 even full modules:
52 \list
53 \li Pipes and FIFOs: \l QFile
54 \li Child processes: \l QProcess
55 \li Sockets: \l QTcpSocket, \l QUdpSocket (in \l{Qt Network})
56 \li HTTP(S): \l QNetworkAccessManager (in \l{Qt Network}) and
57 \l QHttpServer (in \l{Qt HTTP Server})
58 \li CoAP(S): \l QCoapClient (in \l{Qt CoAP})
59 \endlist
60
61 For random-access data sharing within the same system, Qt provides
62 \l{QSharedMemory}. See the \l{Shared Memory} documentation for detailed
63 information.
64
65 \section1 Structured message passing
66
67 Qt also provides a number of techniques to exchange structured messages
68 with other processes. Applications can build on top of the byte-level
69 solutions above, such as by using \l QJsonDocument or \l QXmlStreamReader /
70 \l QXmlStreamWriter over HTTP to perform JSONRPC or XMLRPC, respectively,
71 or \l QCborValue with QtCoAP.
72
73 Dedicated Qt modules for structured messages and remote procedure-calling
74 include:
75 \list
76 \li \l{Qt D-Bus}
77 \li \l{Qt Remote Objects}
78 \li \l{Qt WebSockets}
79 \endlist
80*/
81
82/*!
83 \page shared-memory.html
84 \title Shared Memory
85 \keyword ipc
86 \keyword shared memory
87
88 \brief Overview of the techniques for sharing memory between processes
89
90 Qt provides two techniques to share memory with other processes in the same
91 system: \l{QSharedMemory} and memory-mapped files using \l{QFile}. Memory
92 that is shared with other processes is often referred to as a "segment",
93 and although it may have been implemented as specific segments on
94 processors with segmented memory models in the past, this is not the case
95 in any modern operating system. Shared memory segments are simply regions
96 of memory that the operating system will ensure are available to all
97 processes participating.
98
99 \note The address at which the segment is located in memory will almost
100 always be different for each process that is participating in the sharing.
101 Therefore, applications must take care to share only position-independent
102 data, such as primitive C++ types or arrays of such types.
103
104 \section1 Sharing memory using QSharedMemory
105
106 QSharedMemory provides a simple API to create a shared memory segment of a
107 given size or attach to one that was created by another process.
108 Additionally, it provides a pair of methods to \l{QSharedMemory::}{lock}
109 and \l{QSharedMemory::}{unlock} the whole segment, using an internal
110 \l{QSystemSemaphore}.
111
112 Shared memory segments and system semaphores are globally identified in the
113 system through a "key", which in Qt is represented by the \l{QNativeIpcKey}
114 class. Additionally, depending on the OS, Qt may support multiple different
115 backends for sharing memory; see the \l{Native IPC Keys} documentation for
116 more information and limitations.
117
118 QSharedMemory is designed to share memory only within the same privilege
119 level (that is, not with untrusted other processes, such as those started
120 by other users). For backends that support it, QSharedMemory will create
121 segments such that only processes with the same privilege level can attach.
122
123 \section1 Sharing memory via memory-mapped files
124
125 Most files can be mapped to memory using QFile::map() and, if the
126 \l{QFileDevice::MapPrivateOption}{MapPrivateOption} option is not specified,
127 any writes to the mapped segment will be observed by all other processes
128 that have mapped the same file. Exceptions to files that can be mapped to
129 memory include remote files found in network shares or those located in
130 certain filesystems. Even if the operating system does allow mapping remote
131 files to memory, I/O operations on the file will likely be cached and
132 delayed, thus making true memory sharing impossible.
133
134 This solution has the major advantages of being independent of any backend
135 API and of being simpler to interoperate with from non-Qt applications.
136 Since \l{QTemporaryFile} is a \l{QFile}, applications can use that class to
137 achieve clean-up semantics and to create unique shared memory segments too.
138
139 To achieve locking of the shared memory segment, applications will need to
140 deploy their own mechanisms. One way may be to use \l QLockFile. Another
141 and less costly solution is to use QBasicAtomicInteger or \c{std::atomic} in
142 a pre-determined offset in the segment itself. Higher-level locking
143 primitives may be available on some operating systems; for example, on
144 Linux, applications can set the "pshared" flag in the mutex attribute
145 passed to \c{pthread_mutex_create()} to indicate that the mutex resides in
146 a shared memory segment.
147
148 Be aware that the operating system will likely attempt to commit to
149 permanent storage any writes made to the shared memory. This may be desired
150 or it may be a performance penalty if the file itself was meant to be
151 temporary. In that case, applications should locate a RAM-backed
152 filesystem, such as \c{tmpfs} on Linux (see
153 QStorageInfo::fileSystemType()), or pass a flag to the native file-opening
154 function to inform the OS to avoid committing the contents to storage.
155
156 It is possible to use file-backed shared memory to communicate with
157 untrusted processes, in which case the application should exercise great
158 care. The files may be truncated/shrunk and cause applications accessing
159 memory beyond the file's size to crash.
160
161 \section2 Linux hints on memory-mapped files
162
163 On modern Linux systems, while the \c{/tmp} directory is often a \c{tmpfs}
164 mount point, that is not a requirement. However, the \c{/dev/shm} directory
165 is required to be a \c{tmpfs} and exists for the very purpose of sharing
166 memory. Do note that it is world-readable and writable (like \c{/tmp} and
167 \c{/var/tmp}), so applications must be careful of the contents revealed
168 there. Another alternative is to use the XDG Runtime Directory (see
169 QStandardPaths::writableLocation() and \l{QStandardPaths::RuntimeLocation}),
170 which on Linux systems using systemd is a user-specific \c{tmpfs}.
171
172 An even more secure solution is to create a "memfd" using \c{memfd_create(2)}
173 and use interprocess communication to pass the file descriptor, like
174 \l{QDBusUnixFileDescriptor} or by letting the child process of a \l{QProcess}
175 inherit it. "memfds" can also be sealed against being shrunk, so they are
176 safe to be used when communicating with processes with a different privilege
177 level.
178
179 \section2 FreeBSD hints on memory-mapped files
180
181 FreeBSD also has \c{memfd_create(2)} and can pass file descriptors to other
182 processes using the same techniques as Linux. It does not have temporary
183 filesystems mounted by default.
184
185 \section2 Windows hints on memory-mapped files
186
187 On Windows, the application can request the operating system avoid saving
188 the file's contents on permanent storage. This request is performed by
189 passing the \c{FILE_ATTRIBUTE_TEMPORARY} flag in the
190 \c{dwFlagsAndAttributes} parameter to the \c{CreateFile} Win32 function,
191 the \c{_O_SHORT_LIVED} flag to \c{_open()} low-level function, or by
192 including the modifier "T" to the
193 \c{fopen()} C runtime function.
194
195 There's also a flag to inform the operating system to delete the file when
196 the last handle to it is closed (\c{FILE_FLAG_DELETE_ON_CLOSE},
197 \c{_O_TEMPORARY}, and the "D" modifier), but do note that all processes
198 attempting to open the file must agree on using this flag or not using it. A
199 mismatch will likely cause a sharing violation and failure to open the file.
200*/
201
202/*!
203 \page native-ipc-keys.html
204 \title Native IPC Keys
205 \keyword ipc
206 \keyword shared memory
207 \keyword system semaphore
208
209 \brief An overview of keys for QSharedMemory and QSystemSemaphore
210
211 The \l QSharedMemory and \l QSystemSemaphore classes identify their
212 resource using a system-wide identifier known as a "key". The low-level key
213 value as well as the key type are encapsulated in Qt using the \l
214 QNativeIpcKey class. That class also provides the proper means of
215 exchanging the key with other processes, by way of
216 QNativeIpcKey::toString() and QNativeIpcKey::fromString().
217
218 Qt currently supports three distinct backends for those two classes, which
219 match the values available in the \l{QNativeIpcKey::Type} enumeration.
220 \list
221 \li POSIX Realtime extensions (IEEE 1003.1b, POSIX.1b)
222 \li X/Open System Interfaces (XSI) or System V (SVr4), though also now part of POSIX
223 \li Windows primitives
224 \endlist
225
226 As the name indicates, the Windows primitives are only available on the
227 Windows operating system, where they are the default backend. The other two
228 are usually both available on Unix operating systems. The following table
229 provides an overview of typical availability since Qt 6.6:
230
231 \table
232 \header \li Operating system \li POSIX \li System V \li Windows
233 \row \li Android \li \li \li
234 \row \li INTEGRITY \li \li \li
235 \row \li QNX \li Yes \li \li
236 \row \li \macos \li Yes \li Usually (1) \li
237 \row \li Other Apple OSes \li Yes \li \li
238 \row \li Other Unix systems \li Yes \li Yes \li
239 \row \li Windows \li Rarely (2) \li \li Yes
240 \endtable
241
242 \note 1 Sandboxed \macos applications, which include all applications
243 distributed via the Apple App Store, may not use System V objects.
244
245 \note 2 Some GCC-compatible C runtimes on Windows provide POSIX-compatible
246 shared memory support, but this is rare. It is always absent with the
247 Microsoft compiler.
248
249 To determine whether a given key type is supported, applications should
250 call QSharedMemory::isKeyTypeSupported() and
251 QSystemSemaphore::isKeyTypeSupported().
252
253 QNativeIpcKey also provides support for compatibility with Qt applications
254 prior to its introduction. The following sections detail the limitations of
255 the backends, the contents of the string keys themselves, and
256 compatibility.
257
258 \section1 Cross-platform safe key format
259
260 QNativeIpcKey::setNativeKey() and QNativeIpcKey::nativeKey() handle the
261 low-level native key, which may be used with the native APIs and shared
262 with other, non-Qt processes (see below for the API). This format is not
263 usually cross-platform, so both QSharedMemory and QSystemSemaphore provide
264 a function to translate a cross-platform identifier string to the native
265 key: QSharedMemory::platformSafeKey() and
266 QSystemSemaphore::platformSafeKey().
267
268 The length of the cross-platform key on most platforms is the same as that
269 of a file name, but is severely limited on Apple platforms to only 30
270 usable bytes (be mindful of UTF-8 encoding if using characters outside the
271 US-ASCII range). The format of the key is also similar to that of a file
272 path component, meaning it should not contain any characters not allowed in
273 file names, in particular those that separate path components (slash and
274 backslash), with the exception of sandboxed applications on Apple operating
275 systems. The following are good examples of cross-platform keys: "myapp",
276 "org.example.myapp", "org.example.myapp-12345".
277
278 \b{Apple sandbox limitations:} if the application is running inside of a
279 sandbox in an Apple operating system, the key must be in a very specific
280 format: \c {<application group identifier>/<custom identifier>}. Sandboxing
281 is implied for all applications distributed through the Apple App Store.
282 See Apple's documentation
283 \l{https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW24}
284 {here} and \l{https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_application-groups}
285 {here} for more information, including how to obtain the application's group identifier.
286
287 \section1 Native key format
288
289 This section details the format of the native keys of the supported
290 backends.
291
292 \section3 POSIX Realtime
293 Native keys resemble file names and may contain any character that file
294 names do, except for a slash. POSIX requires the first character in the key
295 name to be a slash and leaves undetermined whether any additional slashes
296 are permitted. On most operating systems, the key length is the same as a
297 file name, but it is limited to 32 characters on Apple operating systems
298 (this includes the first slash and the terminating null, so only 30 usable
299 characters are possible).
300
301 The following are good examples of native POSIX keys: "/myapp",
302 "/org.example.myapp", "/org.example.myapp-12345".
303
304 QSharedMemory::platformSafeKey() and QSystemSemaphore::platformSafeKey()
305 simply prepend the slash. On Apple operating systems, they also truncate
306 the result to the available size.
307
308 \section3 Windows
309 Windows key types are NT
310 \l{https://learn.microsoft.com/en-us/windows/win32/sync/object-namespaces}{kernel
311 object names} and may be up to \c{MAX_PATH} (260) characters in length.
312 They look like relative paths (that is, they don't start with a backslash
313 or a drive letter), but unlike file names on Windows, they are
314 case-sensitive.
315
316 The following are good examples of native Windows keys: "myapp",
317 "org.example.myapp", "org.example.myapp-12345".
318
319 QSharedMemory::platformSafeKey() and QSystemSemaphore::platformSafeKey()
320 insert a prefix to disambiguate shared memory and system semaphores,
321 respectively.
322
323 \section3 X/Open System Interfaces (XSI) / System V
324 System V keys take the form of the name of a file in the system, and thus
325 have the exact same limitations as file paths do. Both QSharedMemory and
326 QSystemSemaphore will create this file if it does not exist when creating
327 the object. If auto-removal is disabled, it may also be shared between
328 QSharedMemory and QSystemSemaphore without conflict and can be any extant
329 file (for example, it can be the process executable itself, see
330 QCoreApplication::applicationFilePath()). The path should be an absolute
331 one to avoid mistakes due to different current directories.
332
333 QSharedMemory::platformSafeKey() and QSystemSemaphore::platformSafeKey()
334 always return an absolute path. If the input was already absolute, they
335 will return their input unchanged. Otherwise, they will prepend a suitable
336 path where the application usually has permission to create files in.
337
338 \section1 Ownership
339
340 Shared memory and system semaphore objects need to be created before use,
341 which is accomplished with QSharedMemory::create() or by passing
342 QSystemSemaphore::Create to the constructor, respectively.
343
344 On Unix systems, the Qt classes that created the object will be responsible
345 for cleaning up the object in question. Therefore, if the application with
346 that C++ object exits uncleanly (a crash, qFatal(), etc.), the object may
347 be left behind. If that happens, applications may fail to create the
348 object again and should instead attach to an existing one. For example, for
349 QSharedMemory:
350
351 \code
352 if (!shm.create(4096) && shm.error() == QSharedMemory::AlreadyExists)
353 shm.attach();
354 \endcode
355
356 Re-attaching to a QSystemSemaphore is probably unwise, as the token counter
357 in it is probably in an unknown state and therefore may lead to deadlocks.
358
359 \section3 POSIX Realtime
360 POSIX Realtime object ownership is patterned after files, in the sense that
361 they exist independent of any process using them or not. Qt is unable to
362 determine if the object is still in use, so auto-removal will remove it
363 even then, which will make attaching to the same object impossible but
364 otherwise not affecting existing attachments.
365
366 Prior to Qt 6.6, Qt never cleaned up POSIX Realtime objects, except on QNX.
367
368 \section3 X/Open System Interfaces (XSI) / System V
369 There are two resources managed by the Qt classes: the file the key refers
370 to and the object itself. QSharedMemory manages the object cooperatively:
371 the last attachment is responsible for removing the object itself and then
372 removing the key file. QSystemSemaphore will remove the object if and only
373 if it was passed QSystemSemaphore::Create; additionally, if it created the
374 key file, it will remove that too.
375
376 Since Qt 6.6, it is possible to ask either class not to clean up.
377
378 \section3 Windows
379 The operating system owns the object and will clean up after the last
380 handle to the object is closed.
381
382 \section1 Interoperability with old Qt applications
383
384 The QNativeIpcKey class was introduced in Qt 6.6. Prior to this version,
385 QSharedMemory and QSystemSemaphore backends were determined at the time of
386 Qt's own build. For Windows systems, it was always the Windows backend. For
387 Unix systems, it defaulted to the System V backend if the configuration
388 script determined it was available. If it was not available, it fell back
389 to the POSIX one (since Qt 4.8). The POSIX backend could be explicitly
390 selected using the \c{-feature-ipc_posix} option to the Qt configure
391 script; if it was enabled, the \c{QT_POSIX_IPC} macro would be defined.
392
393 Qt 6.6 retains the configure script option but it no longer controls the
394 availability of the backends. Instead, it changes what
395 QNativeIpcKey::legacyDefaultTypeForOs() will return. Applications that need
396 to retain compatibility must use this key type exclusively to guarantee
397 interoperability.
398
399 The API in both QSharedMemory and QSystemSemaphore had the concept of a
400 cross-platform key, which is now deprecated in favor of using
401 QSharedMemory::legacyNativeKey() and QSystemSemaphore::legacyNativeKey().
402 Those two functions produce the same native key as the deprecated functions
403 did in prior versions. If the old code was for example:
404
405 \code
406 QSharedMemory shm("org.example.myapplication");
407 QSystemSemaphore sem("org.example.myapplication");
408 \endcode
409
410 It can be updated to be:
411 \code
412 QSharedMemory shm(QSharedMemory::legacyNativeKey("org.example.myapplication"));
413 QSystemSemaphore sem(QSystemSemaphore::legacyNativeKey("org.example.myapplication"));
414 \endcode
415
416 If the two applications exchanged native keys, there is no need to update
417 code such as:
418
419 \code
420 QSharedMemory shm;
421 shm.setNativeKey(key);
422 \endcode
423
424 Though if the older application did accept a native key, the new one may
425 opt to use \c{platformSafeKey()} with a second argument of
426 QNativeIpcKey::legacyDefaultTypeForOs().
427
428 \section3 X/Open System Interfaces (XSI) / System V
429 Never use existing files for QSharedMemory keys, as the old Qt application
430 may attempt to remove it. Instead, let QSharedMemory create it.
431
432 \section1 Interoperability with non-Qt applications
433
434 Interoperability with non-Qt applications is possible, with some limitations:
435 \list
436 \li Creation of shared memory segments must not race
437 \li QSharedMemory support for locking the segment is unavailable
438 \endlist
439
440 Communication with non-Qt applications must always be through the native
441 key.
442
443 QSharedMemory always maps the entire segment to memory. The non-Qt
444 application may choose to only map a subset of it to memory, with no ill
445 effects.
446
447 \section3 POSIX Realtime
448 POSIX shared memory can be opened using
449 \l{https://pubs.opengroup.org/onlinepubs/9699919799/functions/shm_open.html}{shm_open()}
450 and POSIX system semaphores can be opened using
451 \l{https://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_open.html}{sem_open()}.
452
453 Both of those functions take a \c name parameter that is the result of
454 QNativeIpcKey::nativeKey(), encoded for file names using
455 QFile::encodeName() / QFile::decodeName().
456
457 \section3 Windows
458 Windows shared memory objects can be opened using
459 \l{https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-createfilemappingw}{CreateFileMappingW}
460 and Windows system semaphore objects can be opened using
461 \l{https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createsemaphorew}{CreateSemaphoreW}.
462 Despite the name of both functions starting with "Create", they are able
463 to attach to existing objects.
464
465 The \c lpName parameter to those functions is the result of
466 QNativeIpcKey::nativeKey(), without transformation.
467
468 If the foreign application uses the non-Unicode version of those functions
469 (ending in "A"), the name can be converted to and from 8-bit using QString.
470
471 \section3 X/Open System Interfaces (XSI) / System V
472 System V shared memory can be obtained using
473 \l{https://pubs.opengroup.org/onlinepubs/9699919799/functions/shmget.html}{shmget()}
474 and System V system semaphores can be obtained using
475 \l{https://pubs.opengroup.org/onlinepubs/9699919799/functions/semget.html}{semget()}.
476
477 The \c{key} parameter to either of those functions is the result of the
478 \l{https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftok.html}{ftok()}
479 function when passed the file name obtained from QNativeIpcKey::nativeKey()
480 with an \c id of 81 or 0x51 (the ASCII capital letter 'Q').
481
482 System V semaphore objects may contain multiple semaphores, but
483 QSystemSemaphore only uses the first one (number 0 for \c{sem_num}).
484
485 Both QSharedMemory and QSystemSemaphore default to removing the object
486 using the \c{IPC_RMID} operation to \c{shmctl()} and \c{semctl()}
487 respectively if they are the last attachment.
488*/