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; }
/*! \internal Setup unix_key */ key_t QSystemLockPrivate::handle() { if (key.isEmpty()) return -1; // ftok requires that an actual file exists somewhere // If we have already made at some point in the past, // double check that it is still there. if (-1 != unix_key) { int aNewunix_key = ftok(QFile::encodeName(fileName).constData(), 'Q'); if (aNewunix_key != unix_key) { cleanHandle(); } else { return unix_key; } } // Create the file needed for ftok #if defined(Q_OS_SYMBIAN) int built = createUnixKeyFile(fileName); #else int built = QSharedMemoryPrivate::createUnixKeyFile(fileName); #endif if (-1 == built) return -1; createdFile = (1 == built); // Get the unix key for the created file unix_key = ftok(QFile::encodeName(fileName).constData(), 'Q'); if (-1 == unix_key) { setErrorString(QLatin1String("QSystemLock::handle ftok")); return -1; } // Get semaphore semaphore = semget(unix_key, 1, 0666 | IPC_CREAT | IPC_EXCL); if (-1 == semaphore) { if (errno == EEXIST) semaphore = semget(unix_key, 1, 0666 | IPC_CREAT); if (-1 == semaphore) { setErrorString(QLatin1String("QSystemLock::handle semget")); cleanHandle(); return -1; } } else { // Created semaphore, initialize value. createdSemaphore = true; qt_semun init_op; init_op.val = MAX_LOCKS; if (-1 == semctl(semaphore, 0, SETVAL, init_op)) { setErrorString(QLatin1String("QSystemLock::handle semctl")); cleanHandle(); return -1; } } return unix_key; }
/*! \internal */ bool QSystemSemaphorePrivate::modifySemaphore(int count) { if (-1 == handle()) return false; struct sembuf operation; operation.sem_num = 0; operation.sem_op = count; operation.sem_flg = SEM_UNDO; int res; EINTR_LOOP(res, semop(semaphore, &operation, 1)); if (-1 == res) { // If the semaphore was removed be nice and create it and then modifySemaphore again if (errno == EINVAL || errno == EIDRM) { semaphore = -1; cleanHandle(); handle(); return modifySemaphore(count); } setErrorString(QLatin1String("QSystemSemaphore::modifySemaphore")); #if defined QSYSTEMSEMAPHORE_DEBUG qDebug() << QLatin1String("QSystemSemaphore::modify failed") << count << semctl(semaphore, 0, GETVAL) << errno << EIDRM << EINVAL; #endif return false; } clearError(); return true; }
bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode) { // Grab a pointer to the memory block int permissions = (mode == QSharedMemory::ReadOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS); #if defined(Q_OS_WINPHONE) Q_UNIMPLEMENTED(); Q_UNUSED(mode) memory = 0; #elif defined(Q_OS_WINRT) memory = (void *)MapViewOfFileFromApp(handle(), permissions, 0, 0); #else memory = (void *)MapViewOfFile(handle(), permissions, 0, 0, 0); #endif if (0 == memory) { setErrorString(QLatin1String("QSharedMemory::attach")); cleanHandle(); return false; } // Grab the size of the memory we have been given (a multiple of 4K on windows) MEMORY_BASIC_INFORMATION info; if (!VirtualQuery(memory, &info, sizeof(info))) { // Windows doesn't set an error code on this one, // it should only be a kernel memory error. error = QSharedMemory::UnknownError; errorString = QSharedMemory::tr("%1: size query failed").arg(QLatin1String("QSharedMemory::attach: ")); return false; } size = info.RegionSize; return true; }
bool QSharedMemoryPrivate::detach() { // umap memory if (!UnmapViewOfFile(memory)) { setErrorString(QLatin1String("QSharedMemory::detach")); return false; } memory = 0; // close handle return cleanHandle(); }
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; }
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; size = 0; // Get the number of current attachments int id = shmget(unix_key, 0, 0444); cleanHandle(); 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 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::detach() { // umap memory #if defined(Q_OS_WINPHONE) Q_UNIMPLEMENTED(); return false; #else if (!UnmapViewOfFile(memory)) { setErrorString(QLatin1String("QSharedMemory::detach")); return false; } #endif memory = 0; size = 0; // close handle return cleanHandle(); }
bool QSharedMemoryPrivate::initKey() { if (!cleanHandle()) return false; #ifndef QT_NO_SYSTEMSEMAPHORE systemSemaphore.setKey(QString(), 1); systemSemaphore.setKey(key, 1); if (systemSemaphore.error() != QSystemSemaphore::NoError) { QString function = QLatin1String("QSharedMemoryPrivate::initKey"); errorString = QSharedMemory::tr("%1: unable to set key on lock").arg(function); switch(systemSemaphore.error()) { case QSystemSemaphore::PermissionDenied: error = QSharedMemory::PermissionDenied; break; case QSystemSemaphore::KeyError: error = QSharedMemory::KeyError; break; case QSystemSemaphore::AlreadyExists: error = QSharedMemory::AlreadyExists; break; case QSystemSemaphore::NotFound: error = QSharedMemory::NotFound; break; case QSystemSemaphore::OutOfResources: error = QSharedMemory::OutOfResources; break; case QSystemSemaphore::UnknownError: default: error = QSharedMemory::UnknownError; break; } return false; } #endif errorString = QString(); error = QSharedMemory::NoError; return true; }
QT_BEGIN_NAMESPACE /*! \internal Setup unix_key */ key_t QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode) { if (key.isEmpty()){ errorString = QCoreApplication::tr("%1: key is empty", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle:")); error = QSystemSemaphore::KeyError; return -1; } // ftok requires that an actual file exists somewhere if (-1 != unix_key) return unix_key; // Create the file needed for ftok int built = QSharedMemoryPrivate::createUnixKeyFile(fileName); if (-1 == built) { errorString = QCoreApplication::tr("%1: unable to make key", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle:")); error = QSystemSemaphore::KeyError; return -1; } createdFile = (1 == built); // Get the unix key for the created file unix_key = qt_safe_ftok(QFile::encodeName(fileName), 'Q'); if (-1 == unix_key) { errorString = QCoreApplication::tr("%1: ftok failed", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle:")); error = QSystemSemaphore::KeyError; return -1; } // Get semaphore semaphore = semget(unix_key, 1, 0600 | IPC_CREAT | IPC_EXCL); if (-1 == semaphore) { if (errno == EEXIST) semaphore = semget(unix_key, 1, 0600 | IPC_CREAT); if (-1 == semaphore) { setErrorString(QLatin1String("QSystemSemaphore::handle")); cleanHandle(); return -1; } } else { createdSemaphore = true; // Force cleanup of file, it is possible that it can be left over from a crash createdFile = true; } if (mode == QSystemSemaphore::Create) { createdSemaphore = true; createdFile = true; } // Created semaphore so initialize its value. if (createdSemaphore && initialValue >= 0) { qt_semun init_op; init_op.val = initialValue; if (-1 == semctl(semaphore, 0, SETVAL, init_op)) { setErrorString(QLatin1String("QSystemSemaphore::handle")); cleanHandle(); return -1; } } return unix_key; }
/*! \internal */ bool QSystemSemaphorePrivate::modifySemaphore(int count) { #ifndef QT_POSIX_IPC if (-1 == handle()) return false; struct sembuf operation; operation.sem_num = 0; operation.sem_op = count; operation.sem_flg = SEM_UNDO; register int res; EINTR_LOOP(res, semop(semaphore, &operation, 1)); if (-1 == res) { // If the semaphore was removed be nice and create it and then modifySemaphore again if (errno == EINVAL || errno == EIDRM) { semaphore = -1; cleanHandle(); handle(); return modifySemaphore(count); } setErrorString(QLatin1String("QSystemSemaphore::modifySemaphore")); #ifdef QSYSTEMSEMAPHORE_DEBUG qDebug() << QLatin1String("QSystemSemaphore::modify failed") << count << semctl(semaphore, 0, GETVAL) << errno << EIDRM << EINVAL; #endif return false; } #else if (!handle()) return false; if (count > 0) { int cnt = count; do { if (sem_post(semaphore) == -1) { setErrorString(QLatin1String("QSystemSemaphore::modifySemaphore (sem_post)")); #ifdef QSYSTEMSEMAPHORE_DEBUG qDebug() << QLatin1String("QSystemSemaphore::modify sem_post failed") << count << errno; #endif // rollback changes to preserve the SysV semaphore behavior for ( ; cnt < count; ++cnt) { register int res; EINTR_LOOP(res, sem_wait(semaphore)); } return false; } --cnt; } while (cnt > 0); } else { register int res; EINTR_LOOP(res, sem_wait(semaphore)); if (res == -1) { // If the semaphore was removed be nice and create it and then modifySemaphore again if (errno == EINVAL || errno == EIDRM) { semaphore = SEM_FAILED; return modifySemaphore(count); } setErrorString(QLatin1String("QSystemSemaphore::modifySemaphore (sem_wait)")); #ifdef QSYSTEMSEMAPHORE_DEBUG qDebug() << QLatin1String("QSystemSemaphore::modify sem_wait failed") << count << errno; #endif return false; } } #endif // QT_POSIX_IPC return true; }