source: trunk/src/corelib/kernel/qsharedmemory_unix.cpp

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

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

File size: 8.9 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 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 "qplatformdefs.h"
43
44#include "qsharedmemory.h"
45#include "qsharedmemory_p.h"
46#include "qsystemsemaphore.h"
47#include <qdir.h>
48#include <qdebug.h>
49
50#include <errno.h>
51
52#ifndef QT_NO_SHAREDMEMORY
53#include <sys/types.h>
54#include <sys/ipc.h>
55#include <sys/shm.h>
56#include <sys/types.h>
57#include <sys/stat.h>
58#include <fcntl.h>
59#include <unistd.h>
60#endif //QT_NO_SHAREDMEMORY
61
62#include "private/qcore_unix_p.h"
63
64#ifndef QT_NO_SHAREDMEMORY
65QT_BEGIN_NAMESPACE
66
67QSharedMemoryPrivate::QSharedMemoryPrivate()
68 : QObjectPrivate(), memory(0), size(0), error(QSharedMemory::NoError),
69#ifndef QT_NO_SYSTEMSEMAPHORE
70 systemSemaphore(QString()), lockedByMe(false),
71#endif
72 unix_key(0)
73{
74}
75
76void QSharedMemoryPrivate::setErrorString(const QString &function)
77{
78 // EINVAL is handled in functions so they can give better error strings
79 switch (errno) {
80 case EACCES:
81 errorString = QSharedMemory::tr("%1: permission denied").arg(function);
82 error = QSharedMemory::PermissionDenied;
83 break;
84 case EEXIST:
85 errorString = QSharedMemory::tr("%1: already exists").arg(function);
86 error = QSharedMemory::AlreadyExists;
87 break;
88 case ENOENT:
89 errorString = QSharedMemory::tr("%1: doesn't exist").arg(function);
90 error = QSharedMemory::NotFound;
91 break;
92 case EMFILE:
93 case ENOMEM:
94 case ENOSPC:
95 errorString = QSharedMemory::tr("%1: out of resources").arg(function);
96 error = QSharedMemory::OutOfResources;
97 break;
98 default:
99 errorString = QSharedMemory::tr("%1: unknown error %2").arg(function).arg(errno);
100 error = QSharedMemory::UnknownError;
101#if defined QSHAREDMEMORY_DEBUG
102 qDebug() << errorString << "key" << key << "errno" << errno << EINVAL;
103#endif
104 }
105}
106
107/*!
108 \internal
109
110 If not already made create the handle used for accessing the shared memory.
111*/
112key_t QSharedMemoryPrivate::handle()
113{
114 // already made
115 if (unix_key)
116 return unix_key;
117
118 // don't allow making handles on empty keys
119 if (key.isEmpty()) {
120 errorString = QSharedMemory::tr("%1: key is empty").arg(QLatin1String("QSharedMemory::handle:"));
121 error = QSharedMemory::KeyError;
122 return 0;
123 }
124
125 // ftok requires that an actual file exists somewhere
126 QString fileName = makePlatformSafeKey(key);
127 if (!QFile::exists(fileName)) {
128 errorString = QSharedMemory::tr("%1: UNIX key file doesn't exist").arg(QLatin1String("QSharedMemory::handle:"));
129 error = QSharedMemory::NotFound;
130 return 0;
131 }
132
133 unix_key = ftok(QFile::encodeName(fileName).constData(), 'Q');
134 if (-1 == unix_key) {
135 errorString = QSharedMemory::tr("%1: ftok failed").arg(QLatin1String("QSharedMemory::handle:"));
136 error = QSharedMemory::KeyError;
137 unix_key = 0;
138 }
139 return unix_key;
140}
141
142#endif // QT_NO_SHAREDMEMORY
143
144#if !(defined(QT_NO_SHAREDMEMORY) && defined(QT_NO_SYSTEMSEMAPHORE))
145/*!
146 \internal
147 Creates the unix file if needed.
148 returns true if the unix file was created.
149
150 -1 error
151 0 already existed
152 1 created
153 */
154int QSharedMemoryPrivate::createUnixKeyFile(const QString &fileName)
155{
156 if (QFile::exists(fileName))
157 return 0;
158
159 int fd = qt_safe_open(QFile::encodeName(fileName).constData(),
160 O_EXCL | O_CREAT | O_RDWR, 0640);
161 if (-1 == fd) {
162 if (errno == EEXIST)
163 return 0;
164 return -1;
165 } else {
166 close(fd);
167 }
168 return 1;
169}
170#endif // QT_NO_SHAREDMEMORY && QT_NO_SYSTEMSEMAPHORE
171
172#ifndef QT_NO_SHAREDMEMORY
173
174bool QSharedMemoryPrivate::cleanHandle()
175{
176 unix_key = 0;
177 return true;
178}
179
180bool QSharedMemoryPrivate::create(int size)
181{
182 // build file if needed
183 bool createdFile = false;
184 int built = createUnixKeyFile(makePlatformSafeKey(key));
185 if (built == -1) {
186 errorString = QSharedMemory::tr("%1: unable to make key").arg(QLatin1String("QSharedMemory::handle:"));
187 error = QSharedMemory::KeyError;
188 return false;
189 }
190 if (built == 1) {
191 createdFile = true;
192 }
193
194 // get handle
195 if (!handle()) {
196 if (createdFile)
197 QFile::remove(makePlatformSafeKey(key));
198 return false;
199 }
200
201 // create
202 if (-1 == shmget(handle(), size, 0666 | IPC_CREAT | IPC_EXCL)) {
203 QString function = QLatin1String("QSharedMemory::create");
204 switch (errno) {
205 case EINVAL:
206 errorString = QSharedMemory::tr("%1: system-imposed size restrictions").arg(QLatin1String("QSharedMemory::handle"));
207 error = QSharedMemory::InvalidSize;
208 break;
209 default:
210 setErrorString(function);
211 }
212 if (createdFile && error != QSharedMemory::AlreadyExists)
213 QFile::remove(makePlatformSafeKey(key));
214 return false;
215 }
216
217 return true;
218}
219
220bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode)
221{
222 // grab the shared memory segment id
223 if (!handle())
224 return false;
225
226 int id = shmget(handle(), 0, (mode == QSharedMemory::ReadOnly ? 0444 : 0660));
227 if (-1 == id) {
228 setErrorString(QLatin1String("QSharedMemory::attach (shmget)"));
229 return false;
230 }
231
232 // grab the memory
233 memory = shmat(id, 0, (mode == QSharedMemory::ReadOnly ? SHM_RDONLY : 0));
234 if ((void*) - 1 == memory) {
235 memory = 0;
236 setErrorString(QLatin1String("QSharedMemory::attach (shmat)"));
237 return false;
238 }
239
240 // grab the size
241 shmid_ds shmid_ds;
242 if (!shmctl(id, IPC_STAT, &shmid_ds)) {
243 size = (int)shmid_ds.shm_segsz;
244 } else {
245 setErrorString(QLatin1String("QSharedMemory::attach (shmctl)"));
246 return false;
247 }
248
249 return true;
250}
251
252bool QSharedMemoryPrivate::detach()
253{
254 // detach from the memory segment
255 if (-1 == shmdt(memory)) {
256 QString function = QLatin1String("QSharedMemory::detach");
257 switch (errno) {
258 case EINVAL:
259 errorString = QSharedMemory::tr("%1: not attached").arg(function);
260 error = QSharedMemory::NotFound;
261 break;
262 default:
263 setErrorString(function);
264 }
265 return false;
266 }
267 memory = 0;
268
269 // Get the number of current attachments
270 if (!handle())
271 return false;
272 int id = shmget(handle(), 0, 0444);
273 unix_key = 0;
274
275 struct shmid_ds shmid_ds;
276 if (0 != shmctl(id, IPC_STAT, &shmid_ds)) {
277 switch (errno) {
278 case EINVAL:
279 return true;
280 default:
281 return false;
282 }
283 }
284 // If there are no attachments then remove it.
285 if (shmid_ds.shm_nattch == 0) {
286 // mark for removal
287 if (-1 == shmctl(id, IPC_RMID, &shmid_ds)) {
288 setErrorString(QLatin1String("QSharedMemory::remove"));
289 switch (errno) {
290 case EINVAL:
291 return true;
292 default:
293 return false;
294 }
295 }
296
297 // remove file
298 if (!QFile::remove(makePlatformSafeKey(key)))
299 return false;
300 }
301 return true;
302}
303
304
305QT_END_NAMESPACE
306
307#endif // QT_NO_SHAREDMEMORY
Note: See TracBrowser for help on using the repository browser.