1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://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 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qsharedmemory.h"
43 #include "qsharedmemory_p.h"
44 #include "qsystemsemaphore.h"
45 #include <qdir.h>
46 #include <qcryptographichash.h>
47 #ifdef Q_OS_SYMBIAN
48 #include <e32const.h>
49 #endif
50 #include <qdebug.h>
51
52 QT_BEGIN_NAMESPACE
53
54 #if !(defined(QT_NO_SHAREDMEMORY) && defined(QT_NO_SYSTEMSEMAPHORE))
55 /*!
56 \internal
57
58 Generate a string from the key which can be any unicode string into
59 the subset that the win/unix kernel allows.
60
61 On Unix this will be a file name
62 On Symbian key will be truncated to 80 characters
63 */
64 QString
makePlatformSafeKey(const QString & key,const QString & prefix)65 QSharedMemoryPrivate::makePlatformSafeKey(const QString &key,
66 const QString &prefix)
67 {
68 if (key.isEmpty())
69 return QString();
70
71 QString result = prefix;
72
73 QString part1 = key;
74 part1.replace(QRegExp(QLatin1String("[^A-Za-z]")), QString());
75 result.append(part1);
76
77 QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex();
78 result.append(QLatin1String(hex));
79 #ifdef Q_OS_WIN
80 return result;
81 #elif defined(Q_OS_SYMBIAN)
82 return result.left(KMaxKernelName);
83 #elif defined(QT_POSIX_IPC)
84 return QLatin1Char('/') + result;
85 #else
86 return QDir::tempPath() + QLatin1Char('/') + result;
87 #endif
88 }
89 #endif // QT_NO_SHAREDMEMORY && QT_NO_SHAREDMEMORY
90
91 #ifndef QT_NO_SHAREDMEMORY
92
93 /*!
94 \class QSharedMemory
95 \since 4.4
96
97 \brief The QSharedMemory class provides access to a shared memory segment.
98
99 QSharedMemory provides access to a shared memory segment by multiple
100 threads and processes. It also provides a way for a single thread or
101 process to lock the memory for exclusive access.
102
103 When using this class, be aware of the following platform
104 differences:
105
106 \list
107
108 \o Windows: QSharedMemory does not "own" the shared memory segment.
109 When all threads or processes that have an instance of QSharedMemory
110 attached to a particular shared memory segment have either destroyed
111 their instance of QSharedMemory or exited, the Windows kernel
112 releases the shared memory segment automatically.
113
114 \o Unix: QSharedMemory "owns" the shared memory segment. When the
115 last thread or process that has an instance of QSharedMemory
116 attached to a particular shared memory segment detaches from the
117 segment by destroying its instance of QSharedMemory, the Unix kernel
118 release the shared memory segment. But if that last thread or
119 process crashes without running the QSharedMemory destructor, the
120 shared memory segment survives the crash.
121
122 \o QNX: Due to possible race conditions in the POSIX IPC implementation, create()
123 should be called prior to any attach() calls (even across multiple threads).
124
125 \o HP-UX: Only one attach to a shared memory segment is allowed per
126 process. This means that QSharedMemory should not be used across
127 multiple threads in the same process in HP-UX.
128
129 \o Symbian: QSharedMemory does not "own" the shared memory segment.
130 When all threads or processes that have an instance of QSharedMemory
131 attached to a particular shared memory segment have either destroyed
132 their instance of QSharedMemory or exited, the Symbian kernel
133 releases the shared memory segment automatically.
134 Also, access to a shared memory segment cannot be limited to read-only
135 in Symbian.
136
137 \endlist
138
139 Remember to lock the shared memory with lock() before reading from
140 or writing to the shared memory, and remember to release the lock
141 with unlock() after you are done.
142
143 Unlike QtSharedMemory, QSharedMemory automatically destroys the
144 shared memory segment when the last instance of QSharedMemory is
145 detached from the segment, and no references to the segment
146 remain. Do not mix using QtSharedMemory and QSharedMemory. Port
147 everything to QSharedMemory.
148
149 \warning QSharedMemory changes the key in a Qt-specific way, unless otherwise
150 specified. Interoperation with non-Qt applications is achieved by first creating
151 a default shared memory with QSharedMemory() and then setting a native key with
152 setNativeKey(). When using native keys, shared memory is not protected against
153 multiple accesses on it (e.g. unable to lock()) and a user-defined mechanism
154 should be used to achieve a such protection.
155 */
156
157 /*!
158 \overload QSharedMemory()
159
160 Constructs a shared memory object with the given \a parent. The
161 shared memory object's key is not set by the constructor, so the
162 shared memory object does not have an underlying shared memory
163 segment attached. The key must be set with setKey() or setNativeKey()
164 before create() or attach() can be used.
165
166 \sa setKey()
167 */
QSharedMemory(QObject * parent)168 QSharedMemory::QSharedMemory(QObject *parent)
169 : QObject(*new QSharedMemoryPrivate, parent)
170 {
171 }
172
173 /*!
174 Constructs a shared memory object with the given \a parent and with
175 its key set to \a key. Because its key is set, its create() and
176 attach() functions can be called.
177
178 \sa setKey(), create(), attach()
179 */
QSharedMemory(const QString & key,QObject * parent)180 QSharedMemory::QSharedMemory(const QString &key, QObject *parent)
181 : QObject(*new QSharedMemoryPrivate, parent)
182 {
183 setKey(key);
184 }
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 */
~QSharedMemory()195 QSharedMemory::~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 */
setKey(const QString & key)214 void 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 */
setNativeKey(const QString & key)246 void 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.clear();
256 d->nativeKey = key;
257 }
258
initKey()259 bool QSharedMemoryPrivate::initKey()
260 {
261 cleanHandle();
262
263 #ifndef QT_NO_SYSTEMSEMAPHORE
264 systemSemaphore.setKey(QString(), 1);
265 systemSemaphore.setKey(key, 1);
266 if (systemSemaphore.error() != QSystemSemaphore::NoError) {
267 QString function = QLatin1String("QSharedMemoryPrivate::initKey");
268 errorString = QSharedMemory::tr("%1: unable to set key on lock").arg(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.clear();
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 */
key() const309 QString 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 */
nativeKey() const327 QString 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 */
create(int size,AccessMode mode)343 bool QSharedMemory::create(int size, AccessMode mode)
344 {
345 Q_D(QSharedMemory);
346
347 if (!d->initKey())
348 return false;
349
350 if (size <= 0) {
351 d->error = QSharedMemory::InvalidSize;
352 d->errorString = QSharedMemory::tr("%1: create size is less then 0").arg(QLatin1String("QSharedMemory::create"));
353 return false;
354 }
355
356 #ifndef QT_NO_SYSTEMSEMAPHORE
357 #ifndef Q_OS_WIN
358 // Take ownership and force set initialValue because the semaphore
359 // might have already existed from a previous crash.
360 d->systemSemaphore.setKey(d->key, 1, QSystemSemaphore::Create);
361 #endif
362
363 QSharedMemoryLocker lock(this);
364 if (!d->key.isNull() && !d->tryLocker(&lock, QLatin1String("QSharedMemory::create")))
365 return false;
366 #endif
367
368 if (!d->create(size))
369 return false;
370
371 return d->attach(mode);
372 }
373
374 /*!
375 Returns the size of the attached shared memory segment. If no shared
376 memory segment is attached, 0 is returned.
377
378 \sa create() attach()
379 */
size() const380 int QSharedMemory::size() const
381 {
382 Q_D(const QSharedMemory);
383 return d->size;
384 }
385
386 /*!
387 \enum QSharedMemory::AccessMode
388
389 \value ReadOnly The shared memory segment is read-only. Writing to
390 the shared memory segment is not allowed. An attempt to write to a
391 shared memory segment created with ReadOnly causes the program to
392 abort.
393
394 \value ReadWrite Reading and writing the shared memory segment are
395 both allowed.
396 */
397
398 /*!
399 Attempts to attach the process to the shared memory segment
400 identified by the key that was passed to the constructor or to a
401 call to setKey() or setNativeKey(). The access \a mode is \l {QSharedMemory::}
402 {ReadWrite} by default. It can also be \l {QSharedMemory::}
403 {ReadOnly}. Returns true if the attach operation is successful. If
404 false is returned, call error() to determine which error occurred.
405 After attaching the shared memory segment, a pointer to the shared
406 memory can be obtained by calling data().
407
408 \sa isAttached(), detach(), create()
409 */
attach(AccessMode mode)410 bool QSharedMemory::attach(AccessMode mode)
411 {
412 Q_D(QSharedMemory);
413
414 if (isAttached() || !d->initKey())
415 return false;
416 #ifndef QT_NO_SYSTEMSEMAPHORE
417 QSharedMemoryLocker lock(this);
418 if (!d->key.isNull() && !d->tryLocker(&lock, QLatin1String("QSharedMemory::attach")))
419 return false;
420 #endif
421
422 if (isAttached() || !d->handle())
423 return false;
424
425 return d->attach(mode);
426 }
427
428 /*!
429 Returns true if this process is attached to the shared memory
430 segment.
431
432 \sa attach(), detach()
433 */
isAttached() const434 bool QSharedMemory::isAttached() const
435 {
436 Q_D(const QSharedMemory);
437 return (0 != d->memory);
438 }
439
440 /*!
441 Detaches the process from the shared memory segment. If this was the
442 last process attached to the shared memory segment, then the shared
443 memory segment is released by the system, i.e., the contents are
444 destroyed. The function returns true if it detaches the shared
445 memory segment. If it returns false, it usually means the segment
446 either isn't attached, or it is locked by another process.
447
448 \sa attach(), isAttached()
449 */
detach()450 bool QSharedMemory::detach()
451 {
452 Q_D(QSharedMemory);
453 if (!isAttached())
454 return false;
455
456 #ifndef QT_NO_SYSTEMSEMAPHORE
457 QSharedMemoryLocker lock(this);
458 if (!d->key.isNull() && !d->tryLocker(&lock, QLatin1String("QSharedMemory::detach")))
459 return false;
460 #endif
461
462 return d->detach();
463 }
464
465 /*!
466 Returns a pointer to the contents of the shared memory segment, if
467 one is attached. Otherwise it returns null. Remember to lock the
468 shared memory with lock() before reading from or writing to the
469 shared memory, and remember to release the lock with unlock() after
470 you are done.
471
472 \sa attach()
473 */
data()474 void *QSharedMemory::data()
475 {
476 Q_D(QSharedMemory);
477 return d->memory;
478 }
479
480 /*!
481 Returns a const pointer to the contents of the shared memory
482 segment, if one is attached. Otherwise it returns null. Remember to
483 lock the shared memory with lock() before reading from or writing to
484 the shared memory, and remember to release the lock with unlock()
485 after you are done.
486
487 \sa attach() create()
488 */
constData() const489 const void* QSharedMemory::constData() const
490 {
491 Q_D(const QSharedMemory);
492 return d->memory;
493 }
494
495 /*!
496 \overload data()
497 */
data() const498 const void *QSharedMemory::data() const
499 {
500 Q_D(const QSharedMemory);
501 return d->memory;
502 }
503
504 #ifndef QT_NO_SYSTEMSEMAPHORE
505 /*!
506 This is a semaphore that locks the shared memory segment for access
507 by this process and returns true. If another process has locked the
508 segment, this function blocks until the lock is released. Then it
509 acquires the lock and returns true. If this function returns false,
510 it means that you have ignored a false return from create() or attach(),
511 that you have set the key with setNativeKey() or that
512 QSystemSemaphore::acquire() failed due to an unknown system error.
513
514 \sa unlock(), data(), QSystemSemaphore::acquire()
515 */
lock()516 bool QSharedMemory::lock()
517 {
518 Q_D(QSharedMemory);
519 if (d->lockedByMe) {
520 qWarning("QSharedMemory::lock: already locked");
521 return true;
522 }
523 if (d->systemSemaphore.acquire()) {
524 d->lockedByMe = true;
525 return true;
526 }
527 QString function = QLatin1String("QSharedMemory::lock");
528 d->errorString = QSharedMemory::tr("%1: unable to lock").arg(function);
529 d->error = QSharedMemory::LockError;
530 return false;
531 }
532
533 /*!
534 Releases the lock on the shared memory segment and returns true, if
535 the lock is currently held by this process. If the segment is not
536 locked, or if the lock is held by another process, nothing happens
537 and false is returned.
538
539 \sa lock()
540 */
unlock()541 bool QSharedMemory::unlock()
542 {
543 Q_D(QSharedMemory);
544 if (!d->lockedByMe)
545 return false;
546 d->lockedByMe = false;
547 if (d->systemSemaphore.release())
548 return true;
549 QString function = QLatin1String("QSharedMemory::unlock");
550 d->errorString = QSharedMemory::tr("%1: unable to unlock").arg(function);
551 d->error = QSharedMemory::LockError;
552 return false;
553 }
554 #endif // QT_NO_SYSTEMSEMAPHORE
555
556 /*!
557 \enum QSharedMemory::SharedMemoryError
558
559 \value NoError No error occurred.
560
561 \value PermissionDenied The operation failed because the caller
562 didn't have the required permissions.
563
564 \value InvalidSize A create operation failed because the requested
565 size was invalid.
566
567 \value KeyError The operation failed because of an invalid key.
568
569 \value AlreadyExists A create() operation failed because a shared
570 memory segment with the specified key already existed.
571
572 \value NotFound An attach() failed because a shared memory segment
573 with the specified key could not be found.
574
575 \value LockError The attempt to lock() the shared memory segment
576 failed because create() or attach() failed and returned false, or
577 because a system error occurred in QSystemSemaphore::acquire().
578
579 \value OutOfResources A create() operation failed because there was
580 not enough memory available to fill the request.
581
582 \value UnknownError Something else happened and it was bad.
583 */
584
585 /*!
586 Returns a value indicating whether an error occurred, and, if so,
587 which error it was.
588
589 \sa errorString()
590 */
error() const591 QSharedMemory::SharedMemoryError QSharedMemory::error() const
592 {
593 Q_D(const QSharedMemory);
594 return d->error;
595 }
596
597 /*!
598 Returns a text description of the last error that occurred. If
599 error() returns an \l {QSharedMemory::SharedMemoryError} {error
600 value}, call this function to get a text string that describes the
601 error.
602
603 \sa error()
604 */
errorString() const605 QString QSharedMemory::errorString() const
606 {
607 Q_D(const QSharedMemory);
608 return d->errorString;
609 }
610
611 #endif // QT_NO_SHAREDMEMORY
612
613 QT_END_NAMESPACE
614