| 1 |
/**************************************************************************** |
| 2 |
** |
| 3 |
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). |
| 4 |
** All rights reserved. |
| 5 |
** Contact: Nokia Corporation (qt-info@nokia.com) |
| 6 |
** |
| 7 |
** This file is part of the QtCore module of the Qt Toolkit. |
| 8 |
** |
| 9 |
** $QT_BEGIN_LICENSE:LGPL$ |
| 10 |
** GNU Lesser General Public License Usage |
| 11 |
** This file may be used under the terms of the GNU Lesser General Public |
| 12 |
** License version 2.1 as published by the Free Software Foundation and |
| 13 |
** appearing in the file LICENSE.LGPL included in the packaging of this |
| 14 |
** file. Please review the following information to ensure the GNU Lesser |
| 15 |
** General Public License version 2.1 requirements will be met: |
| 16 |
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| 17 |
** |
| 18 |
** In addition, as a special exception, Nokia gives you certain additional |
| 19 |
** rights. These rights are described in the Nokia Qt LGPL Exception |
| 20 |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| 21 |
** |
| 22 |
** GNU General Public License Usage |
| 23 |
** Alternatively, this file may be used under the terms of the GNU General |
| 24 |
** Public License version 3.0 as published by the Free Software Foundation |
| 25 |
** and appearing in the file LICENSE.GPL included in the packaging of this |
| 26 |
** file. Please review the following information to ensure the GNU General |
| 27 |
** Public License version 3.0 requirements will be met: |
| 28 |
** http://www.gnu.org/copyleft/gpl.html. |
| 29 |
** |
| 30 |
** Other Usage |
| 31 |
** Alternatively, this file may be used in accordance with the terms and |
| 32 |
** conditions contained in a signed written agreement between you and Nokia. |
| 33 |
** |
| 34 |
** |
| 35 |
** |
| 36 |
** |
| 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 |
| 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 |
*/ |
| 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 |
*/ |
| 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 |
*/ |
| 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 |
*/ |
| 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 |
*/ |
| 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 |
|
| 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 |
*/ |
| 309 |
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 |
*/ |
| 327 |
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 |
*/ |
| 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 |
*/ |
| 380 |
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 |
*/ |
| 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 |
*/ |
| 434 |
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 |
*/ |
| 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 |
*/ |
| 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 |
*/ |
| 489 |
const void* QSharedMemory::constData() const |
| 490 |
{ |
| 491 |
Q_D(const QSharedMemory); |
| 492 |
return d->memory; |
| 493 |
} |
| 494 |
|
| 495 |
/*! |
| 496 |
\overload data() |
| 497 |
*/ |
| 498 |
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 |
*/ |
| 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 |
*/ |
| 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 |
*/ |
| 591 |
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 |
*/ |
| 605 |
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 |