1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qsharedmemory.h"
41#include "qsharedmemory_p.h"
42#include "qsystemsemaphore.h"
43#include <qdir.h>
44#include <qcryptographichash.h>
45#include <qdebug.h>
46#ifdef Q_OS_WIN
47# include <qt_windows.h>
48#endif
49
50QT_BEGIN_NAMESPACE
51
52#if !(defined(QT_NO_SHAREDMEMORY) && defined(QT_NO_SYSTEMSEMAPHORE))
53/*!
54 \internal
55
56 Generate a string from the key which can be any unicode string into
57 the subset that the win/unix kernel allows.
58
59 On Unix this will be a file name
60 */
61QString
62QSharedMemoryPrivate::makePlatformSafeKey(const QString &key,
63 const QString &prefix)
64{
65 if (key.isEmpty())
66 return QString();
67
68 QString result = prefix;
69
70 for (QChar ch : key) {
71 if ((ch >= QLatin1Char('a') && ch <= QLatin1Char('z')) ||
72 (ch >= QLatin1Char('A') && ch <= QLatin1Char('Z')))
73 result += ch;
74 }
75
76 QByteArray hex = QCryptographicHash::hash(data: key.toUtf8(), method: QCryptographicHash::Sha1).toHex();
77 result.append(s: QLatin1String(hex));
78#ifdef Q_OS_WIN
79 return result;
80#elif defined(QT_POSIX_IPC)
81 return QLatin1Char('/') + result;
82#else
83 return QDir::tempPath() + QLatin1Char('/') + result;
84#endif
85}
86#endif // QT_NO_SHAREDMEMORY && QT_NO_SHAREDMEMORY
87
88#ifndef QT_NO_SHAREDMEMORY
89
90/*!
91 \class QSharedMemory
92 \inmodule QtCore
93 \since 4.4
94
95 \brief The QSharedMemory class provides access to a shared memory segment.
96
97 QSharedMemory provides access to a shared memory segment by multiple
98 threads and processes. It also provides a way for a single thread or
99 process to lock the memory for exclusive access.
100
101 When using this class, be aware of the following platform
102 differences:
103
104 \list
105
106 \li Windows: QSharedMemory does not "own" the shared memory segment.
107 When all threads or processes that have an instance of QSharedMemory
108 attached to a particular shared memory segment have either destroyed
109 their instance of QSharedMemory or exited, the Windows kernel
110 releases the shared memory segment automatically.
111
112 \li Unix: QSharedMemory "owns" the shared memory segment. When the
113 last thread or process that has an instance of QSharedMemory
114 attached to a particular shared memory segment detaches from the
115 segment by destroying its instance of QSharedMemory, the Unix kernel
116 release the shared memory segment. But if that last thread or
117 process crashes without running the QSharedMemory destructor, the
118 shared memory segment survives the crash.
119
120 \li HP-UX: Only one attach to a shared memory segment is allowed per
121 process. This means that QSharedMemory should not be used across
122 multiple threads in the same process in HP-UX.
123
124 \endlist
125
126 Remember to lock the shared memory with lock() before reading from
127 or writing to the shared memory, and remember to release the lock
128 with unlock() after you are done.
129
130 QSharedMemory automatically destroys the shared memory segment when
131 the last instance of QSharedMemory is detached from the segment, and
132 no references to the segment remain.
133
134 \warning QSharedMemory changes the key in a Qt-specific way, unless otherwise
135 specified. Interoperation with non-Qt applications is achieved by first creating
136 a default shared memory with QSharedMemory() and then setting a native key with
137 setNativeKey(). When using native keys, shared memory is not protected against
138 multiple accesses on it (for example, unable to lock()) and a user-defined mechanism
139 should be used to achieve such protection.
140 */
141
142/*!
143 \overload QSharedMemory()
144
145 Constructs a shared memory object with the given \a parent. The
146 shared memory object's key is not set by the constructor, so the
147 shared memory object does not have an underlying shared memory
148 segment attached. The key must be set with setKey() or setNativeKey()
149 before create() or attach() can be used.
150
151 \sa setKey()
152 */
153
154#ifndef QT_NO_QOBJECT
155QSharedMemory::QSharedMemory(QObject *parent)
156 : QObject(*new QSharedMemoryPrivate, parent)
157{
158}
159#else
160QSharedMemory::QSharedMemory()
161 : d_ptr(new QSharedMemoryPrivate)
162{
163}
164#endif
165/*!
166 Constructs a shared memory object with the given \a parent and with
167 its key set to \a key. Because its key is set, its create() and
168 attach() functions can be called.
169
170 \sa setKey(), create(), attach()
171 */
172#ifndef QT_NO_QOBJECT
173QSharedMemory::QSharedMemory(const QString &key, QObject *parent)
174 : QObject(*new QSharedMemoryPrivate, parent)
175{
176 setKey(key);
177}
178#else
179QSharedMemory::QSharedMemory(const QString &key)
180 : d_ptr(new QSharedMemoryPrivate)
181{
182 setKey(key);
183}
184#endif
185
186/*!
187 The destructor clears the key, which forces the shared memory object
188 to \l {detach()} {detach} from its underlying shared memory
189 segment. If this shared memory object is the last one connected to
190 the shared memory segment, the detach() operation destroys the
191 shared memory segment.
192
193 \sa detach(), isAttached()
194 */
195QSharedMemory::~QSharedMemory()
196{
197 setKey(QString());
198}
199
200/*!
201 Sets the platform independent \a key for this shared memory object. If \a key
202 is the same as the current key, the function returns without doing anything.
203
204 You can call key() to retrieve the platform independent key. Internally,
205 QSharedMemory converts this key into a platform specific key. If you instead
206 call nativeKey(), you will get the platform specific, converted key.
207
208 If the shared memory object is attached to an underlying shared memory
209 segment, it will \l {detach()} {detach} from it before setting the new key.
210 This function does not do an attach().
211
212 \sa key(), nativeKey(), isAttached()
213*/
214void QSharedMemory::setKey(const QString &key)
215{
216 Q_D(QSharedMemory);
217 if (key == d->key && d->makePlatformSafeKey(key) == d->nativeKey)
218 return;
219
220 if (isAttached())
221 detach();
222 d->cleanHandle();
223 d->key = key;
224 d->nativeKey = d->makePlatformSafeKey(key);
225}
226
227/*!
228 \since 4.8
229
230 Sets the native, platform specific, \a key for this shared memory object. If
231 \a key is the same as the current native key, the function returns without
232 doing anything. If all you want is to assign a key to a segment, you should
233 call setKey() instead.
234
235 You can call nativeKey() to retrieve the native key. If a native key has been
236 assigned, calling key() will return a null string.
237
238 If the shared memory object is attached to an underlying shared memory
239 segment, it will \l {detach()} {detach} from it before setting the new key.
240 This function does not do an attach().
241
242 The application will not be portable if you set a native key.
243
244 \sa nativeKey(), key(), isAttached()
245*/
246void QSharedMemory::setNativeKey(const QString &key)
247{
248 Q_D(QSharedMemory);
249 if (key == d->nativeKey && d->key.isNull())
250 return;
251
252 if (isAttached())
253 detach();
254 d->cleanHandle();
255 d->key = QString();
256 d->nativeKey = key;
257}
258
259bool QSharedMemoryPrivate::initKey()
260{
261 if (!cleanHandle())
262 return false;
263#ifndef QT_NO_SYSTEMSEMAPHORE
264 systemSemaphore.setKey(key: QString(), initialValue: 1);
265 systemSemaphore.setKey(key, initialValue: 1);
266 if (systemSemaphore.error() != QSystemSemaphore::NoError) {
267 QString function = QLatin1String("QSharedMemoryPrivate::initKey");
268 errorString = QSharedMemory::tr(s: "%1: unable to set key on lock").arg(a: function);
269 switch(systemSemaphore.error()) {
270 case QSystemSemaphore::PermissionDenied:
271 error = QSharedMemory::PermissionDenied;
272 break;
273 case QSystemSemaphore::KeyError:
274 error = QSharedMemory::KeyError;
275 break;
276 case QSystemSemaphore::AlreadyExists:
277 error = QSharedMemory::AlreadyExists;
278 break;
279 case QSystemSemaphore::NotFound:
280 error = QSharedMemory::NotFound;
281 break;
282 case QSystemSemaphore::OutOfResources:
283 error = QSharedMemory::OutOfResources;
284 break;
285 case QSystemSemaphore::UnknownError:
286 default:
287 error = QSharedMemory::UnknownError;
288 break;
289 }
290 return false;
291 }
292#endif
293 errorString = QString();
294 error = QSharedMemory::NoError;
295 return true;
296}
297
298/*!
299 Returns the key assigned with setKey() to this shared memory, or a null key
300 if no key has been assigned, or if the segment is using a nativeKey(). The
301 key is the identifier used by Qt applications to identify the shared memory
302 segment.
303
304 You can find the native, platform specific, key used by the operating system
305 by calling nativeKey().
306
307 \sa setKey(), setNativeKey()
308 */
309QString QSharedMemory::key() const
310{
311 Q_D(const QSharedMemory);
312 return d->key;
313}
314
315/*!
316 \since 4.8
317
318 Returns the native, platform specific, key for this shared memory object. The
319 native key is the identifier used by the operating system to identify the
320 shared memory segment.
321
322 You can use the native key to access shared memory segments that have not
323 been created by Qt, or to grant shared memory access to non-Qt applications.
324
325 \sa setKey(), setNativeKey()
326*/
327QString QSharedMemory::nativeKey() const
328{
329 Q_D(const QSharedMemory);
330 return d->nativeKey;
331}
332
333/*!
334 Creates a shared memory segment of \a size bytes with the key passed to the
335 constructor, set with setKey() or set with setNativeKey(), then attaches to
336 the new shared memory segment with the given access \a mode and returns
337 \tt true. If a shared memory segment identified by the key already exists,
338 the attach operation is not performed and \tt false is returned. When the
339 return value is \tt false, call error() to determine which error occurred.
340
341 \sa error()
342 */
343bool QSharedMemory::create(int size, AccessMode mode)
344{
345 Q_D(QSharedMemory);
346
347 if (!d->initKey())
348 return false;
349
350#ifndef QT_NO_SYSTEMSEMAPHORE
351#ifndef Q_OS_WIN
352 // Take ownership and force set initialValue because the semaphore
353 // might have already existed from a previous crash.
354 d->systemSemaphore.setKey(key: d->key, initialValue: 1, mode: QSystemSemaphore::Create);
355#endif
356#endif
357
358 QString function = QLatin1String("QSharedMemory::create");
359#ifndef QT_NO_SYSTEMSEMAPHORE
360 QSharedMemoryLocker lock(this);
361 if (!d->key.isNull() && !d->tryLocker(locker: &lock, function))
362 return false;
363#endif
364
365 if (size <= 0) {
366 d->error = QSharedMemory::InvalidSize;
367 d->errorString =
368 QSharedMemory::tr(s: "%1: create size is less then 0").arg(a: function);
369 return false;
370 }
371
372 if (!d->create(size))
373 return false;
374
375 return d->attach(mode);
376}
377
378/*!
379 Returns the size of the attached shared memory segment. If no shared
380 memory segment is attached, 0 is returned.
381
382 \note The size of the segment may be larger than the requested size that was
383 passed to create().
384
385 \sa create(), attach()
386 */
387int QSharedMemory::size() const
388{
389 Q_D(const QSharedMemory);
390 return d->size;
391}
392
393/*!
394 \enum QSharedMemory::AccessMode
395
396 \value ReadOnly The shared memory segment is read-only. Writing to
397 the shared memory segment is not allowed. An attempt to write to a
398 shared memory segment created with ReadOnly causes the program to
399 abort.
400
401 \value ReadWrite Reading and writing the shared memory segment are
402 both allowed.
403*/
404
405/*!
406 Attempts to attach the process to the shared memory segment
407 identified by the key that was passed to the constructor or to a
408 call to setKey() or setNativeKey(). The access \a mode is \l {QSharedMemory::}
409 {ReadWrite} by default. It can also be \l {QSharedMemory::}
410 {ReadOnly}. Returns \c true if the attach operation is successful. If
411 false is returned, call error() to determine which error occurred.
412 After attaching the shared memory segment, a pointer to the shared
413 memory can be obtained by calling data().
414
415 \sa isAttached(), detach(), create()
416 */
417bool QSharedMemory::attach(AccessMode mode)
418{
419 Q_D(QSharedMemory);
420
421 if (isAttached() || !d->initKey())
422 return false;
423#ifndef QT_NO_SYSTEMSEMAPHORE
424 QSharedMemoryLocker lock(this);
425 if (!d->key.isNull() && !d->tryLocker(locker: &lock, function: QLatin1String("QSharedMemory::attach")))
426 return false;
427#endif
428
429 if (isAttached() || !d->handle())
430 return false;
431
432 return d->attach(mode);
433}
434
435/*!
436 Returns \c true if this process is attached to the shared memory
437 segment.
438
439 \sa attach(), detach()
440 */
441bool QSharedMemory::isAttached() const
442{
443 Q_D(const QSharedMemory);
444 return (nullptr != d->memory);
445}
446
447/*!
448 Detaches the process from the shared memory segment. If this was the
449 last process attached to the shared memory segment, then the shared
450 memory segment is released by the system, i.e., the contents are
451 destroyed. The function returns \c true if it detaches the shared
452 memory segment. If it returns \c false, it usually means the segment
453 either isn't attached, or it is locked by another process.
454
455 \sa attach(), isAttached()
456 */
457bool QSharedMemory::detach()
458{
459 Q_D(QSharedMemory);
460 if (!isAttached())
461 return false;
462
463#ifndef QT_NO_SYSTEMSEMAPHORE
464 QSharedMemoryLocker lock(this);
465 if (!d->key.isNull() && !d->tryLocker(locker: &lock, function: QLatin1String("QSharedMemory::detach")))
466 return false;
467#endif
468
469 return d->detach();
470}
471
472/*!
473 Returns a pointer to the contents of the shared memory segment, if
474 one is attached. Otherwise it returns null. Remember to lock the
475 shared memory with lock() before reading from or writing to the
476 shared memory, and remember to release the lock with unlock() after
477 you are done.
478
479 \sa attach()
480 */
481void *QSharedMemory::data()
482{
483 Q_D(QSharedMemory);
484 return d->memory;
485}
486
487/*!
488 Returns a const pointer to the contents of the shared memory
489 segment, if one is attached. Otherwise it returns null. Remember to
490 lock the shared memory with lock() before reading from or writing to
491 the shared memory, and remember to release the lock with unlock()
492 after you are done.
493
494 \sa attach(), create()
495 */
496const void* QSharedMemory::constData() const
497{
498 Q_D(const QSharedMemory);
499 return d->memory;
500}
501
502/*!
503 \overload data()
504 */
505const void *QSharedMemory::data() const
506{
507 Q_D(const QSharedMemory);
508 return d->memory;
509}
510
511#ifndef QT_NO_SYSTEMSEMAPHORE
512/*!
513 This is a semaphore that locks the shared memory segment for access
514 by this process and returns \c true. If another process has locked the
515 segment, this function blocks until the lock is released. Then it
516 acquires the lock and returns \c true. If this function returns \c false,
517 it means that you have ignored a false return from create() or attach(),
518 that you have set the key with setNativeKey() or that
519 QSystemSemaphore::acquire() failed due to an unknown system error.
520
521 \sa unlock(), data(), QSystemSemaphore::acquire()
522 */
523bool QSharedMemory::lock()
524{
525 Q_D(QSharedMemory);
526 if (d->lockedByMe) {
527 qWarning(msg: "QSharedMemory::lock: already locked");
528 return true;
529 }
530 if (d->systemSemaphore.acquire()) {
531 d->lockedByMe = true;
532 return true;
533 }
534 QString function = QLatin1String("QSharedMemory::lock");
535 d->errorString = QSharedMemory::tr(s: "%1: unable to lock").arg(a: function);
536 d->error = QSharedMemory::LockError;
537 return false;
538}
539
540/*!
541 Releases the lock on the shared memory segment and returns \c true, if
542 the lock is currently held by this process. If the segment is not
543 locked, or if the lock is held by another process, nothing happens
544 and false is returned.
545
546 \sa lock()
547 */
548bool QSharedMemory::unlock()
549{
550 Q_D(QSharedMemory);
551 if (!d->lockedByMe)
552 return false;
553 d->lockedByMe = false;
554 if (d->systemSemaphore.release())
555 return true;
556 QString function = QLatin1String("QSharedMemory::unlock");
557 d->errorString = QSharedMemory::tr(s: "%1: unable to unlock").arg(a: function);
558 d->error = QSharedMemory::LockError;
559 return false;
560}
561#endif // QT_NO_SYSTEMSEMAPHORE
562
563/*!
564 \enum QSharedMemory::SharedMemoryError
565
566 \value NoError No error occurred.
567
568 \value PermissionDenied The operation failed because the caller
569 didn't have the required permissions.
570
571 \value InvalidSize A create operation failed because the requested
572 size was invalid.
573
574 \value KeyError The operation failed because of an invalid key.
575
576 \value AlreadyExists A create() operation failed because a shared
577 memory segment with the specified key already existed.
578
579 \value NotFound An attach() failed because a shared memory segment
580 with the specified key could not be found.
581
582 \value LockError The attempt to lock() the shared memory segment
583 failed because create() or attach() failed and returned false, or
584 because a system error occurred in QSystemSemaphore::acquire().
585
586 \value OutOfResources A create() operation failed because there was
587 not enough memory available to fill the request.
588
589 \value UnknownError Something else happened and it was bad.
590*/
591
592/*!
593 Returns a value indicating whether an error occurred, and, if so,
594 which error it was.
595
596 \sa errorString()
597 */
598QSharedMemory::SharedMemoryError QSharedMemory::error() const
599{
600 Q_D(const QSharedMemory);
601 return d->error;
602}
603
604/*!
605 Returns a text description of the last error that occurred. If
606 error() returns an \l {QSharedMemory::SharedMemoryError} {error
607 value}, call this function to get a text string that describes the
608 error.
609
610 \sa error()
611 */
612QString QSharedMemory::errorString() const
613{
614 Q_D(const QSharedMemory);
615 return d->errorString;
616}
617
618#endif // QT_NO_SHAREDMEMORY
619
620QT_END_NAMESPACE
621
622#ifndef QT_NO_QOBJECT
623#include "moc_qsharedmemory.cpp"
624#endif
625

source code of qtbase/src/corelib/kernel/qsharedmemory.cpp