8f427b2 by axis at 2009-04-24 1
/****************************************************************************
2
**
89c08c0 by Jason McDonald at 2012-01-11 3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
04e3b30 by Jason McDonald at 2009-09-09 4
** All rights reserved.
858c70f by Jason McDonald at 2009-06-16 5
** Contact: Nokia Corporation (qt-info@nokia.com)
8f427b2 by axis at 2009-04-24 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
1eea52e by Jyri Tahtela at 2011-05-13 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.
8f427b2 by axis at 2009-04-24 17
**
04e3b30 by Jason McDonald at 2009-09-09 18
** In addition, as a special exception, Nokia gives you certain additional
1eea52e by Jyri Tahtela at 2011-05-13 19
** rights. These rights are described in the Nokia Qt LGPL Exception
04e3b30 by Jason McDonald at 2009-09-09 20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
8f427b2 by axis at 2009-04-24 21
**
1eea52e by Jyri Tahtela at 2011-05-13 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.
309db73 by Jason McDonald at 2009-08-31 33
**
34
**
35
**
36
**
8f427b2 by axis at 2009-04-24 37
**
38
** $QT_END_LICENSE$
39
**
40
****************************************************************************/
41
42
#include "qsystemsemaphore.h"
43
#include "qsystemsemaphore_p.h"
44
#include <qglobal.h>
45
46
QT_BEGIN_NAMESPACE
47
48
#ifndef QT_NO_SYSTEMSEMAPHORE
49
50
/*!
51
  \class QSystemSemaphore
52
  \since 4.4
53
54
  \brief The QSystemSemaphore class provides a general counting system semaphore.
55
56
  A semaphore is a generalization of a mutex. While a mutex can be
57
  locked only once, a semaphore can be acquired multiple times.
58
  Typically, a semaphore is used to protect a certain number of
59
  identical resources.
60
61
  Like its lighter counterpart QSemaphore, a QSystemSemaphore can be
62
  accessed from multiple \l {QThread} {threads}. Unlike QSemaphore, a
63
  QSystemSemaphore can also be accessed from multiple \l {QProcess}
64
  {processes}. This means QSystemSemaphore is a much heavier class, so
65
  if your application doesn't need to access your semaphores across
66
  multiple processes, you will probably want to use QSemaphore.
67
68
  Semaphores support two fundamental operations, acquire() and release():
69
70
  acquire() tries to acquire one resource. If there isn't a resource
71
  available, the call blocks until a resource becomes available. Then
72
  the resource is acquired and the call returns.
73
74
  release() releases one resource so it can be acquired by another
75
  process. The function can also be called with a parameter n > 1,
76
  which releases n resources.
77
78
  A system semaphore is created with a string key that other processes
79
  can use to use the same semaphore.
80
81
  Example: Create a system semaphore
82
  \snippet doc/src/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp 0
83
84
  A typical application of system semaphores is for controlling access
85
  to a circular buffer shared by a producer process and a consumer
86
  processes.
87
88
  \section1 Platform-Specific Behavior
89
90
  When using this class, be aware of the following platform
91
  differences:
92
93
  \bold{Windows:} QSystemSemaphore does not own its underlying system
94
  semaphore. Windows owns it. This means that when all instances of
95
  QSystemSemaphore for a particular key have been destroyed, either by
96
  having their destructors called, or because one or more processes
97
  crash, Windows removes the underlying system semaphore.
98
99
  \bold{Unix:}
100
101
  \list
102
  \o QSystemSemaphore owns the underlying system semaphore
103
  in Unix systems. This means that the last process having an instance of
104
  QSystemSemaphore for a particular key must remove the underlying
105
  system semaphore in its destructor. If the last process crashes
106
  without running the QSystemSemaphore destructor, Unix does not
107
  automatically remove the underlying system semaphore, and the
108
  semaphore survives the crash. A subsequent process that constructs a
109
  QSystemSemaphore with the same key will then be given the existing
110
  system semaphore. In that case, if the QSystemSemaphore constructor
111
  has specified its \l {QSystemSemaphore::AccessMode} {access mode} as
112
  \l {QSystemSemaphore::} {Open}, its initial resource count will not
113
  be reset to the one provided but remain set to the value it received
114
  in the crashed process. To protect against this, the first process
115
  to create a semaphore for a particular key (usually a server), must
116
  pass its \l {QSystemSemaphore::AccessMode} {access mode} as \l
117
  {QSystemSemaphore::} {Create}, which will force Unix to reset the
118
  resource count in the underlying system semaphore.
119
120
  \o When a process using QSystemSemaphore terminates for
121
  any reason, Unix automatically reverses the effect of all acquire
122
  operations that were not released. Thus if the process acquires a
123
  resource and then exits without releasing it, Unix will release that
124
  resource.
125
126
  \o Symbian: QSystemSemaphore behaves the same as Windows semaphores.
127
  In other words, the operating system owns the semaphore and ignores
128
  QSystemSemaphore::AccessMode.
129
130
  \endlist
131
132
  \sa QSharedMemory, QSemaphore
133
 */
134
135
/*!
136
  Requests a system semaphore for the specified \a key. The parameters
137
  \a initialValue and \a mode are used according to the following
138
  rules, which are system dependent.
139
140
  In Unix, if the \a mode is \l {QSystemSemaphore::} {Open} and the
141
  system already has a semaphore identified by \a key, that semaphore
142
  is used, and the semaphore's resource count is not changed, i.e., \a
143
  initialValue is ignored. But if the system does not already have a
144
  semaphore identified by \a key, it creates a new semaphore for that
145
  key and sets its resource count to \a initialValue.
146
147
  In Unix, if the \a mode is \l {QSystemSemaphore::} {Create} and the
148
  system already has a semaphore identified by \a key, that semaphore
149
  is used, and its resource count is set to \a initialValue. If the
150
  system does not already have a semaphore identified by \a key, it
151
  creates a new semaphore for that key and sets its resource count to
152
  \a initialValue.
153
d869e1a by Ritt Konstantin at 2011-06-21 154
  In QNX, if the \a mode is \l {QSystemSemaphore::} {Create} and the
155
  system already has a semaphore identified by \a key, that semaphore
156
  will be deleted and the new one will be created for that key with
157
  a resource count set to \a initialValue.
158
8f427b2 by axis at 2009-04-24 159
  In Windows and in Symbian, \a mode is ignored, and the system always tries to
160
  create a semaphore for the specified \a key. If the system does not
161
  already have a semaphore identified as \a key, it creates the
162
  semaphore and sets its resource count to \a initialValue. But if the
163
  system already has a semaphore identified as \a key it uses that
164
  semaphore and ignores \a initialValue.
165
166
  The \l {QSystemSemaphore::AccessMode} {mode} parameter is only used
167
  in Unix systems to handle the case where a semaphore survives a
168
  process crash. In that case, the next process to allocate a
169
  semaphore with the same \a key will get the semaphore that survived
170
  the crash, and unless \a mode is \l {QSystemSemaphore::} {Create},
171
  the resource count will not be reset to \a initialValue but will
172
  retain the initial value it had been given by the crashed process.
173
174
  \sa acquire(), key()
175
 */
176
QSystemSemaphore::QSystemSemaphore(const QString &key, int initialValue, AccessMode mode)
7604f80 by Robert Griebl at 2009-06-10 177
    : d(new QSystemSemaphorePrivate)
8f427b2 by axis at 2009-04-24 178
{
179
    setKey(key, initialValue, mode);
180
}
181
182
/*!
183
  The destructor destroys the QSystemSemaphore object, but the
184
  underlying system semaphore is not removed from the system unless
185
  this instance of QSystemSemaphore is the last one existing for that
186
  system semaphore.
187
188
  Two important side effects of the destructor depend on the system.
189
  In Windows, if acquire() has been called for this semaphore but not
190
  release(), release() will not be called by the destructor, nor will
191
  the resource be released when the process exits normally. This would
192
  be a program bug which could be the cause of a deadlock in another
193
  process trying to acquire the same resource. In Unix, acquired
194
  resources that are not released before the destructor is called are
195
  automatically released when the process exits.
196
*/
197
QSystemSemaphore::~QSystemSemaphore()
198
{
199
    d->cleanHandle();
200
}
201
202
/*!
203
  \enum QSystemSemaphore::AccessMode
204
205
  This enum is used by the constructor and setKey(). Its purpose is to
206
  enable handling the problem in Unix implementations of semaphores
207
  that survive a crash. In Unix, when a semaphore survives a crash, we
208
  need a way to force it to reset its resource count, when the system
209
  reuses the semaphore. In Windows and in Symbian, where semaphores can't survive a
210
  crash, this enum has no effect.
211
212
  \value Open If the semaphore already exists, its initial resource
213
  count is not reset. If the semaphore does not already exist, it is
214
  created and its initial resource count set.
215
216
  \value Create QSystemSemaphore takes ownership of the semaphore and
217
  sets its resource count to the requested value, regardless of
218
  whether the semaphore already exists by having survived a crash.
219
  This value should be passed to the constructor, when the first
220
  semaphore for a particular key is constructed and you know that if
221
  the semaphore already exists it could only be because of a crash. In
222
  Windows and in Symbian, where a semaphore can't survive a crash, Create and Open
223
  have the same behavior.
224
*/
225
226
/*!
227
  This function works the same as the constructor. It reconstructs
228
  this QSystemSemaphore object. If the new \a key is different from
229
  the old key, calling this function is like calling the destructor of
230
  the semaphore with the old key, then calling the constructor to
231
  create a new semaphore with the new \a key. The \a initialValue and
232
  \a mode parameters are as defined for the constructor.
233
234
  \sa QSystemSemaphore(), key()
235
 */
236
void QSystemSemaphore::setKey(const QString &key, int initialValue, AccessMode mode)
237
{
238
    if (key == d->key && mode == Open)
239
        return;
240
    d->error = NoError;
241
    d->errorString = QString();
d869e1a by Ritt Konstantin at 2011-06-21 242
#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) && !defined(QT_POSIX_IPC)
8f427b2 by axis at 2009-04-24 243
    // optimization to not destroy/create the file & semaphore
244
    if (key == d->key && mode == Create && d->createdSemaphore && d->createdFile) {
245
        d->initialValue = initialValue;
246
        d->unix_key = -1;
247
        d->handle(mode);
248
        return;
249
    }
250
#endif
251
    d->cleanHandle();
252
    d->key = key;
253
    d->initialValue = initialValue;
254
    // cache the file name so it doesn't have to be generated all the time.
255
    d->fileName = d->makeKeyFileName();
256
    d->handle(mode);
257
}
258
259
/*!
260
  Returns the key assigned to this system semaphore. The key is the
261
  name by which the semaphore can be accessed from other processes.
262
263
  \sa setKey()
264
 */
265
QString QSystemSemaphore::key() const
266
{
267
    return d->key;
268
}
269
270
/*!
271
  Acquires one of the resources guarded by this semaphore, if there is
272
  one available, and returns true. If all the resources guarded by this
273
  semaphore have already been acquired, the call blocks until one of
274
  them is released by another process or thread having a semaphore
275
  with the same key.
276
277
  If false is returned, a system error has occurred. Call error()
278
  to get a value of QSystemSemaphore::SystemSemaphoreError that
279
  indicates which error occurred.
280
281
  \sa release()
282
 */
283
bool QSystemSemaphore::acquire()
284
{
285
    return d->modifySemaphore(-1);
286
}
287
288
/*!
289
  Releases \a n resources guarded by the semaphore. Returns true
290
  unless there is a system error.
291
292
  Example: Create a system semaphore having five resources; acquire
293
  them all and then release them all.
294
295
  \snippet doc/src/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp 1
296
297
  This function can also "create" resources. For example, immediately
298
  following the sequence of statements above, suppose we add the
299
  statement:
300
301
  \snippet doc/src/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp 2
302
303
  Ten new resources are now guarded by the semaphore, in addition to
304
  the five that already existed. You would not normally use this
305
  function to create more resources.
306
307
  \sa acquire()
308
 */
309
bool QSystemSemaphore::release(int n)
310
{
311
    if (n == 0)
312
        return true;
313
    if (n < 0) {
314
        qWarning("QSystemSemaphore::release: n is negative.");
315
        return false;
316
    }
317
    return d->modifySemaphore(n);
318
}
319
320
/*!
321
  Returns a value indicating whether an error occurred, and, if so,
322
  which error it was.
323
324
  \sa errorString()
325
 */
326
QSystemSemaphore::SystemSemaphoreError QSystemSemaphore::error() const
327
{
328
    return d->error;
329
}
330
331
/*!
332
  \enum QSystemSemaphore::SystemSemaphoreError
333
334
  \value NoError No error occurred.
335
336
  \value PermissionDenied The operation failed because the caller
337
  didn't have the required permissions.
338
339
  \value KeyError The operation failed because of an invalid key.
340
341
  \value AlreadyExists The operation failed because a system
342
  semaphore with the specified key already existed.
343
344
  \value NotFound The operation failed because a system semaphore
345
  with the specified key could not be found.
346
347
  \value OutOfResources The operation failed because there was
348
  not enough memory available to fill the request.
349
350
  \value UnknownError Something else happened and it was bad.
351
*/
352
353
/*!
354
  Returns a text description of the last error that occurred. If
355
  error() returns an \l {QSystemSemaphore::SystemSemaphoreError} {error
356
  value}, call this function to get a text string that describes the
357
  error.
358
359
  \sa error()
360
 */
361
QString QSystemSemaphore::errorString() const
362
{
363
    return d->errorString;
364
}
365
366
#endif // QT_NO_SYSTEMSEMAPHORE
367
368
QT_END_NAMESPACE