From 96995db4af6e1f5e9fe313e4c71a41fd939fedf8 Mon Sep 17 00:00:00 2001 From: Tobias Koenig Date: Mon, 22 Dec 2014 11:24:41 +0100 Subject: Add POSIX IPC support to QSystemSemaphore and QSharedMemory This patch is a forward-port from 4.8 branch (d869e1ad4b0007757e97046609de2097cd9e9c5d). Change-Id: I6ae36a5417d1176fbecf775668f6033b1cb22a94 Reviewed-by: Konstantin Ritt Reviewed-by: Thiago Macieira --- src/corelib/kernel/qsystemsemaphore_posix.cpp | 182 ++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 src/corelib/kernel/qsystemsemaphore_posix.cpp (limited to 'src/corelib/kernel/qsystemsemaphore_posix.cpp') diff --git a/src/corelib/kernel/qsystemsemaphore_posix.cpp b/src/corelib/kernel/qsystemsemaphore_posix.cpp new file mode 100644 index 0000000000..1ee643a6ab --- /dev/null +++ b/src/corelib/kernel/qsystemsemaphore_posix.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Konstantin Ritt +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias Koenig +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsystemsemaphore.h" +#include "qsystemsemaphore_p.h" + +#include +#include +#include + +#ifdef QT_POSIX_IPC + +#ifndef QT_NO_SYSTEMSEMAPHORE + +#include +#include +#include +#include +#include + +#include "private/qcore_unix_p.h" + +// OpenBSD 4.2 doesn't define EIDRM, see BUGS section: +// http://www.openbsd.org/cgi-bin/man.cgi?query=semop&manpath=OpenBSD+4.2 +#if defined(Q_OS_OPENBSD) && !defined(EIDRM) +#define EIDRM EINVAL +#endif + +QT_BEGIN_NAMESPACE + +bool QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode) +{ + if (semaphore != SEM_FAILED) + return true; // we already have a semaphore + + if (fileName.isEmpty()) { + errorString = QCoreApplication::tr("%1: key is empty", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle")); + error = QSystemSemaphore::KeyError; + return false; + } + + const QByteArray semName = QFile::encodeName(fileName); + + // Always try with O_EXCL so we know whether we created the semaphore. + int oflag = O_CREAT | O_EXCL; + for (int tryNum = 0, maxTries = 1; tryNum < maxTries; ++tryNum) { + do { + semaphore = ::sem_open(semName.constData(), oflag, 0600, initialValue); + } while (semaphore == SEM_FAILED && errno == EINTR); + if (semaphore == SEM_FAILED && errno == EEXIST) { + if (mode == QSystemSemaphore::Create) { + if (::sem_unlink(semName.constData()) == -1 && errno != ENOENT) { + setErrorString(QLatin1String("QSystemSemaphore::handle (sem_unlink)")); + return false; + } + // Race condition: the semaphore might be recreated before + // we call sem_open again, so we'll retry several times. + maxTries = 3; + } else { + // Race condition: if it no longer exists at the next sem_open + // call, we won't realize we created it, so we'll leak it later. + oflag &= ~O_EXCL; + maxTries = 2; + } + } else { + break; + } + } + + if (semaphore == SEM_FAILED) { + setErrorString(QLatin1String("QSystemSemaphore::handle")); + return false; + } + + createdSemaphore = (oflag & O_EXCL) != 0; + + return true; +} + +void QSystemSemaphorePrivate::cleanHandle() +{ + if (semaphore != SEM_FAILED) { + if (::sem_close(semaphore) == -1) { + setErrorString(QLatin1String("QSystemSemaphore::cleanHandle (sem_close)")); +#if defined QSYSTEMSEMAPHORE_DEBUG + qDebug() << QLatin1String("QSystemSemaphore::cleanHandle sem_close failed."); +#endif + } + semaphore = SEM_FAILED; + } + + if (createdSemaphore) { + if (::sem_unlink(QFile::encodeName(fileName).constData()) == -1 && errno != ENOENT) { + setErrorString(QLatin1String("QSystemSemaphore::cleanHandle (sem_unlink)")); +#if defined QSYSTEMSEMAPHORE_DEBUG + qDebug() << QLatin1String("QSystemSemaphore::cleanHandle sem_unlink failed."); +#endif + } + createdSemaphore = false; + } +} + +bool QSystemSemaphorePrivate::modifySemaphore(int count) +{ + if (!handle()) + return false; + + if (count > 0) { + int cnt = count; + do { + if (::sem_post(semaphore) == -1) { + setErrorString(QLatin1String("QSystemSemaphore::modifySemaphore (sem_post)")); +#if defined QSYSTEMSEMAPHORE_DEBUG + qDebug() << QLatin1String("QSystemSemaphore::modify sem_post failed") << count << errno; +#endif + // rollback changes to preserve the SysV semaphore behavior + for ( ; cnt < count; ++cnt) { + int res; + EINTR_LOOP(res, ::sem_wait(semaphore)); + } + return false; + } + --cnt; + } while (cnt > 0); + } else { + 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)")); +#if defined QSYSTEMSEMAPHORE_DEBUG + qDebug() << QLatin1String("QSystemSemaphore::modify sem_wait failed") << count << errno; +#endif + return false; + } + } + + clearError(); + return true; +} + +QT_END_NAMESPACE + +#endif // QT_NO_SYSTEMSEMAPHORE + +#endif // QT_POSIX_IPC -- cgit v1.2.3