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