Exemple #1
0
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();
}
Exemple #6
0
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;
}
Exemple #7
0
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;
}