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 "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 |
|
---|
154 | In Windows and in Symbian, \a mode is ignored, and the system always tries to
|
---|
155 | create a semaphore for the specified \a key. If the system does not
|
---|
156 | already have a semaphore identified as \a key, it creates the
|
---|
157 | semaphore and sets its resource count to \a initialValue. But if the
|
---|
158 | system already has a semaphore identified as \a key it uses that
|
---|
159 | semaphore and ignores \a initialValue.
|
---|
160 |
|
---|
161 | The \l {QSystemSemaphore::AccessMode} {mode} parameter is only used
|
---|
162 | in Unix systems to handle the case where a semaphore survives a
|
---|
163 | process crash. In that case, the next process to allocate a
|
---|
164 | semaphore with the same \a key will get the semaphore that survived
|
---|
165 | the crash, and unless \a mode is \l {QSystemSemaphore::} {Create},
|
---|
166 | the resource count will not be reset to \a initialValue but will
|
---|
167 | retain the initial value it had been given by the crashed process.
|
---|
168 |
|
---|
169 | \sa acquire(), key()
|
---|
170 | */
|
---|
171 | QSystemSemaphore::QSystemSemaphore(const QString &key, int initialValue, AccessMode mode)
|
---|
172 | : d(new QSystemSemaphorePrivate)
|
---|
173 | {
|
---|
174 | setKey(key, initialValue, mode);
|
---|
175 | }
|
---|
176 |
|
---|
177 | /*!
|
---|
178 | The destructor destroys the QSystemSemaphore object, but the
|
---|
179 | underlying system semaphore is not removed from the system unless
|
---|
180 | this instance of QSystemSemaphore is the last one existing for that
|
---|
181 | system semaphore.
|
---|
182 |
|
---|
183 | Two important side effects of the destructor depend on the system.
|
---|
184 | In Windows, if acquire() has been called for this semaphore but not
|
---|
185 | release(), release() will not be called by the destructor, nor will
|
---|
186 | the resource be released when the process exits normally. This would
|
---|
187 | be a program bug which could be the cause of a deadlock in another
|
---|
188 | process trying to acquire the same resource. In Unix, acquired
|
---|
189 | resources that are not released before the destructor is called are
|
---|
190 | automatically released when the process exits.
|
---|
191 | */
|
---|
192 | QSystemSemaphore::~QSystemSemaphore()
|
---|
193 | {
|
---|
194 | d->cleanHandle();
|
---|
195 | }
|
---|
196 |
|
---|
197 | /*!
|
---|
198 | \enum QSystemSemaphore::AccessMode
|
---|
199 |
|
---|
200 | This enum is used by the constructor and setKey(). Its purpose is to
|
---|
201 | enable handling the problem in Unix implementations of semaphores
|
---|
202 | that survive a crash. In Unix, when a semaphore survives a crash, we
|
---|
203 | need a way to force it to reset its resource count, when the system
|
---|
204 | reuses the semaphore. In Windows and in Symbian, where semaphores can't survive a
|
---|
205 | crash, this enum has no effect.
|
---|
206 |
|
---|
207 | \value Open If the semaphore already exists, its initial resource
|
---|
208 | count is not reset. If the semaphore does not already exist, it is
|
---|
209 | created and its initial resource count set.
|
---|
210 |
|
---|
211 | \value Create QSystemSemaphore takes ownership of the semaphore and
|
---|
212 | sets its resource count to the requested value, regardless of
|
---|
213 | whether the semaphore already exists by having survived a crash.
|
---|
214 | This value should be passed to the constructor, when the first
|
---|
215 | semaphore for a particular key is constructed and you know that if
|
---|
216 | the semaphore already exists it could only be because of a crash. In
|
---|
217 | Windows and in Symbian, where a semaphore can't survive a crash, Create and Open
|
---|
218 | have the same behavior.
|
---|
219 | */
|
---|
220 |
|
---|
221 | /*!
|
---|
222 | This function works the same as the constructor. It reconstructs
|
---|
223 | this QSystemSemaphore object. If the new \a key is different from
|
---|
224 | the old key, calling this function is like calling the destructor of
|
---|
225 | the semaphore with the old key, then calling the constructor to
|
---|
226 | create a new semaphore with the new \a key. The \a initialValue and
|
---|
227 | \a mode parameters are as defined for the constructor.
|
---|
228 |
|
---|
229 | \sa QSystemSemaphore(), key()
|
---|
230 | */
|
---|
231 | void QSystemSemaphore::setKey(const QString &key, int initialValue, AccessMode mode)
|
---|
232 | {
|
---|
233 | if (key == d->key && mode == Open)
|
---|
234 | return;
|
---|
235 | d->error = NoError;
|
---|
236 | d->errorString = QString();
|
---|
237 | #if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN)
|
---|
238 | // optimization to not destroy/create the file & semaphore
|
---|
239 | if (key == d->key && mode == Create && d->createdSemaphore && d->createdFile) {
|
---|
240 | d->initialValue = initialValue;
|
---|
241 | d->unix_key = -1;
|
---|
242 | d->handle(mode);
|
---|
243 | return;
|
---|
244 | }
|
---|
245 | #endif
|
---|
246 | d->cleanHandle();
|
---|
247 | d->key = key;
|
---|
248 | d->initialValue = initialValue;
|
---|
249 | // cache the file name so it doesn't have to be generated all the time.
|
---|
250 | d->fileName = d->makeKeyFileName();
|
---|
251 | d->handle(mode);
|
---|
252 | }
|
---|
253 |
|
---|
254 | /*!
|
---|
255 | Returns the key assigned to this system semaphore. The key is the
|
---|
256 | name by which the semaphore can be accessed from other processes.
|
---|
257 |
|
---|
258 | \sa setKey()
|
---|
259 | */
|
---|
260 | QString QSystemSemaphore::key() const
|
---|
261 | {
|
---|
262 | return d->key;
|
---|
263 | }
|
---|
264 |
|
---|
265 | /*!
|
---|
266 | Acquires one of the resources guarded by this semaphore, if there is
|
---|
267 | one available, and returns true. If all the resources guarded by this
|
---|
268 | semaphore have already been acquired, the call blocks until one of
|
---|
269 | them is released by another process or thread having a semaphore
|
---|
270 | with the same key.
|
---|
271 |
|
---|
272 | If false is returned, a system error has occurred. Call error()
|
---|
273 | to get a value of QSystemSemaphore::SystemSemaphoreError that
|
---|
274 | indicates which error occurred.
|
---|
275 |
|
---|
276 | \sa release()
|
---|
277 | */
|
---|
278 | bool QSystemSemaphore::acquire()
|
---|
279 | {
|
---|
280 | return d->modifySemaphore(-1);
|
---|
281 | }
|
---|
282 |
|
---|
283 | /*!
|
---|
284 | Releases \a n resources guarded by the semaphore. Returns true
|
---|
285 | unless there is a system error.
|
---|
286 |
|
---|
287 | Example: Create a system semaphore having five resources; acquire
|
---|
288 | them all and then release them all.
|
---|
289 |
|
---|
290 | \snippet doc/src/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp 1
|
---|
291 |
|
---|
292 | This function can also "create" resources. For example, immediately
|
---|
293 | following the sequence of statements above, suppose we add the
|
---|
294 | statement:
|
---|
295 |
|
---|
296 | \snippet doc/src/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp 2
|
---|
297 |
|
---|
298 | Ten new resources are now guarded by the semaphore, in addition to
|
---|
299 | the five that already existed. You would not normally use this
|
---|
300 | function to create more resources.
|
---|
301 |
|
---|
302 | \sa acquire()
|
---|
303 | */
|
---|
304 | bool QSystemSemaphore::release(int n)
|
---|
305 | {
|
---|
306 | if (n == 0)
|
---|
307 | return true;
|
---|
308 | if (n < 0) {
|
---|
309 | qWarning("QSystemSemaphore::release: n is negative.");
|
---|
310 | return false;
|
---|
311 | }
|
---|
312 | return d->modifySemaphore(n);
|
---|
313 | }
|
---|
314 |
|
---|
315 | /*!
|
---|
316 | Returns a value indicating whether an error occurred, and, if so,
|
---|
317 | which error it was.
|
---|
318 |
|
---|
319 | \sa errorString()
|
---|
320 | */
|
---|
321 | QSystemSemaphore::SystemSemaphoreError QSystemSemaphore::error() const
|
---|
322 | {
|
---|
323 | return d->error;
|
---|
324 | }
|
---|
325 |
|
---|
326 | /*!
|
---|
327 | \enum QSystemSemaphore::SystemSemaphoreError
|
---|
328 |
|
---|
329 | \value NoError No error occurred.
|
---|
330 |
|
---|
331 | \value PermissionDenied The operation failed because the caller
|
---|
332 | didn't have the required permissions.
|
---|
333 |
|
---|
334 | \value KeyError The operation failed because of an invalid key.
|
---|
335 |
|
---|
336 | \value AlreadyExists The operation failed because a system
|
---|
337 | semaphore with the specified key already existed.
|
---|
338 |
|
---|
339 | \value NotFound The operation failed because a system semaphore
|
---|
340 | with the specified key could not be found.
|
---|
341 |
|
---|
342 | \value OutOfResources The operation failed because there was
|
---|
343 | not enough memory available to fill the request.
|
---|
344 |
|
---|
345 | \value UnknownError Something else happened and it was bad.
|
---|
346 | */
|
---|
347 |
|
---|
348 | /*!
|
---|
349 | Returns a text description of the last error that occurred. If
|
---|
350 | error() returns an \l {QSystemSemaphore::SystemSemaphoreError} {error
|
---|
351 | value}, call this function to get a text string that describes the
|
---|
352 | error.
|
---|
353 |
|
---|
354 | \sa error()
|
---|
355 | */
|
---|
356 | QString QSystemSemaphore::errorString() const
|
---|
357 | {
|
---|
358 | return d->errorString;
|
---|
359 | }
|
---|
360 |
|
---|
361 | #endif // QT_NO_SYSTEMSEMAPHORE
|
---|
362 |
|
---|
363 | QT_END_NAMESPACE
|
---|