source: trunk/src/gui/embedded/qlock.cpp@ 890

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

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

  • Property svn:eol-style set to native
File size: 8.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 QtGui 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 "qlock_p.h"
43
44
45#ifdef QT_NO_QWS_MULTIPROCESS
46
47QT_BEGIN_NAMESPACE
48
49/* no multiprocess - use a dummy */
50
51QLock::QLock(const QString & /*filename*/, char /*id*/, bool /*create*/)
52 : type(Read), data(0)
53{
54}
55
56QLock::~QLock()
57{
58}
59
60bool QLock::isValid() const
61{
62 return true;
63}
64
65void QLock::lock(Type t)
66{
67 data = (QLockData *)-1;
68 type = t;
69}
70
71void QLock::unlock()
72{
73 data = 0;
74}
75
76bool QLock::locked() const
77{
78 return data;
79}
80
81QT_END_NAMESPACE
82
83#else // QT_NO_QWS_MULTIPROCESS
84
85#include "qwssignalhandler_p.h"
86
87#include <unistd.h>
88#include <sys/types.h>
89#if defined(Q_OS_DARWIN)
90# define Q_NO_SEMAPHORE
91# include <sys/stat.h>
92# include <sys/file.h>
93#else // Q_OS_DARWIN
94# include <sys/sem.h>
95# if (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) && !defined(QT_LINUXBASE)) \
96 || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) || defined(Q_OS_NETBSD) \
97 || defined(Q_OS_BSDI)
98 /* union semun is defined by including <sys/sem.h> */
99# else
100/* according to X/OPEN we have to define it ourselves */
101union semun {
102 int val; /* value for SETVAL */
103 struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
104 unsigned short *array; /* array for GETALL, SETALL */
105};
106# endif
107#endif // Q_OS_DARWIN
108#include <sys/ipc.h>
109#include <string.h>
110#include <errno.h>
111#include <qdebug.h>
112#include <signal.h>
113
114#include <private/qcore_unix_p.h> // overrides QT_OPEN
115
116
117QT_BEGIN_NAMESPACE
118
119#define MAX_LOCKS 200 // maximum simultaneous read locks
120
121class QLockData
122{
123public:
124#ifdef Q_NO_SEMAPHORE
125 QByteArray file;
126#endif // Q_NO_SEMAPHORE
127 int id;
128 int count;
129 bool owned;
130};
131
132/*!
133 \class QLock
134 \brief The QLock class is a wrapper for a System V shared semaphore.
135
136 \ingroup qws
137
138 \internal
139
140 It is used by \l{Qt for Embedded Linux} for synchronizing access to the graphics
141 card and shared memory region between processes.
142*/
143
144/*!
145 \enum QLock::Type
146
147 \value Read
148 \value Write
149*/
150
151/*!
152 \fn QLock::QLock(const QString &filename, char id, bool create)
153
154 Creates a lock. \a filename is the file path of the Unix-domain
155 socket the \l{Qt for Embedded Linux} client is using. \a id is the name of the
156 particular lock to be created on that socket. If \a create is true
157 the lock is to be created (as the Qt for Embedded Linux server does); if \a
158 create is false the lock should exist already (as the Qt for Embedded Linux
159 client expects).
160*/
161
162QLock::QLock(const QString &filename, char id, bool create)
163{
164 data = new QLockData;
165 data->count = 0;
166#ifdef Q_NO_SEMAPHORE
167 data->file = QString(filename+id).toLocal8Bit().constData();
168 for(int x = 0; x < 2; x++) {
169 data->id = QT_OPEN(data->file, O_RDWR | (x ? O_CREAT : 0), S_IRWXU);
170 if(data->id != -1 || !create) {
171 data->owned = x;
172 break;
173 }
174 }
175#else
176 key_t semkey = ftok(filename.toLocal8Bit().constData(), id);
177 data->id = semget(semkey,0,0);
178 data->owned = create;
179 if (create) {
180 semun arg; arg.val = 0;
181 if (data->id != -1)
182 semctl(data->id,0,IPC_RMID,arg);
183 data->id = semget(semkey,1,IPC_CREAT|0600);
184 arg.val = MAX_LOCKS;
185 semctl(data->id,0,SETVAL,arg);
186
187 QWSSignalHandler::instance()->addSemaphore(data->id);
188 }
189#endif
190 if (data->id == -1) {
191 int eno = errno;
192 qWarning("Cannot %s semaphore %s '%c'", (create ? "create" : "get"),
193 qPrintable(filename), id);
194 qDebug() << "Error" << eno << strerror(eno);
195 }
196}
197
198/*!
199 \fn QLock::~QLock()
200
201 Destroys a lock
202*/
203
204QLock::~QLock()
205{
206 if (locked())
207 unlock();
208#ifdef Q_NO_SEMAPHORE
209 if(isValid()) {
210 QT_CLOSE(data->id);
211 if(data->owned)
212 unlink(data->file);
213 }
214#else
215 if(data->owned)
216 QWSSignalHandler::instance()->removeSemaphore(data->id);
217#endif
218 delete data;
219}
220
221/*!
222 \fn bool QLock::isValid() const
223
224 Returns true if the lock constructor was successful; returns false if
225 the lock could not be created or was not available to connect to.
226*/
227
228bool QLock::isValid() const
229{
230 return (data->id != -1);
231}
232
233/*!
234 Locks the semaphore with a lock of type \a t. Locks can either be
235 \c Read or \c Write. If a lock is \c Read, attempts by other
236 processes to obtain \c Read locks will succeed, and \c Write
237 attempts will block until the lock is unlocked. If locked as \c
238 Write, all attempts to lock by other processes will block until
239 the lock is unlocked. Locks are stacked: i.e. a given QLock can be
240 locked multiple times by the same process without blocking, and
241 will only be unlocked after a corresponding number of unlock()
242 calls.
243*/
244
245void QLock::lock(Type t)
246{
247 if (!data->count) {
248#ifdef Q_NO_SEMAPHORE
249 int op = LOCK_SH;
250 if(t == Write)
251 op = LOCK_EX;
252 for(int rv=1; rv;) {
253 rv = flock(data->id, op);
254 if (rv == -1 && errno != EINTR)
255 qDebug("Semop lock failure %s",strerror(errno));
256 }
257#else
258 sembuf sops;
259 sops.sem_num = 0;
260 sops.sem_flg = SEM_UNDO;
261
262 if (t == Write) {
263 sops.sem_op = -MAX_LOCKS;
264 type = Write;
265 } else {
266 sops.sem_op = -1;
267 type = Read;
268 }
269
270 int rv;
271 do {
272 rv = semop(data->id,&sops,1);
273 if (rv == -1 && errno != EINTR)
274 qDebug("Semop lock failure %s",strerror(errno));
275 } while (rv == -1 && errno == EINTR);
276#endif
277 }
278 data->count++;
279}
280
281/*!
282 \fn void QLock::unlock()
283
284 Unlocks the semaphore. If other processes were blocking waiting to
285 lock() the semaphore, one of them will wake up and succeed in
286 lock()ing.
287*/
288
289void QLock::unlock()
290{
291 if(data->count) {
292 data->count--;
293 if(!data->count) {
294#ifdef Q_NO_SEMAPHORE
295 for(int rv=1; rv;) {
296 rv = flock(data->id, LOCK_UN);
297 if (rv == -1 && errno != EINTR)
298 qDebug("Semop lock failure %s",strerror(errno));
299 }
300#else
301 sembuf sops;
302 sops.sem_num = 0;
303 sops.sem_op = 1;
304 sops.sem_flg = SEM_UNDO;
305 if (type == Write)
306 sops.sem_op = MAX_LOCKS;
307
308 int rv;
309 do {
310 rv = semop(data->id,&sops,1);
311 if (rv == -1 && errno != EINTR)
312 qDebug("Semop unlock failure %s",strerror(errno));
313 } while (rv == -1 && errno == EINTR);
314#endif
315 }
316 } else {
317 qDebug("Unlock without corresponding lock");
318 }
319}
320
321/*!
322 \fn bool QLock::locked() const
323
324 Returns true if the lock is currently held by the current process;
325 otherwise returns false.
326*/
327
328bool QLock::locked() const
329{
330 return (data->count > 0);
331}
332
333QT_END_NAMESPACE
334
335#endif // QT_NO_QWS_MULTIPROCESS
336
Note: See TracBrowser for help on using the repository browser.