Line | Source Code | Coverage |
---|
1 | /**************************************************************************** | - |
2 | ** | - |
3 | ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). | - |
4 | ** Contact: http://www.qt-project.org/legal | - |
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 Digia. For licensing terms and | - |
14 | ** conditions see http://qt.digia.com/licensing. For further information | - |
15 | ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software | - |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the | - |
21 | ** packaging of this file. Please review the following information to | - |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements | - |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | - |
24 | ** | - |
25 | ** In addition, as a special exception, Digia gives you certain additional | - |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception | - |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | - |
28 | ** | - |
29 | ** GNU General Public License Usage | - |
30 | ** Alternatively, this file may be used under the terms of the GNU | - |
31 | ** General Public License version 3.0 as published by the Free Software | - |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the | - |
33 | ** packaging of this file. Please review the following information to | - |
34 | ** ensure the GNU General Public License version 3.0 requirements will be | - |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. | - |
36 | ** | - |
37 | ** | - |
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/stat.h> | - |
57 | #include <fcntl.h> | - |
58 | #include <unistd.h> | - |
59 | #endif //QT_NO_SHAREDMEMORY | - |
60 | | - |
61 | #include "private/qcore_unix_p.h" | - |
62 | | - |
63 | #ifndef QT_NO_SHAREDMEMORY | - |
64 | QT_BEGIN_NAMESPACE | - |
65 | | - |
66 | QSharedMemoryPrivate::QSharedMemoryPrivate() | - |
67 | : QObjectPrivate(), memory(0), size(0), error(QSharedMemory::NoError), | - |
68 | #ifndef QT_NO_SYSTEMSEMAPHORE | - |
69 | systemSemaphore(QString()), lockedByMe(false), | - |
70 | #endif | - |
71 | unix_key(0) | - |
72 | { | - |
73 | } executed: } Execution Count:1 | 1 |
74 | | - |
75 | void QSharedMemoryPrivate::setErrorString(const QString &function) | - |
76 | { | - |
77 | // EINVAL is handled in functions so they can give better error strings | - |
78 | switch (errno) { | - |
79 | case EACCES: | - |
80 | errorString = QSharedMemory::tr("%1: permission denied").arg(function); never executed (the execution status of this line is deduced): errorString = QSharedMemory::tr("%1: permission denied").arg(function); | - |
81 | error = QSharedMemory::PermissionDenied; never executed (the execution status of this line is deduced): error = QSharedMemory::PermissionDenied; | - |
82 | break; | 0 |
83 | case EEXIST: | - |
84 | errorString = QSharedMemory::tr("%1: already exists").arg(function); never executed (the execution status of this line is deduced): errorString = QSharedMemory::tr("%1: already exists").arg(function); | - |
85 | error = QSharedMemory::AlreadyExists; never executed (the execution status of this line is deduced): error = QSharedMemory::AlreadyExists; | - |
86 | break; | 0 |
87 | case ENOENT: | - |
88 | errorString = QSharedMemory::tr("%1: doesn't exist").arg(function); never executed (the execution status of this line is deduced): errorString = QSharedMemory::tr("%1: doesn't exist").arg(function); | - |
89 | error = QSharedMemory::NotFound; never executed (the execution status of this line is deduced): error = QSharedMemory::NotFound; | - |
90 | break; | 0 |
91 | case EMFILE: | - |
92 | case ENOMEM: | - |
93 | case ENOSPC: | - |
94 | errorString = QSharedMemory::tr("%1: out of resources").arg(function); never executed (the execution status of this line is deduced): errorString = QSharedMemory::tr("%1: out of resources").arg(function); | - |
95 | error = QSharedMemory::OutOfResources; never executed (the execution status of this line is deduced): error = QSharedMemory::OutOfResources; | - |
96 | break; | 0 |
97 | default: | - |
98 | errorString = QSharedMemory::tr("%1: unknown error %2").arg(function).arg(errno); never executed (the execution status of this line is deduced): errorString = QSharedMemory::tr("%1: unknown error %2").arg(function).arg((*__errno_location ())); | - |
99 | error = QSharedMemory::UnknownError; never executed (the execution status of this line is deduced): error = QSharedMemory::UnknownError; | - |
100 | #if defined QSHAREDMEMORY_DEBUG | - |
101 | qDebug() << errorString << "key" << key << "errno" << errno << EINVAL; | - |
102 | #endif | - |
103 | } | 0 |
104 | } | 0 |
105 | | - |
106 | /*! | - |
107 | \internal | - |
108 | | - |
109 | If not already made create the handle used for accessing the shared memory. | - |
110 | */ | - |
111 | key_t QSharedMemoryPrivate::handle() | - |
112 | { | - |
113 | // already made | - |
114 | if (unix_key) never evaluated: unix_key | 0 |
115 | return unix_key; never executed: return unix_key; | 0 |
116 | | - |
117 | // don't allow making handles on empty keys | - |
118 | if (nativeKey.isEmpty()) { never evaluated: nativeKey.isEmpty() | 0 |
119 | errorString = QSharedMemory::tr("%1: key is empty").arg(QLatin1String("QSharedMemory::handle:")); never executed (the execution status of this line is deduced): errorString = QSharedMemory::tr("%1: key is empty").arg(QLatin1String("QSharedMemory::handle:")); | - |
120 | error = QSharedMemory::KeyError; never executed (the execution status of this line is deduced): error = QSharedMemory::KeyError; | - |
121 | return 0; never executed: return 0; | 0 |
122 | } | - |
123 | | - |
124 | // ftok requires that an actual file exists somewhere | - |
125 | if (!QFile::exists(nativeKey)) { never evaluated: !QFile::exists(nativeKey) | 0 |
126 | errorString = QSharedMemory::tr("%1: UNIX key file doesn't exist").arg(QLatin1String("QSharedMemory::handle:")); never executed (the execution status of this line is deduced): errorString = QSharedMemory::tr("%1: UNIX key file doesn't exist").arg(QLatin1String("QSharedMemory::handle:")); | - |
127 | error = QSharedMemory::NotFound; never executed (the execution status of this line is deduced): error = QSharedMemory::NotFound; | - |
128 | return 0; never executed: return 0; | 0 |
129 | } | - |
130 | | - |
131 | unix_key = ftok(QFile::encodeName(nativeKey).constData(), 'Q'); never executed (the execution status of this line is deduced): unix_key = ftok(QFile::encodeName(nativeKey).constData(), 'Q'); | - |
132 | if (-1 == unix_key) { never evaluated: -1 == unix_key | 0 |
133 | errorString = QSharedMemory::tr("%1: ftok failed").arg(QLatin1String("QSharedMemory::handle:")); never executed (the execution status of this line is deduced): errorString = QSharedMemory::tr("%1: ftok failed").arg(QLatin1String("QSharedMemory::handle:")); | - |
134 | error = QSharedMemory::KeyError; never executed (the execution status of this line is deduced): error = QSharedMemory::KeyError; | - |
135 | unix_key = 0; never executed (the execution status of this line is deduced): unix_key = 0; | - |
136 | } | 0 |
137 | return unix_key; never executed: return unix_key; | 0 |
138 | } | - |
139 | | - |
140 | #endif // QT_NO_SHAREDMEMORY | - |
141 | | - |
142 | #if !(defined(QT_NO_SHAREDMEMORY) && defined(QT_NO_SYSTEMSEMAPHORE)) | - |
143 | /*! | - |
144 | \internal | - |
145 | Creates the unix file if needed. | - |
146 | returns true if the unix file was created. | - |
147 | | - |
148 | -1 error | - |
149 | 0 already existed | - |
150 | 1 created | - |
151 | */ | - |
152 | int QSharedMemoryPrivate::createUnixKeyFile(const QString &fileName) | - |
153 | { | - |
154 | if (QFile::exists(fileName)) partially evaluated: QFile::exists(fileName) no Evaluation Count:0 | yes Evaluation Count:46 |
| 0-46 |
155 | return 0; never executed: return 0; | 0 |
156 | | - |
157 | int fd = qt_safe_open(QFile::encodeName(fileName).constData(), executed (the execution status of this line is deduced): int fd = qt_safe_open(QFile::encodeName(fileName).constData(), | - |
158 | O_EXCL | O_CREAT | O_RDWR, 0640); executed (the execution status of this line is deduced): 0200 | 0100 | 02, 0640); | - |
159 | if (-1 == fd) { partially evaluated: -1 == fd no Evaluation Count:0 | yes Evaluation Count:46 |
| 0-46 |
160 | if (errno == EEXIST) never evaluated: (*__errno_location ()) == 17 | 0 |
161 | return 0; never executed: return 0; | 0 |
162 | return -1; never executed: return -1; | 0 |
163 | } else { | - |
164 | close(fd); executed (the execution status of this line is deduced): close(fd); | - |
165 | } executed: } Execution Count:46 | 46 |
166 | return 1; executed: return 1; Execution Count:46 | 46 |
167 | } | - |
168 | #endif // QT_NO_SHAREDMEMORY && QT_NO_SYSTEMSEMAPHORE | - |
169 | | - |
170 | #ifndef QT_NO_SHAREDMEMORY | - |
171 | | - |
172 | bool QSharedMemoryPrivate::cleanHandle() | - |
173 | { | - |
174 | unix_key = 0; never executed (the execution status of this line is deduced): unix_key = 0; | - |
175 | return true; never executed: return true; | 0 |
176 | } | - |
177 | | - |
178 | bool QSharedMemoryPrivate::create(int size) | - |
179 | { | - |
180 | // build file if needed | - |
181 | bool createdFile = false; never executed (the execution status of this line is deduced): bool createdFile = false; | - |
182 | int built = createUnixKeyFile(nativeKey); never executed (the execution status of this line is deduced): int built = createUnixKeyFile(nativeKey); | - |
183 | if (built == -1) { never evaluated: built == -1 | 0 |
184 | errorString = QSharedMemory::tr("%1: unable to make key").arg(QLatin1String("QSharedMemory::handle:")); never executed (the execution status of this line is deduced): errorString = QSharedMemory::tr("%1: unable to make key").arg(QLatin1String("QSharedMemory::handle:")); | - |
185 | error = QSharedMemory::KeyError; never executed (the execution status of this line is deduced): error = QSharedMemory::KeyError; | - |
186 | return false; never executed: return false; | 0 |
187 | } | - |
188 | if (built == 1) { never evaluated: built == 1 | 0 |
189 | createdFile = true; never executed (the execution status of this line is deduced): createdFile = true; | - |
190 | } | 0 |
191 | | - |
192 | // get handle | - |
193 | if (!handle()) { never evaluated: !handle() | 0 |
194 | if (createdFile) never evaluated: createdFile | 0 |
195 | QFile::remove(nativeKey); never executed: QFile::remove(nativeKey); | 0 |
196 | return false; never executed: return false; | 0 |
197 | } | - |
198 | | - |
199 | // create | - |
200 | if (-1 == shmget(unix_key, size, 0600 | IPC_CREAT | IPC_EXCL)) { never evaluated: -1 == shmget(unix_key, size, 0600 | 01000 | 02000) | 0 |
201 | QString function = QLatin1String("QSharedMemory::create"); never executed (the execution status of this line is deduced): QString function = QLatin1String("QSharedMemory::create"); | - |
202 | switch (errno) { | - |
203 | case EINVAL: | - |
204 | errorString = QSharedMemory::tr("%1: system-imposed size restrictions").arg(QLatin1String("QSharedMemory::handle")); never executed (the execution status of this line is deduced): errorString = QSharedMemory::tr("%1: system-imposed size restrictions").arg(QLatin1String("QSharedMemory::handle")); | - |
205 | error = QSharedMemory::InvalidSize; never executed (the execution status of this line is deduced): error = QSharedMemory::InvalidSize; | - |
206 | break; | 0 |
207 | default: | - |
208 | setErrorString(function); never executed (the execution status of this line is deduced): setErrorString(function); | - |
209 | } | 0 |
210 | if (createdFile && error != QSharedMemory::AlreadyExists) never evaluated: createdFile never evaluated: error != QSharedMemory::AlreadyExists | 0 |
211 | QFile::remove(nativeKey); never executed: QFile::remove(nativeKey); | 0 |
212 | return false; never executed: return false; | 0 |
213 | } | - |
214 | | - |
215 | return true; never executed: return true; | 0 |
216 | } | - |
217 | | - |
218 | bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode) | - |
219 | { | - |
220 | // grab the shared memory segment id | - |
221 | int id = shmget(unix_key, 0, (mode == QSharedMemory::ReadOnly ? 0400 : 0600)); never executed (the execution status of this line is deduced): int id = shmget(unix_key, 0, (mode == QSharedMemory::ReadOnly ? 0400 : 0600)); | - |
222 | if (-1 == id) { never evaluated: -1 == id | 0 |
223 | setErrorString(QLatin1String("QSharedMemory::attach (shmget)")); never executed (the execution status of this line is deduced): setErrorString(QLatin1String("QSharedMemory::attach (shmget)")); | - |
224 | return false; never executed: return false; | 0 |
225 | } | - |
226 | | - |
227 | // grab the memory | - |
228 | memory = shmat(id, 0, (mode == QSharedMemory::ReadOnly ? SHM_RDONLY : 0)); never executed (the execution status of this line is deduced): memory = shmat(id, 0, (mode == QSharedMemory::ReadOnly ? 010000 : 0)); | - |
229 | if ((void*) - 1 == memory) { never evaluated: (void*) - 1 == memory | 0 |
230 | memory = 0; never executed (the execution status of this line is deduced): memory = 0; | - |
231 | setErrorString(QLatin1String("QSharedMemory::attach (shmat)")); never executed (the execution status of this line is deduced): setErrorString(QLatin1String("QSharedMemory::attach (shmat)")); | - |
232 | return false; never executed: return false; | 0 |
233 | } | - |
234 | | - |
235 | // grab the size | - |
236 | shmid_ds shmid_ds; never executed (the execution status of this line is deduced): shmid_ds shmid_ds; | - |
237 | if (!shmctl(id, IPC_STAT, &shmid_ds)) { never evaluated: !shmctl(id, 2, &shmid_ds) | 0 |
238 | size = (int)shmid_ds.shm_segsz; never executed (the execution status of this line is deduced): size = (int)shmid_ds.shm_segsz; | - |
239 | } else { | 0 |
240 | setErrorString(QLatin1String("QSharedMemory::attach (shmctl)")); never executed (the execution status of this line is deduced): setErrorString(QLatin1String("QSharedMemory::attach (shmctl)")); | - |
241 | return false; never executed: return false; | 0 |
242 | } | - |
243 | | - |
244 | return true; never executed: return true; | 0 |
245 | } | - |
246 | | - |
247 | bool QSharedMemoryPrivate::detach() | - |
248 | { | - |
249 | // detach from the memory segment | - |
250 | if (-1 == shmdt(memory)) { never evaluated: -1 == shmdt(memory) | 0 |
251 | QString function = QLatin1String("QSharedMemory::detach"); never executed (the execution status of this line is deduced): QString function = QLatin1String("QSharedMemory::detach"); | - |
252 | switch (errno) { | - |
253 | case EINVAL: | - |
254 | errorString = QSharedMemory::tr("%1: not attached").arg(function); never executed (the execution status of this line is deduced): errorString = QSharedMemory::tr("%1: not attached").arg(function); | - |
255 | error = QSharedMemory::NotFound; never executed (the execution status of this line is deduced): error = QSharedMemory::NotFound; | - |
256 | break; | 0 |
257 | default: | - |
258 | setErrorString(function); never executed (the execution status of this line is deduced): setErrorString(function); | - |
259 | } | 0 |
260 | return false; never executed: return false; | 0 |
261 | } | - |
262 | memory = 0; never executed (the execution status of this line is deduced): memory = 0; | - |
263 | size = 0; never executed (the execution status of this line is deduced): size = 0; | - |
264 | | - |
265 | // Get the number of current attachments | - |
266 | int id = shmget(unix_key, 0, 0400); never executed (the execution status of this line is deduced): int id = shmget(unix_key, 0, 0400); | - |
267 | cleanHandle(); never executed (the execution status of this line is deduced): cleanHandle(); | - |
268 | | - |
269 | struct shmid_ds shmid_ds; never executed (the execution status of this line is deduced): struct shmid_ds shmid_ds; | - |
270 | if (0 != shmctl(id, IPC_STAT, &shmid_ds)) { never evaluated: 0 != shmctl(id, 2, &shmid_ds) | 0 |
271 | switch (errno) { | - |
272 | case EINVAL: | - |
273 | return true; never executed: return true; | 0 |
274 | default: | - |
275 | return false; never executed: return false; | 0 |
276 | } | - |
277 | } | 0 |
278 | // If there are no attachments then remove it. | - |
279 | if (shmid_ds.shm_nattch == 0) { never evaluated: shmid_ds.shm_nattch == 0 | 0 |
280 | // mark for removal | - |
281 | if (-1 == shmctl(id, IPC_RMID, &shmid_ds)) { never evaluated: -1 == shmctl(id, 0, &shmid_ds) | 0 |
282 | setErrorString(QLatin1String("QSharedMemory::remove")); never executed (the execution status of this line is deduced): setErrorString(QLatin1String("QSharedMemory::remove")); | - |
283 | switch (errno) { | - |
284 | case EINVAL: | - |
285 | return true; never executed: return true; | 0 |
286 | default: | - |
287 | return false; never executed: return false; | 0 |
288 | } | - |
289 | } | 0 |
290 | | - |
291 | // remove file | - |
292 | if (!QFile::remove(nativeKey)) never evaluated: !QFile::remove(nativeKey) | 0 |
293 | return false; never executed: return false; | 0 |
294 | } | 0 |
295 | return true; never executed: return true; | 0 |
296 | } | - |
297 | | - |
298 | | - |
299 | QT_END_NAMESPACE | - |
300 | | - |
301 | #endif // QT_NO_SHAREDMEMORY | - |
302 | | - |
| | |