source: trunk/tools/qvfb/qlock.cpp@ 372

Last change on this file since 372 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 8.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qlock_p.h"
43
44#ifndef QT_NO_QWS_MULTIPROCESS
45
46#include "qwssignalhandler_p.h"
47#include <unistd.h>
48#include <sys/types.h>
49#if defined(Q_OS_DARWIN)
50# define Q_NO_SEMAPHORE
51# include <sys/stat.h>
52# include <sys/file.h>
53#else // Q_OS_DARWIN
54# include <sys/sem.h>
55# if (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) && !defined(QT_LINUXBASE)) \
56 || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) || defined(Q_OS_NETBSD) \
57 || defined(Q_OS_BSDI)
58 /* union semun is defined by including <sys/sem.h> */
59# else
60/* according to X/OPEN we have to define it ourselves */
61union semun {
62 int val; /* value for SETVAL */
63 struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
64 unsigned short *array; /* array for GETALL, SETALL */
65};
66# endif
67#endif // Q_OS_DARWIN
68#include <sys/ipc.h>
69#include <string.h>
70#include <errno.h>
71#include <qdebug.h>
72#include <signal.h>
73
74#endif // QT_NO_QWS_MULTIPROCESS
75
76#define MAX_LOCKS 200 // maximum simultaneous read locks
77
78QT_BEGIN_NAMESPACE
79
80
81#ifndef QT_NO_QWS_MULTIPROCESS
82class QLockData
83{
84public:
85#ifdef Q_NO_SEMAPHORE
86 QByteArray file;
87#endif // Q_NO_SEMAPHORE
88 int id;
89 int count;
90 bool owned;
91};
92#endif // QT_NO_QWS_MULTIPROCESS
93
94/*!
95 \class QLock
96 \brief The QLock class is a wrapper for a System V shared semaphore.
97
98 \ingroup qws
99 \ingroup io
100
101 \internal
102
103 It is used by \l{Qt for Embedded Linux} for synchronizing access to the graphics
104 card and shared memory region between processes.
105*/
106
107/*!
108 \enum QLock::Type
109
110 \value Read
111 \value Write
112*/
113
114/*!
115 \fn QLock::QLock(const QString &filename, char id, bool create)
116
117 Creates a lock. \a filename is the file path of the Unix-domain
118 socket the \l{Qt for Embedded Linux} client is using. \a id is the name of the
119 particular lock to be created on that socket. If \a create is true
120 the lock is to be created (as the Qt for Embedded Linux server does); if \a
121 create is false the lock should exist already (as the Qt for Embedded Linux
122 client expects).
123*/
124
125QLock::QLock(const QString &filename, char id, bool create)
126{
127#ifdef QT_NO_QWS_MULTIPROCESS
128 Q_UNUSED(filename);
129 Q_UNUSED(id);
130 Q_UNUSED(create);
131#else
132 data = new QLockData;
133 data->count = 0;
134#ifdef Q_NO_SEMAPHORE
135 data->file = QString(filename+id).toLocal8Bit().constData();
136 for(int x = 0; x < 2; x++) {
137 data->id = open(data->file, O_RDWR | (x ? O_CREAT : 0), S_IRWXU);
138 if(data->id != -1 || !create) {
139 data->owned = x;
140 break;
141 }
142 }
143#else
144 key_t semkey = ftok(filename.toLocal8Bit().constData(), id);
145 data->id = semget(semkey,0,0);
146 data->owned = create;
147 if (create) {
148 semun arg; arg.val = 0;
149 if (data->id != -1)
150 semctl(data->id,0,IPC_RMID,arg);
151 data->id = semget(semkey,1,IPC_CREAT|0600);
152 arg.val = MAX_LOCKS;
153 semctl(data->id,0,SETVAL,arg);
154
155 QWSSignalHandler::instance()->addSemaphore(data->id);
156 }
157#endif
158 if (data->id == -1) {
159 int eno = errno;
160 qWarning("Cannot %s semaphore %s '%c'", (create ? "create" : "get"),
161 qPrintable(filename), id);
162 qDebug() << "Error" << eno << strerror(eno);
163 }
164#endif
165}
166
167/*!
168 \fn QLock::~QLock()
169
170 Destroys a lock
171*/
172
173QLock::~QLock()
174{
175#ifndef QT_NO_QWS_MULTIPROCESS
176 if (locked())
177 unlock();
178#ifdef Q_NO_SEMAPHORE
179 if(isValid()) {
180 close(data->id);
181 if(data->owned)
182 unlink(data->file);
183 }
184#else
185 if(data->owned)
186 QWSSignalHandler::instance()->removeSemaphore(data->id);
187#endif
188 delete data;
189#endif
190}
191
192/*!
193 \fn bool QLock::isValid() const
194
195 Returns true if the lock constructor was successful; returns false if
196 the lock could not be created or was not available to connect to.
197*/
198
199bool QLock::isValid() const
200{
201#ifndef QT_NO_QWS_MULTIPROCESS
202 return (data->id != -1);
203#else
204 return true;
205#endif
206}
207
208/*!
209 Locks the semaphore with a lock of type \a t. Locks can either be
210 \c Read or \c Write. If a lock is \c Read, attempts by other
211 processes to obtain \c Read locks will succeed, and \c Write
212 attempts will block until the lock is unlocked. If locked as \c
213 Write, all attempts to lock by other processes will block until
214 the lock is unlocked. Locks are stacked: i.e. a given QLock can be
215 locked multiple times by the same process without blocking, and
216 will only be unlocked after a corresponding number of unlock()
217 calls.
218*/
219
220void QLock::lock(Type t)
221{
222#ifdef QT_NO_QWS_MULTIPROCESS
223 Q_UNUSED(t);
224#else
225 if (!data->count) {
226#ifdef Q_NO_SEMAPHORE
227 int op = LOCK_SH;
228 if(t == Write)
229 op = LOCK_EX;
230 for(int rv=1; rv;) {
231 rv = flock(data->id, op);
232 if (rv == -1 && errno != EINTR)
233 qDebug("Semop lock failure %s",strerror(errno));
234 }
235#else
236 sembuf sops;
237 sops.sem_num = 0;
238 sops.sem_flg = SEM_UNDO;
239
240 if (t == Write) {
241 sops.sem_op = -MAX_LOCKS;
242 type = Write;
243 } else {
244 sops.sem_op = -1;
245 type = Read;
246 }
247
248 int rv;
249 do {
250 rv = semop(data->id,&sops,1);
251 if (rv == -1 && errno != EINTR)
252 qDebug("Semop lock failure %s",strerror(errno));
253 } while (rv == -1 && errno == EINTR);
254#endif
255 }
256 data->count++;
257#endif
258}
259
260/*!
261 \fn void QLock::unlock()
262
263 Unlocks the semaphore. If other processes were blocking waiting to
264 lock() the semaphore, one of them will wake up and succeed in
265 lock()ing.
266*/
267
268void QLock::unlock()
269{
270#ifndef QT_NO_QWS_MULTIPROCESS
271 if(data->count) {
272 data->count--;
273 if(!data->count) {
274#ifdef Q_NO_SEMAPHORE
275 for(int rv=1; rv;) {
276 rv = flock(data->id, LOCK_UN);
277 if (rv == -1 && errno != EINTR)
278 qDebug("Semop lock failure %s",strerror(errno));
279 }
280#else
281 sembuf sops;
282 sops.sem_num = 0;
283 sops.sem_op = 1;
284 sops.sem_flg = SEM_UNDO;
285 if (type == Write)
286 sops.sem_op = MAX_LOCKS;
287
288 int rv;
289 do {
290 rv = semop(data->id,&sops,1);
291 if (rv == -1 && errno != EINTR)
292 qDebug("Semop unlock failure %s",strerror(errno));
293 } while (rv == -1 && errno == EINTR);
294#endif
295 }
296 } else {
297 qDebug("Unlock without corresponding lock");
298 }
299#endif
300}
301
302/*!
303 \fn bool QLock::locked() const
304
305 Returns true if the lock is currently held by the current process;
306 otherwise returns false.
307*/
308
309bool QLock::locked() const
310{
311#ifndef QT_NO_QWS_MULTIPROCESS
312 return (data->count > 0);
313#else
314 return false;
315#endif
316}
317
318QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.