bool QSharedMemoryPrivate::create(int size) { // Get a windows acceptable key QString safeKey = makePlatformSafeKey(key); QString function = QLatin1String("QSharedMemory::create"); if (safeKey.isEmpty()) { error = QSharedMemory::KeyError; errorString = QSharedMemory::tr("%1: key error").arg(function); return false; } TPtrC ptr(qt_QString2TPtrC(safeKey)); TInt err = chunk.CreateGlobal(ptr, size, size); setErrorString(function, err); if (err != KErrNone) return false; // Zero out the created chunk Mem::FillZ(chunk.Base(), chunk.Size()); return true; }
bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode /* mode */) { // Grab a pointer to the memory block if (!chunk.Handle()) { QString function = QLatin1String("QSharedMemory::handle"); QString safeKey = makePlatformSafeKey(key); if (safeKey.isEmpty()) { error = QSharedMemory::KeyError; errorString = QSharedMemory::tr("%1: unable to make key").arg(function); return false; } TPtrC ptr(qt_QString2TPtrC(safeKey)); TInt err = KErrNoMemory; err = chunk.OpenGlobal(ptr, false); if (err != KErrNone) { setErrorString(function, err); return false; } } size = chunk.Size(); memory = chunk.Base(); return true; }
/*! \internal If not already made create the handle used for accessing the shared memory. */ key_t QSharedMemoryPrivate::handle() { // already made if (unix_key) return unix_key; // don't allow making handles on empty keys if (key.isEmpty()) { errorString = QSharedMemory::tr("%1: key is empty").arg(QLatin1String("QSharedMemory::handle:")); error = QSharedMemory::KeyError; return 0; } // ftok requires that an actual file exists somewhere QString fileName = makePlatformSafeKey(key); if (!QFile::exists(fileName)) { errorString = QSharedMemory::tr("%1: UNIX key file doesn't exist").arg(QLatin1String("QSharedMemory::handle:")); error = QSharedMemory::NotFound; return 0; } unix_key = ftok(QFile::encodeName(fileName).constData(), 'Q'); if (-1 == unix_key) { errorString = QSharedMemory::tr("%1: ftok failed").arg(QLatin1String("QSharedMemory::handle:")); error = QSharedMemory::KeyError; unix_key = 0; } return unix_key; }
bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode) { const QByteArray shmName = QFile::encodeName(makePlatformSafeKey(key)); const int oflag = (mode == QSharedMemory::ReadOnly ? O_RDONLY : O_RDWR); const mode_t omode = (mode == QSharedMemory::ReadOnly ? 0400 : 0600); #ifdef O_CLOEXEC // First try with O_CLOEXEC flag, if that fails, fall back to normal flags EINTR_LOOP(hand, ::shm_open(shmName.constData(), oflag | O_CLOEXEC, omode)); if (hand == -1) EINTR_LOOP(hand, ::shm_open(shmName.constData(), oflag, omode)); #else EINTR_LOOP(hand, ::shm_open(shmName.constData(), oflag, omode)); #endif if (hand == -1) { const int errorNumber = errno; const QLatin1String function("QSharedMemory::attach (shm_open)"); switch (errorNumber) { case ENAMETOOLONG: case EINVAL: errorString = QSharedMemory::tr("%1: bad name").arg(function); error = QSharedMemory::KeyError; break; default: setErrorString(function); } hand = -1; return false; } // grab the size QT_STATBUF st; if (QT_FSTAT(hand, &st) == -1) { setErrorString(QLatin1String("QSharedMemory::attach (fstat)")); cleanHandle(); return false; } size = st.st_size; // grab the memory const int mprot = (mode == QSharedMemory::ReadOnly ? PROT_READ : PROT_READ | PROT_WRITE); memory = QT_MMAP(0, size, mprot, MAP_SHARED, hand, 0); if (memory == MAP_FAILED || !memory) { setErrorString(QLatin1String("QSharedMemory::attach (mmap)")); cleanHandle(); memory = 0; size = 0; return false; } #ifdef F_ADD_SEALS // Make sure the shared memory region will not shrink // otherwise someone could cause SIGBUS on us. // (see http://lwn.net/Articles/594919/) fcntl(hand, F_ADD_SEALS, F_SEAL_SHRINK); #endif return true; }
bool QSharedMemoryPrivate::detach() { // detach from the memory segment if (-1 == shmdt(memory)) { QString function = QLatin1String("QSharedMemory::detach"); switch (errno) { case EINVAL: errorString = QSharedMemory::tr("%1: not attached").arg(function); error = QSharedMemory::NotFound; break; default: setErrorString(function); } return false; } memory = 0; // Get the number of current attachments if (!handle()) return false; int id = shmget(handle(), 0, 0444); unix_key = 0; struct shmid_ds shmid_ds; if (0 != shmctl(id, IPC_STAT, &shmid_ds)) { switch (errno) { case EINVAL: return true; default: return false; } } // If there are no attachments then remove it. if (shmid_ds.shm_nattch == 0) { // mark for removal struct shmid_ds shmid_ds; if (-1 == shmctl(id, IPC_RMID, &shmid_ds)) { setErrorString(QLatin1String("QSharedMemory::remove")); switch (errno) { case EINVAL: return true; default: return false; } } // remove file if (!QFile::remove(makePlatformSafeKey(key))) return false; } return true; }
bool QSharedMemoryPrivate::create(int size) { // build file if needed bool createdFile = false; int built = createUnixKeyFile(makePlatformSafeKey(key)); if (built == -1) { errorString = QSharedMemory::tr("%1: unable to make key").arg(QLatin1String("QSharedMemory::handle:")); error = QSharedMemory::KeyError; return false; } if (built == 1) { createdFile = true; } // get handle if (!handle()) { if (createdFile) QFile::remove(makePlatformSafeKey(key)); return false; } // create if (-1 == shmget(unix_key, size, 0666 | IPC_CREAT | IPC_EXCL)) { QString function = QLatin1String("QSharedMemory::create"); switch (errno) { case EINVAL: errorString = QSharedMemory::tr("%1: system-imposed size restrictions").arg(QLatin1String("QSharedMemory::handle")); error = QSharedMemory::InvalidSize; break; default: setErrorString(function); } if (createdFile && error != QSharedMemory::AlreadyExists) QFile::remove(makePlatformSafeKey(key)); return false; } return true; }
QT_BEGIN_NAMESPACE int QSharedMemoryPrivate::handle() { // don't allow making handles on empty keys const QString safeKey = makePlatformSafeKey(key); if (safeKey.isEmpty()) { errorString = QSharedMemory::tr("%1: key is empty").arg(QLatin1String("QSharedMemory::handle")); error = QSharedMemory::KeyError; return 0; } return 1; }
bool QSharedMemoryPrivate::create(int size) { if (!handle()) return false; const QByteArray shmName = QFile::encodeName(makePlatformSafeKey(key)); int fd; #ifdef O_CLOEXEC // First try with O_CLOEXEC flag, if that fails, fall back to normal flags EINTR_LOOP(fd, ::shm_open(shmName.constData(), O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0600)); if (fd == -1) EINTR_LOOP(fd, ::shm_open(shmName.constData(), O_RDWR | O_CREAT | O_EXCL, 0600)); #else EINTR_LOOP(fd, ::shm_open(shmName.constData(), O_RDWR | O_CREAT | O_EXCL, 0600)); #endif if (fd == -1) { const int errorNumber = errno; const QLatin1String function("QSharedMemory::attach (shm_open)"); switch (errorNumber) { case ENAMETOOLONG: case EINVAL: errorString = QSharedMemory::tr("%1: bad name").arg(function); error = QSharedMemory::KeyError; break; default: setErrorString(function); } return false; } // the size may only be set once int ret; EINTR_LOOP(ret, QT_FTRUNCATE(fd, size)); if (ret == -1) { setErrorString(QLatin1String("QSharedMemory::create (ftruncate)")); qt_safe_close(fd); return false; } qt_safe_close(fd); return true; }
bool QSharedMemoryPrivate::create(int size) { // Get a windows acceptable key QString safeKey = makePlatformSafeKey(key); QString function = QLatin1String("QSharedMemory::create"); if (safeKey.isEmpty()) { error = QSharedMemory::KeyError; errorString = QSharedMemory::tr("%1: key error").arg(function); return false; } // Create the file mapping. hand = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, size, (wchar_t*)safeKey.utf16()); setErrorString(function); // hand is valid when it already exists unlike unix so explicitly check if (error == QSharedMemory::AlreadyExists || !hand) return false; return true; }
bool QSharedMemoryPrivate::detach() { // detach from the memory segment if (::munmap(memory, size) == -1) { setErrorString(QLatin1String("QSharedMemory::detach (munmap)")); return false; } memory = 0; size = 0; #ifdef Q_OS_QNX // On QNX the st_nlink field of struct stat contains the number of // active shm_open() connections to the shared memory file, so we // can use it to automatically clean up the file once the last // user has detached from it. // 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; } cleanHandle(); // if there are no attachments then unlink the shared memory if (shm_nattch == 0) { const QByteArray shmName = QFile::encodeName(makePlatformSafeKey(key)); if (::shm_unlink(shmName.constData()) == -1 && errno != ENOENT) setErrorString(QLatin1String("QSharedMemory::detach (shm_unlink)")); } #else // On non-QNX systems (tested Linux and Haiku), the st_nlink field is always 1, // so we'll simply leak the shared memory files. cleanHandle(); #endif return true; }
HANDLE QSharedMemoryPrivate::handle() { if (!hand) { QString function = QLatin1String("QSharedMemory::handle"); QString safeKey = makePlatformSafeKey(key); if (safeKey.isEmpty()) { error = QSharedMemory::KeyError; errorString = QSharedMemory::tr("%1: unable to make key").arg(function); return false; } #ifndef Q_OS_WINCE hand = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, (wchar_t*)safeKey.utf16()); #else // This works for opening a mapping too, but always opens it with read/write access in // attach as it seems. hand = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, 0, (wchar_t*)safeKey.utf16()); #endif if (!hand) { setErrorString(function); return false; } } return hand; }