source: trunk/src/corelib/kernel/qsharedmemory.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 16.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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
52QT_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 */
64QString
65QSharedMemoryPrivate::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#ifdef Q_OS_SYMBIAN
77 return result.left(KMaxKernelName);
78#endif
79
80 QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex();
81 result.append(QLatin1String(hex));
82#ifdef Q_OS_WIN
83 return result;
84#else
85 return QDir::tempPath() + QLatin1Char('/') + result;
86#endif
87}
88#endif // QT_NO_SHAREDMEMORY && QT_NO_SHAREDMEMORY
89
90#ifndef QT_NO_SHAREDMEMORY
91
92/*!
93 \class QSharedMemory
94 \since 4.4
95
96 \brief The QSharedMemory class provides access to a shared memory segment.
97
98 QSharedMemory provides access to a shared memory segment by multiple
99 threads and processes. It also provides a way for a single thread or
100 process to lock the memory for exclusive access.
101
102 When using this class, be aware of the following platform
103 differences:
104
105 \list
106
107 \o Windows: QSharedMemory does not "own" the shared memory segment.
108 When all threads or processes that have an instance of QSharedMemory
109 attached to a particular shared memory segment have either destroyed
110 their instance of QSharedMemory or exited, the Windows kernel
111 releases the shared memory segment automatically.
112
113 \o Unix: QSharedMemory "owns" the shared memory segment. When the
114 last thread or process that has an instance of QSharedMemory
115 attached to a particular shared memory segment detaches from the
116 segment by destroying its instance of QSharedMemory, the Unix kernel
117 release the shared memory segment. But if that last thread or
118 process crashes without running the QSharedMemory destructor, the
119 shared memory segment survives the crash.
120
121 \o HP-UX: Only one attach to a shared memory segment is allowed per
122 process. This means that QSharedMemory should not be used across
123 multiple threads in the same process in HP-UX.
124
125 \o Symbian: QSharedMemory does not "own" the shared memory segment.
126 When all threads or processes that have an instance of QSharedMemory
127 attached to a particular shared memory segment have either destroyed
128 their instance of QSharedMemory or exited, the Symbian kernel
129 releases the shared memory segment automatically.
130 Also, access to a shared memory segment cannot be limited to read-only
131 in Symbian.
132
133 \endlist
134
135 Remember to lock the shared memory with lock() before reading from
136 or writing to the shared memory, and remember to release the lock
137 with unlock() after you are done.
138
139 Unlike QtSharedMemory, QSharedMemory automatically destroys the
140 shared memory segment when the last instance of QSharedMemory is
141 detached from the segment, and no references to the segment
142 remain. Do not mix using QtSharedMemory and QSharedMemory. Port
143 everything to QSharedMemory.
144
145 \warning QSharedMemory changes the key in a Qt-specific way.
146 It is therefore currently not possible to use the shared memory of
147 non-Qt applications with QSharedMemory.
148 */
149
150/*!
151 \overload QSharedMemory()
152
153 Constructs a shared memory object with the given \a parent. The
154 shared memory object's key is not set by the constructor, so the
155 shared memory object does not have an underlying shared memory
156 segment attached. The key must be set with setKey() before create()
157 or attach() can be used.
158
159 \sa setKey()
160 */
161QSharedMemory::QSharedMemory(QObject *parent)
162 : QObject(*new QSharedMemoryPrivate, parent)
163{
164}
165
166/*!
167 Constructs a shared memory object with the given \a parent and with
168 its key set to \a key. Because its key is set, its create() and
169 attach() functions can be called.
170
171 \sa setKey(), create(), attach()
172 */
173QSharedMemory::QSharedMemory(const QString &key, QObject *parent)
174 : QObject(*new QSharedMemoryPrivate, parent)
175{
176 setKey(key);
177}
178
179/*!
180 The destructor clears the key, which forces the shared memory object
181 to \l {detach()} {detach} from its underlying shared memory
182 segment. If this shared memory object is the last one connected to
183 the shared memory segment, the detach() operation destroys the
184 shared memory segment.
185
186 \sa detach() isAttached()
187 */
188QSharedMemory::~QSharedMemory()
189{
190 setKey(QString());
191}
192
193/*!
194 Sets a new \a key for this shared memory object. If \a key and the
195 current key are the same, the function returns without doing
196 anything. If the shared memory object is attached to an underlying
197 shared memory segment, it will \l {detach()} {detach} from it before
198 setting the new key. This function does not do an attach().
199
200 \sa key() isAttached()
201 */
202void QSharedMemory::setKey(const QString &key)
203{
204 Q_D(QSharedMemory);
205 if (key == d->key)
206 return;
207
208 if (isAttached())
209 detach();
210 d->cleanHandle();
211 d->key = key;
212}
213
214bool QSharedMemoryPrivate::initKey()
215{
216 if (!cleanHandle())
217 return false;
218#ifndef QT_NO_SYSTEMSEMAPHORE
219 systemSemaphore.setKey(QString(), 1);
220 systemSemaphore.setKey(key, 1);
221 if (systemSemaphore.error() != QSystemSemaphore::NoError) {
222 QString function = QLatin1String("QSharedMemoryPrivate::initKey");
223 errorString = QSharedMemory::tr("%1: unable to set key on lock").arg(function);
224 switch(systemSemaphore.error()) {
225 case QSystemSemaphore::PermissionDenied:
226 error = QSharedMemory::PermissionDenied;
227 break;
228 case QSystemSemaphore::KeyError:
229 error = QSharedMemory::KeyError;
230 break;
231 case QSystemSemaphore::AlreadyExists:
232 error = QSharedMemory::AlreadyExists;
233 break;
234 case QSystemSemaphore::NotFound:
235 error = QSharedMemory::NotFound;
236 break;
237 case QSystemSemaphore::OutOfResources:
238 error = QSharedMemory::OutOfResources;
239 break;
240 case QSystemSemaphore::UnknownError:
241 default:
242 error = QSharedMemory::UnknownError;
243 break;
244 }
245 return false;
246 }
247#endif
248 errorString = QString();
249 error = QSharedMemory::NoError;
250 return true;
251}
252
253/*!
254 Returns the key assigned to this shared memory. The key is the
255 identifier used by the operating system to identify the shared
256 memory segment. When QSharedMemory is used for interprocess
257 communication, the key is how each process attaches to the shared
258 memory segment through which the IPC occurs.
259
260 \sa setKey()
261 */
262QString QSharedMemory::key() const
263{
264 Q_D(const QSharedMemory);
265 return d->key;
266}
267
268/*!
269 Creates a shared memory segment of \a size bytes with the key passed
270 to the constructor or set with setKey(), attaches to the new shared
271 memory segment with the given access \a mode, and returns \tt true.
272 If a shared memory segment identified by the key already exists, the
273 attach operation is not performed, and \tt false is returned. When
274 the return value is \tt false, call error() to determine which error
275 occurred.
276
277 \sa error()
278 */
279bool QSharedMemory::create(int size, AccessMode mode)
280{
281 Q_D(QSharedMemory);
282
283 if (!d->initKey())
284 return false;
285
286#ifndef QT_NO_SYSTEMSEMAPHORE
287#ifndef Q_OS_WIN
288 // Take ownership and force set initialValue because the semaphore
289 // might have already existed from a previous crash.
290 d->systemSemaphore.setKey(d->key, 1, QSystemSemaphore::Create);
291#endif
292#endif
293
294 QString function = QLatin1String("QSharedMemory::create");
295#ifndef QT_NO_SYSTEMSEMAPHORE
296 QSharedMemoryLocker lock(this);
297 if (!d->tryLocker(&lock, function))
298 return false;
299#endif
300
301 if (size <= 0) {
302 d->error = QSharedMemory::InvalidSize;
303 d->errorString =
304 QSharedMemory::tr("%1: create size is less then 0").arg(function);
305 return false;
306 }
307
308 if (!d->create(size))
309 return false;
310
311 return d->attach(mode);
312}
313
314/*!
315 Returns the size of the attached shared memory segment. If no shared
316 memory segment is attached, 0 is returned.
317
318 \sa create() attach()
319 */
320int QSharedMemory::size() const
321{
322 Q_D(const QSharedMemory);
323 return d->size;
324}
325
326/*!
327 \enum QSharedMemory::AccessMode
328
329 \value ReadOnly The shared memory segment is read-only. Writing to
330 the shared memory segment is not allowed. An attempt to write to a
331 shared memory segment created with ReadOnly causes the program to
332 abort.
333
334 \value ReadWrite Reading and writing the shared memory segment are
335 both allowed.
336*/
337
338/*!
339 Attempts to attach the process to the shared memory segment
340 identified by the key that was passed to the constructor or to a
341 call to setKey(). The access \a mode is \l {QSharedMemory::}
342 {ReadWrite} by default. It can also be \l {QSharedMemory::}
343 {ReadOnly}. Returns true if the attach operation is successful. If
344 false is returned, call error() to determine which error occurred.
345 After attaching the shared memory segment, a pointer to the shared
346 memory can be obtained by calling data().
347
348 \sa isAttached(), detach(), create()
349 */
350bool QSharedMemory::attach(AccessMode mode)
351{
352 Q_D(QSharedMemory);
353
354 if (isAttached() || !d->initKey())
355 return false;
356#ifndef QT_NO_SYSTEMSEMAPHORE
357 QSharedMemoryLocker lock(this);
358 if (!d->tryLocker(&lock, QLatin1String("QSharedMemory::attach")))
359 return false;
360#endif
361
362 if (isAttached() || !d->handle())
363 return false;
364
365 return d->attach(mode);
366}
367
368/*!
369 Returns true if this process is attached to the shared memory
370 segment.
371
372 \sa attach(), detach()
373 */
374bool QSharedMemory::isAttached() const
375{
376 Q_D(const QSharedMemory);
377 return (0 != d->memory);
378}
379
380/*!
381 Detaches the process from the shared memory segment. If this was the
382 last process attached to the shared memory segment, then the shared
383 memory segment is released by the system, i.e., the contents are
384 destroyed. The function returns true if it detaches the shared
385 memory segment. If it returns false, it usually means the segment
386 either isn't attached, or it is locked by another process.
387
388 \sa attach(), isAttached()
389 */
390bool QSharedMemory::detach()
391{
392 Q_D(QSharedMemory);
393 if (!isAttached())
394 return false;
395
396#ifndef QT_NO_SYSTEMSEMAPHORE
397 QSharedMemoryLocker lock(this);
398 if (!d->tryLocker(&lock, QLatin1String("QSharedMemory::detach")))
399 return false;
400#endif
401
402 if (d->detach()) {
403 d->size = 0;
404 return true;
405 }
406 return false;
407}
408
409/*!
410 Returns a pointer to the contents of the shared memory segment, if
411 one is attached. Otherwise it returns null. Remember to lock the
412 shared memory with lock() before reading from or writing to the
413 shared memory, and remember to release the lock with unlock() after
414 you are done.
415
416 \sa attach()
417 */
418void *QSharedMemory::data()
419{
420 Q_D(QSharedMemory);
421 return d->memory;
422}
423
424/*!
425 Returns a const pointer to the contents of the shared memory
426 segment, if one is attached. Otherwise it returns null. Remember to
427 lock the shared memory with lock() before reading from or writing to
428 the shared memory, and remember to release the lock with unlock()
429 after you are done.
430
431 \sa attach() create()
432 */
433const void* QSharedMemory::constData() const
434{
435 Q_D(const QSharedMemory);
436 return d->memory;
437}
438
439/*!
440 \overload data()
441 */
442const void *QSharedMemory::data() const
443{
444 Q_D(const QSharedMemory);
445 return d->memory;
446}
447
448#ifndef QT_NO_SYSTEMSEMAPHORE
449/*!
450 This is a semaphore that locks the shared memory segment for access
451 by this process and returns true. If another process has locked the
452 segment, this function blocks until the lock is released. Then it
453 acquires the lock and returns true. If this function returns false,
454 it means either that you have ignored a false return from create()
455 or attach(), or that QSystemSemaphore::acquire() failed due to an
456 unknown system error.
457
458 \sa unlock(), data(), QSystemSemaphore::acquire()
459 */
460bool QSharedMemory::lock()
461{
462 Q_D(QSharedMemory);
463 if (d->lockedByMe) {
464 qWarning("QSharedMemory::lock: already locked");
465 return true;
466 }
467 if (d->systemSemaphore.acquire()) {
468 d->lockedByMe = true;
469 return true;
470 }
471 QString function = QLatin1String("QSharedMemory::lock");
472 d->errorString = QSharedMemory::tr("%1: unable to lock").arg(function);
473 d->error = QSharedMemory::LockError;
474 return false;
475}
476
477/*!
478 Releases the lock on the shared memory segment and returns true, if
479 the lock is currently held by this process. If the segment is not
480 locked, or if the lock is held by another process, nothing happens
481 and false is returned.
482
483 \sa lock()
484 */
485bool QSharedMemory::unlock()
486{
487 Q_D(QSharedMemory);
488 if (!d->lockedByMe)
489 return false;
490 d->lockedByMe = false;
491 if (d->systemSemaphore.release())
492 return true;
493 QString function = QLatin1String("QSharedMemory::unlock");
494 d->errorString = QSharedMemory::tr("%1: unable to unlock").arg(function);
495 d->error = QSharedMemory::LockError;
496 return false;
497}
498#endif // QT_NO_SYSTEMSEMAPHORE
499
500/*!
501 \enum QSharedMemory::SharedMemoryError
502
503 \value NoError No error occurred.
504
505 \value PermissionDenied The operation failed because the caller
506 didn't have the required permissions.
507
508 \value InvalidSize A create operation failed because the requested
509 size was invalid.
510
511 \value KeyError The operation failed because of an invalid key.
512
513 \value AlreadyExists A create() operation failed because a shared
514 memory segment with the specified key already existed.
515
516 \value NotFound An attach() failed because a shared memory segment
517 with the specified key could not be found.
518
519 \value LockError The attempt to lock() the shared memory segment
520 failed because create() or attach() failed and returned false, or
521 because a system error occurred in QSystemSemaphore::acquire().
522
523 \value OutOfResources A create() operation failed because there was
524 not enough memory available to fill the request.
525
526 \value UnknownError Something else happened and it was bad.
527*/
528
529/*!
530 Returns a value indicating whether an error occurred, and, if so,
531 which error it was.
532
533 \sa errorString()
534 */
535QSharedMemory::SharedMemoryError QSharedMemory::error() const
536{
537 Q_D(const QSharedMemory);
538 return d->error;
539}
540
541/*!
542 Returns a text description of the last error that occurred. If
543 error() returns an \l {QSharedMemory::SharedMemoryError} {error
544 value}, call this function to get a text string that describes the
545 error.
546
547 \sa error()
548 */
549QString QSharedMemory::errorString() const
550{
551 Q_D(const QSharedMemory);
552 return d->errorString;
553}
554
555#endif // QT_NO_SHAREDMEMORY
556
557QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.