Qt 4.8
qwssharedmemory.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui 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 "qwssharedmemory_p.h"
43 
44 #if !defined(QT_NO_QWS_MULTIPROCESS)
45 
46 #include <sys/types.h>
47 #include <sys/ipc.h>
48 #ifndef QT_POSIX_IPC
49 #include <sys/shm.h>
50 #else
51 #include <sys/mman.h>
52 #include <sys/stat.h>
53 #endif
54 #include <fcntl.h>
55 #include <unistd.h>
56 
57 #include <private/qcore_unix_p.h>
58 
59 //#define QT_SHM_DEBUG
60 
62 
63 #ifdef QT_POSIX_IPC
64 #include <QtCore/QAtomicInt>
65 #include <QByteArray>
66 
67 static QBasicAtomicInt localUniqueId = Q_BASIC_ATOMIC_INITIALIZER(1);
68 
69 static inline QByteArray makeKey(int id)
70 {
71  return "/qwsshm_" + QByteArray::number(id, 16);
72 }
73 #endif
74 
76  : shmId(-1), shmBase(0), shmSize(0)
77 #ifdef QT_POSIX_IPC
78  , hand(-1)
79 #endif
80 {
81 }
82 
84 {
85  detach();
86 }
87 
89 {
90  if (shmId != -1)
91  detach();
92 
93 #ifndef QT_POSIX_IPC
94  shmId = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600);
95 #else
96  // ### generate really unique IDs
97  shmId = (getpid() << 16) + (localUniqueId.fetchAndAddRelaxed(1) % ushort(-1));
98  QByteArray shmName = makeKey(shmId);
99  EINTR_LOOP(hand, shm_open(shmName.constData(), O_RDWR | O_CREAT, 0660));
100  if (hand != -1) {
101  // the size may only be set once; ignore errors
102  int ret;
103  EINTR_LOOP(ret, ftruncate(hand, size));
104  if (ret == -1)
105  shmId = -1;
106  } else {
107  shmId = -1;
108  }
109 #endif
110  if (shmId == -1) {
111 #ifdef QT_SHM_DEBUG
112  perror("QWSSharedMemory::create():");
113  qWarning("Error allocating shared memory of size %d", size);
114 #endif
115  detach();
116  return false;
117  }
118 
119 #ifndef QT_POSIX_IPC
120  shmBase = shmat(shmId, 0, 0);
121  // On Linux, it is possible to attach a shared memory segment even if it
122  // is already marked to be deleted. However, POSIX.1-2001 does not specify
123  // this behaviour and many other implementations do not support it.
124  shmctl(shmId, IPC_RMID, 0);
125 #else
126  // grab the size
127  QT_STATBUF st;
128  if (QT_FSTAT(hand, &st) != -1) {
129  shmSize = st.st_size;
130  // grab the memory
131  shmBase = mmap(0, shmSize, PROT_READ | PROT_WRITE, MAP_SHARED, hand, 0);
132  }
133 #endif
134  if (shmBase == (void*)-1 || !shmBase) {
135 #ifdef QT_SHM_DEBUG
136  perror("QWSSharedMemory::create():");
137  qWarning("Error attaching to shared memory id %d", shmId);
138 #endif
139  detach();
140  return false;
141  }
142 
143  return true;
144 }
145 
147 {
148  if (shmId == id)
149  return id != -1;
150 
151  detach();
152 
153  if (id == -1)
154  return false;
155 
156  shmId = id;
157 #ifndef QT_POSIX_IPC
158  shmBase = shmat(shmId, 0, 0);
159 #else
160  QByteArray shmName = makeKey(shmId);
161  EINTR_LOOP(hand, shm_open(shmName.constData(), O_RDWR, 0660));
162  if (hand != -1) {
163  // grab the size
164  QT_STATBUF st;
165  if (QT_FSTAT(hand, &st) != -1) {
166  shmSize = st.st_size;
167  // grab the memory
168  shmBase = mmap(0, shmSize, PROT_READ | PROT_WRITE, MAP_SHARED, hand, 0);
169  }
170  }
171 #endif
172  if (shmBase == (void*)-1 || !shmBase) {
173 #ifdef QT_SHM_DEBUG
174  perror("QWSSharedMemory::attach():");
175  qWarning("Error attaching to shared memory id %d", shmId);
176 #endif
177  detach();
178  return false;
179  }
180 
181  return true;
182 }
183 
185 {
186 #ifndef QT_POSIX_IPC
187  if (shmBase && shmBase != (void*)-1)
188  shmdt(shmBase);
189 #else
190  if (shmBase && shmBase != (void*)-1)
191  munmap(shmBase, shmSize);
192  if (hand > 0) {
193  // get the number of current attachments
194  int shm_nattch = 0;
195  QT_STATBUF st;
196  if (QT_FSTAT(hand, &st) == 0) {
197  // subtract 2 from linkcount: one for our own open and one for the dir entry
198  shm_nattch = st.st_nlink - 2;
199  }
200  qt_safe_close(hand);
201  // if there are no attachments then unlink the shared memory
202  if (shm_nattch == 0) {
203  QByteArray shmName = makeKey(shmId);
204  shm_unlink(shmName.constData());
205  }
206  }
207 #endif
208  shmBase = 0;
209  shmSize = 0;
210  shmId = -1;
211 }
212 
214 {
215  if (shmId == -1)
216  return 0;
217 
218 #ifndef QT_POSIX_IPC
219  if (!shmSize) {
220  struct shmid_ds shm;
221  shmctl(shmId, IPC_STAT, &shm);
222  shmSize = shm.shm_segsz;
223  }
224 #endif
225 
226  return shmSize;
227 }
228 
230 
231 #endif // QT_NO_QWS_MULTIPROCESS
bool create(int size)
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
#define EINTR_LOOP(var, cmd)
Definition: qcore_unix_p.h:96
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
static int qt_safe_close(int fd)
Definition: qcore_unix_p.h:297
#define Q_BASIC_ATOMIC_INITIALIZER(a)
Definition: qbasicatomic.h:218
#define O_CREAT
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
Q_CORE_EXPORT void qWarning(const char *,...)
bool attach(int id)
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
unsigned short ushort
Definition: qglobal.h:995
#define st(var, type, card)
#define O_RDWR
static QByteArray number(int, int base=10)
Returns a byte array containing the string equivalent of the number n to base base (10 by default)...