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