Hi all,

it's not clear to me whether our licensing policy allows exceptions or not.

https://community.kde.org/Policies/Licensing_Policy does not mention any 
exceptions.

https://community.kde.org/Guidelines_and_HOWTOs/Licensing explains how to use 
exceptions and gives an example with the Qt-LGPL-exception-1.1.

I have copied code from GCC's STL to implement a QMutex-compatible replacement 
for std::unique_lock (because apparently Windows resp. mingw doesn't have 
std::mutex). GCC's code is "GPL-3.0-or-later WITH GCC-exception-3.1". (Ignore 
the bogus license id in the .cpp file. I've already fixed it.) Therefore I've 
put my Qt'ified copy under the same license.

What now? Did I violate our licensing policy? Should we explicitly add allowed 
exceptions to our licensing policy? I guess we don't want to allow all 
exceptions listed at https://spdx.org/licenses/exceptions-index.html.

Regards,
Ingo
--- Begin Message ---
Git commit bd610f307dcd08be0e08007b483002f7c4df24ca by Ingo Klöcker.
Committed on 25/11/2021 at 11:01.
Pushed by kloecker into branch 'master'.

Add a QMutex-compatible replacement for std::unique_lock

M  +3    -0    src/CMakeLists.txt
A  +149  -0    src/utils/uniquelock.cpp  *
A  +135  -0    src/utils/uniquelock.h  *

The files marked with a * at the end have a non valid license. Please read: 
https://community.kde.org/Policies/Licensing_Policy and use the headers which 
are listed at that page.


https://invent.kde.org/pim/libkleo/commit/bd610f307dcd08be0e08007b483002f7c4df24ca

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 561e618..d871dd3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -103,6 +103,8 @@ target_sources(KF5Libkleo PRIVATE
    utils/stringutils.h
    utils/test.cpp
    utils/test.h
+   utils/uniquelock.cpp
+   utils/uniquelock.h
    )
 ecm_qt_declare_logging_category(KF5Libkleo HEADER libkleo_debug.h IDENTIFIER 
LIBKLEO_LOG CATEGORY_NAME org.kde.pim.libkleo
         DESCRIPTION "libkleo (kleo_core)"
@@ -255,6 +257,7 @@ ecm_generate_headers(libkleo_CamelCase_utils_HEADERS
   SCDaemon
   StringUtils
   Test
+  UniqueLock
   REQUIRED_HEADERS libkleo_utils_HEADERS
   PREFIX Libkleo
   RELATIVE utils
diff --git a/src/utils/uniquelock.cpp b/src/utils/uniquelock.cpp
new file mode 100644
index 0000000..de462cf
--- /dev/null
+++ b/src/utils/uniquelock.cpp
@@ -0,0 +1,149 @@
+/*
+    utils/uniquelock.cpp
+    QMutex-compatible replacement for std::UniqueLock
+
+    This file is part of libkleopatra, the KDE keymanagement library
+    SPDX-FileCopyrightText: 2008-2021 Free Software Foundation, Inc.
+    SPDX-FileCopyrightText: 2021 g10 Code GmbH
+    SPDX-FileContributor: Ingo Klöcker <[email protected]>
+
+    SPDX-License-Identifier: GPL-3.0-or-later+GCC Runtime Library Exception
+*/
+
+#include <config-libkleo.h>
+
+#include "uniquelock.h"
+
+#include <libkleo_debug.h>
+
+#include <QDebug>
+
+namespace Kleo
+{
+
+UniqueLock::UniqueLock() noexcept
+    : mMutex{nullptr}, mOwnsMutex{false}
+{
+}
+
+UniqueLock::UniqueLock(QMutex &mutex)
+    : mMutex{std::addressof(mutex)}, mOwnsMutex{false}
+{
+    lock();
+    mOwnsMutex = true;
+}
+
+UniqueLock::UniqueLock(QMutex &mutex, DeferLockType) noexcept
+    : mMutex{std::addressof(mutex)}, mOwnsMutex{false}
+{
+}
+
+UniqueLock::UniqueLock(QMutex &mutex, TryToLockType)
+    : mMutex{std::addressof(mutex)}, mOwnsMutex{mMutex->try_lock()}
+{
+}
+
+UniqueLock::UniqueLock(QMutex &mutex, AdoptLockType) noexcept
+    : mMutex{std::addressof(mutex)}, mOwnsMutex{true}
+{
+    // XXX calling thread owns mutex
+}
+
+UniqueLock::~UniqueLock()
+{
+    if (mOwnsMutex) {
+        unlock();
+    }
+}
+
+UniqueLock::UniqueLock(UniqueLock &&u) noexcept
+    : mMutex{u.mMutex}, mOwnsMutex{u.mOwnsMutex}
+{
+    u.mMutex = nullptr;
+    u.mOwnsMutex = false;
+}
+
+UniqueLock &UniqueLock::operator=(UniqueLock &&u) noexcept
+{
+    if(mOwnsMutex) {
+        unlock();
+    }
+
+    UniqueLock(std::move(u)).swap(*this);
+
+    u.mMutex = nullptr;
+    u.mOwnsMutex = false;
+
+    return *this;
+}
+
+void UniqueLock::lock()
+{
+    Q_ASSERT(mMutex);
+    Q_ASSERT(!mOwnsMutex);
+    if (!mMutex) {
+        qCWarning(LIBKLEO_LOG) << __func__ << "Error: operation not permitted";
+    } else if (mOwnsMutex) {
+        qCWarning(LIBKLEO_LOG) << __func__ << "Error: resource deadlock would 
occur";
+    } else {
+        mMutex->lock();
+        mOwnsMutex = true;
+    }
+}
+
+bool UniqueLock::try_lock()
+{
+    Q_ASSERT(mMutex);
+    Q_ASSERT(!mOwnsMutex);
+    if (!mMutex) {
+        qCWarning(LIBKLEO_LOG) << __func__ << "Error: operation not permitted";
+        return false;
+    } else if (mOwnsMutex) {
+        qCWarning(LIBKLEO_LOG) << __func__ << "Error: resource deadlock would 
occur";
+        return false;
+    } else {
+        mOwnsMutex = mMutex->try_lock();
+        return mOwnsMutex;
+    }
+}
+
+void UniqueLock::unlock()
+{
+    if (!mOwnsMutex) {
+        qCWarning(LIBKLEO_LOG) << __func__ << "Error: operation not permitted";
+    } else if (mMutex) {
+        mMutex->unlock();
+        mOwnsMutex = false;
+    }
+}
+
+void UniqueLock::swap(UniqueLock &u) noexcept
+{
+    std::swap(mMutex, u.mMutex);
+    std::swap(mOwnsMutex, u.mOwnsMutex);
+}
+
+QMutex *UniqueLock::release() noexcept
+{
+    QMutex *ret = mMutex;
+    mMutex = nullptr;
+    mOwnsMutex = false;
+    return ret;
+}
+
+bool UniqueLock::owns_lock() const noexcept
+{
+    return mOwnsMutex;
+}
+
+UniqueLock::operator bool() const noexcept
+{
+    return owns_lock();
+}
+
+QMutex *UniqueLock::mutex() const noexcept
+{
+    return mMutex;
+}
+
+} // namespace Kleo
diff --git a/src/utils/uniquelock.h b/src/utils/uniquelock.h
new file mode 100644
index 0000000..9ad1a42
--- /dev/null
+++ b/src/utils/uniquelock.h
@@ -0,0 +1,135 @@
+/*
+    utils/uniquelock.h
+    QMutex-compatible replacement for std::unique_lock
+
+    This file is part of libkleopatra, the KDE keymanagement library
+    SPDX-FileCopyrightText: 2008-2021 Free Software Foundation, Inc.
+    SPDX-FileCopyrightText: 2021 g10 Code GmbH
+    SPDX-FileContributor: Ingo Klöcker <[email protected]>
+
+    SPDX-License-Identifier: GPL-3.0-or-later WITH GCC-exception-3.1
+*/
+
+#pragma once
+
+#include "kleo_export.h"
+
+#include <QtGlobal>
+#include <QMutex>
+
+#include <chrono>
+#include <memory>
+
+namespace Kleo
+{
+
+/// Do not acquire ownership of the mutex.
+struct DeferLockType { explicit DeferLockType() = default; };
+
+/// Try to acquire ownership of the mutex without blocking.
+struct TryToLockType { explicit TryToLockType() = default; };
+
+/// Assume the calling thread has already obtained mutex ownership
+/// and manage it.
+struct AdoptLockType { explicit AdoptLockType() = default; };
+
+/// Tag used to prevent a scoped lock from acquiring ownership of a mutex.
+inline constexpr DeferLockType deferLock { };
+
+/// Tag used to prevent a scoped lock from blocking if a mutex is locked.
+inline constexpr TryToLockType tryToLock { };
+
+/// Tag used to make a scoped lock take ownership of a locked mutex.
+inline constexpr AdoptLockType adoptLock { };
+
+/** @brief A movable scoped lock type for QMutex.
+ *
+ * A UniqueLock controls mutex ownership within a scope. Ownership of the
+ * mutex can be delayed until after construction and can be transferred
+ * to another UniqueLock by move construction or move assignment. If a
+ * mutex lock is owned when the destructor runs ownership will be released.
+ */
+class KLEO_EXPORT UniqueLock
+{
+public:
+    UniqueLock() noexcept;
+    explicit UniqueLock(QMutex &mutex);
+
+    UniqueLock(QMutex &mutex, DeferLockType) noexcept;
+    UniqueLock(QMutex &mutex, TryToLockType);
+    UniqueLock(QMutex &mutex, AdoptLockType) noexcept;
+
+    template<typename Clock, typename Duration>
+    UniqueLock(QMutex &mutex, const std::chrono::time_point<Clock, Duration> 
&timePoint)
+        : mMutex{std::addressof(mutex)}
+        , mOwnsMutex{mMutex->try_lock_until(timePoint)}
+    {
+    }
+
+    template<typename Rep, typename Period>
+    UniqueLock(QMutex &mutex, const std::chrono::duration<Rep, Period> 
&duration)
+        : mMutex{std::addressof(mutex)}
+        , mOwnsMutex{mMutex->try_lock_for(duration)}
+    {
+    }
+
+    ~UniqueLock();
+
+    UniqueLock(const UniqueLock &) = delete;
+    UniqueLock &operator=(const UniqueLock &) = delete;
+
+    UniqueLock(UniqueLock &&u) noexcept;
+    UniqueLock &operator=(UniqueLock &&u) noexcept;
+
+    void lock();
+
+    bool try_lock();
+
+    template<typename Clock, typename Duration>
+    bool try_lock_until(const std::chrono::time_point<Clock, Duration> 
&timePoint)
+    {
+        Q_ASSERT(mMutex);
+        Q_ASSERT(!mOwnsMutex);
+        if (mMutex && !mOwnsMutex) {
+            mOwnsMutex = mMutex->try_lock_until(timePoint);
+            return mOwnsMutex;
+        }
+    }
+
+    template<typename Rep, typename Period>
+    bool try_lock_for(const std::chrono::duration<Rep, Period> &duration)
+    {
+        Q_ASSERT(mMutex);
+        Q_ASSERT(!mOwnsMutex);
+        if (mMutex && !mOwnsMutex) {
+            mOwnsMutex = mMutex->try_lock_for(duration);
+            return mOwnsMutex;
+        }
+    }
+
+    void unlock();
+
+    void swap(UniqueLock &u) noexcept;
+
+    QMutex *release() noexcept;
+
+    bool owns_lock() const noexcept;
+
+    explicit operator bool() const noexcept;
+
+    QMutex *mutex() const noexcept;
+
+private:
+    QMutex *mMutex;
+    bool    mOwnsMutex;
+};
+
+} // namespace Kleo
+
+namespace std {
+
+/// Swap overload for UniqueLock objects.
+/// @relates UniqueLock
+inline void swap(Kleo::UniqueLock &x, Kleo::UniqueLock &y) noexcept { 
x.swap(y); }
+
+}



--- End Message ---

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to