diff options
Diffstat (limited to 'src/gui/embedded/qwssharedmemory.cpp')
-rw-r--r-- | src/gui/embedded/qwssharedmemory.cpp | 89 |
1 files changed, 88 insertions, 1 deletions
diff --git a/src/gui/embedded/qwssharedmemory.cpp b/src/gui/embedded/qwssharedmemory.cpp index a677626..853de61 100644 --- a/src/gui/embedded/qwssharedmemory.cpp +++ b/src/gui/embedded/qwssharedmemory.cpp @@ -45,14 +45,37 @@ #include <sys/types.h> #include <sys/ipc.h> +#ifndef QT_POSIX_IPC #include <sys/shm.h> +#else +#include <sys/mman.h> +#include <sys/stat.h> +#endif +#include <fcntl.h> +#include <unistd.h> + +#include <private/qcore_unix_p.h> //#define QT_SHM_DEBUG QT_BEGIN_NAMESPACE +#ifdef QT_POSIX_IPC +#include <QtCore/QAtomicInt> + +static QBasicAtomicInt localUniqueId = Q_BASIC_ATOMIC_INITIALIZER(1); + +static inline QByteArray makeKey(int id) +{ + return "/qwsshm_" + QByteArray::number(id, 16); +} +#endif + QWSSharedMemory::QWSSharedMemory() : shmId(-1), shmBase(0), shmSize(0) +#ifdef QT_POSIX_IPC + , hand(-1) +#endif { } @@ -66,19 +89,47 @@ bool QWSSharedMemory::create(int size) if (shmId != -1) detach(); +#ifndef QT_POSIX_IPC shmId = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600); +#else + // ### generate really unique IDs + shmId = (getpid() << 16) + (localUniqueId.fetchAndAddRelaxed(1) % ushort(-1)); + QByteArray shmName = makeKey(shmId); + EINTR_LOOP(hand, shm_open(shmName.constData(), O_RDWR | O_CREAT, 0660)); + if (hand != -1) { + // the size may only be set once; ignore errors + int ret; + EINTR_LOOP(ret, ftruncate(hand, size)); + if (ret == -1) + shmId = -1; + } else { + shmId = -1; + } +#endif if (shmId == -1) { #ifdef QT_SHM_DEBUG perror("QWSSharedMemory::create():"); qWarning("Error allocating shared memory of size %d", size); #endif + detach(); return false; } + +#ifndef QT_POSIX_IPC shmBase = shmat(shmId, 0, 0); // On Linux, it is possible to attach a shared memory segment even if it // is already marked to be deleted. However, POSIX.1-2001 does not specify // this behaviour and many other implementations do not support it. shmctl(shmId, IPC_RMID, 0); +#else + // grab the size + QT_STATBUF st; + if (QT_FSTAT(hand, &st) != -1) { + shmSize = st.st_size; + // grab the memory + shmBase = mmap(0, shmSize, PROT_READ | PROT_WRITE, MAP_SHARED, hand, 0); + } +#endif if (shmBase == (void*)-1 || !shmBase) { #ifdef QT_SHM_DEBUG perror("QWSSharedMemory::create():"); @@ -102,7 +153,21 @@ bool QWSSharedMemory::attach(int id) return false; shmId = id; +#ifndef QT_POSIX_IPC shmBase = shmat(shmId, 0, 0); +#else + QByteArray shmName = makeKey(shmId); + EINTR_LOOP(hand, shm_open(shmName.constData(), O_RDWR, 0660)); + if (hand != -1) { + // grab the size + QT_STATBUF st; + if (QT_FSTAT(hand, &st) != -1) { + shmSize = st.st_size; + // grab the memory + shmBase = mmap(0, shmSize, PROT_READ | PROT_WRITE, MAP_SHARED, hand, 0); + } + } +#endif if (shmBase == (void*)-1 || !shmBase) { #ifdef QT_SHM_DEBUG perror("QWSSharedMemory::attach():"); @@ -117,8 +182,28 @@ bool QWSSharedMemory::attach(int id) void QWSSharedMemory::detach() { +#ifndef QT_POSIX_IPC if (shmBase && shmBase != (void*)-1) shmdt(shmBase); +#else + if (shmBase && shmBase != (void*)-1) + munmap(shmBase, shmSize); + if (hand > 0) { + // get the number of current attachments + int shm_nattch = 0; + QT_STATBUF st; + if (QT_FSTAT(hand, &st) == 0) { + // subtract 2 from linkcount: one for our own open and one for the dir entry + shm_nattch = st.st_nlink - 2; + } + qt_safe_close(hand); + // if there are no attachments then unlink the shared memory + if (shm_nattch == 0) { + QByteArray shmName = makeKey(shmId); + shm_unlink(shmName.constData()); + } + } +#endif shmBase = 0; shmSize = 0; shmId = -1; @@ -129,11 +214,13 @@ int QWSSharedMemory::size() const if (shmId == -1) return 0; +#ifndef QT_POSIX_IPC if (!shmSize) { struct shmid_ds shm; shmctl(shmId, IPC_STAT, &shm); - const_cast<QWSSharedMemory *>(this)->shmSize = shm.shm_segsz; + shmSize = shm.shm_segsz; } +#endif return shmSize; } |