{"id":14902,"url":"https://patchwork.libcamera.org/api/patches/14902/?format=json","web_url":"https://patchwork.libcamera.org/patch/14902/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20211130155600.2203123-6-hiroh@chromium.org>","date":"2021-11-30T15:55:53","name":"[libcamera-devel,v3,05/12] libcamera: base: Add mutex classes with thread safety annotations","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"73a13e7ef3dea4037375a6c0fcfcdff6ad1b9dcb","submitter":{"id":63,"url":"https://patchwork.libcamera.org/api/people/63/?format=json","name":"Hirokazu Honda","email":"hiroh@chromium.org"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/14902/mbox/","series":[{"id":2785,"url":"https://patchwork.libcamera.org/api/series/2785/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=2785","date":"2021-11-30T15:55:48","name":"Introduce clang thread safety annotations","version":3,"mbox":"https://patchwork.libcamera.org/series/2785/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/14902/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/14902/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 45C51BF415\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 30 Nov 2021 15:56:24 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 018506072C;\n\tTue, 30 Nov 2021 16:56:24 +0100 (CET)","from mail-pj1-x1029.google.com (mail-pj1-x1029.google.com\n\t[IPv6:2607:f8b0:4864:20::1029])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A778C60721\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 30 Nov 2021 16:56:17 +0100 (CET)","by mail-pj1-x1029.google.com with SMTP id\n\tj5-20020a17090a318500b001a6c749e697so14095491pjb.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 30 Nov 2021 07:56:17 -0800 (PST)","from hiroh2.tok.corp.google.com\n\t([2401:fa00:8f:203:c90a:5a53:b139:1336])\n\tby smtp.gmail.com with ESMTPSA id\n\tpc10sm3510283pjb.9.2021.11.30.07.56.14\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tTue, 30 Nov 2021 07:56:15 -0800 (PST)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=chromium.org header.i=@chromium.org\n\theader.b=\"gimMj3GU\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org;\n\ts=google; \n\th=from:to:cc:subject:date:message-id:in-reply-to:references\n\t:mime-version:content-transfer-encoding;\n\tbh=AAc/KAYnNTACC5cCKhDfWsaHmWoRqjF3AfvdOey73Xk=;\n\tb=gimMj3GUVwJXigxBhYuAFj7Ak867vEEmM20+zmSiewdMRQ5tdsH9c2KCle4wTY2mYM\n\tCbcSYH8OO6XYAwJ623ZEEYpc8As5MCEBWBbNPQjZgkZc0BdreqhCaQAi+KnqrwoZnjpi\n\t92pwW6q/pbhOpSnCNvxscUHDvkY6EYWxXzwE8=","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20210112;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references:mime-version:content-transfer-encoding;\n\tbh=AAc/KAYnNTACC5cCKhDfWsaHmWoRqjF3AfvdOey73Xk=;\n\tb=3sK+a9zlB8BND82TPyjxWU20fWUByjyxJ61DQU2wc5z0brAvQRZ6R8xH4YdVmOm/e9\n\t82j2QmuV2m7gUUS+XY2BTlwja6c58UPxyXAuRQ746Er+kyR1Q9MtAtkk38kAWgfXRA32\n\tFyp/b/jIgkEL203R8SPGOJWHBgh1mumFV01+uBJB4QIE5mjzaYhoxCwW7gJdub3gufFp\n\tpfWBSINLGh1YpiPP835LZ7NRZHZHmpcv0QtpqSoAWUmQ5vc5CDQAASVu731uulSjx0fS\n\t8USaQ66+IiWoIjSciKOPcm6RdBIVjhEiaGzN9UA1qMvnwRMtS4u6RLLmPARTSHVAh+dd\n\tXqzQ==","X-Gm-Message-State":"AOAM533PYFu/UdJCPOW8fu359o8k1y0xGYX01yDzJJlvLYqbUw8XtlM0\n\tZzebQ9qSl9axEnfuxsdE36VsmFrrYyy8Sg==","X-Google-Smtp-Source":"ABdhPJzsZVdZgQjRb420INIYgioxYUGFUzHh92MIOuAz/hIn9wxTZAZUPZscDNQnzVdif9Hf/7et7g==","X-Received":"by 2002:a17:90b:230c:: with SMTP id\n\tmt12mr285357pjb.63.1638287775909; \n\tTue, 30 Nov 2021 07:56:15 -0800 (PST)","From":"Hirokazu Honda <hiroh@chromium.org>","To":"libcamera-devel@lists.libcamera.org","Date":"Wed,  1 Dec 2021 00:55:53 +0900","Message-Id":"<20211130155600.2203123-6-hiroh@chromium.org>","X-Mailer":"git-send-email 2.34.0.rc2.393.gf8c9666880-goog","In-Reply-To":"<20211130155600.2203123-1-hiroh@chromium.org>","References":"<20211130155600.2203123-1-hiroh@chromium.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [PATCH v3 05/12] libcamera: base: Add mutex\n\tclasses with thread safety annotations","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"This replaces Mutex and MutexLocker with our own defined classes.\nThe classes are annotated by clang thread safety annotations.\nSo we can add annotation to code where the classes are used.\n\nv4l2 code needs to be annotated, which violates Mutex capability.\n\nSigned-off-by: Hirokazu Honda <hiroh@chromium.org>\n---\n include/libcamera/base/meson.build |   1 +\n include/libcamera/base/mutex.h     | 131 +++++++++++++++++++++++++++++\n include/libcamera/base/thread.h    |   7 +-\n src/libcamera/base/meson.build     |   1 +\n src/libcamera/base/mutex.cpp       | 121 ++++++++++++++++++++++++++\n src/libcamera/base/thread.cpp      |  15 ----\n src/v4l2/v4l2_camera_proxy.h       |   5 +-\n 7 files changed, 258 insertions(+), 23 deletions(-)\n create mode 100644 include/libcamera/base/mutex.h\n create mode 100644 src/libcamera/base/mutex.cpp","diff":"diff --git a/include/libcamera/base/meson.build b/include/libcamera/base/meson.build\nindex 1a71ce5a..37c4435a 100644\n--- a/include/libcamera/base/meson.build\n+++ b/include/libcamera/base/meson.build\n@@ -13,6 +13,7 @@ libcamera_base_headers = files([\n     'flags.h',\n     'log.h',\n     'message.h',\n+    'mutex.h',\n     'object.h',\n     'private.h',\n     'semaphore.h',\ndiff --git a/include/libcamera/base/mutex.h b/include/libcamera/base/mutex.h\nnew file mode 100644\nindex 00000000..2792551c\n--- /dev/null\n+++ b/include/libcamera/base/mutex.h\n@@ -0,0 +1,131 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2021, Google Inc.\n+ *\n+ * thread.h - Thread support\n+ */\n+\n+#pragma once\n+\n+#include <condition_variable>\n+#include <mutex>\n+\n+#include <libcamera/base/thread_annotations.h>\n+\n+namespace libcamera {\n+\n+class ConditionVariable;\n+\n+#ifndef __DOXYGEN__\n+class LIBCAMERA_TSA_SCOPED_CAPABILITY MutexLocker;\n+#else\n+class MutexLocker;\n+#endif /* __DOXYGEN__ */\n+\n+/* \\todo using Mutex = std::mutex if lib++ is used. */\n+\n+#ifndef __DOXYGEN__\n+class LIBCAMERA_TSA_CAPABILITY(\"mutex\") Mutex final\n+#else\n+class Mutex final\n+#endif /* __DOXYGEN__ */\n+{\n+public:\n+\tconstexpr Mutex()\n+\t{\n+\t}\n+\n+\tvoid lock() LIBCAMERA_TSA_ACQUIRE()\n+\t{\n+\t\tmutex_.lock();\n+\t}\n+\n+\tvoid unlock() LIBCAMERA_TSA_RELEASE()\n+\t{\n+\t\tmutex_.unlock();\n+\t}\n+\n+private:\n+\tfriend MutexLocker;\n+\n+\tstd::mutex mutex_;\n+};\n+\n+#ifndef __DOXYGEN__\n+class LIBCAMERA_TSA_SCOPED_CAPABILITY MutexLocker final\n+#else\n+class MutexLocker final\n+#endif /* __DOXYGEN__ */\n+{\n+public:\n+\texplicit MutexLocker(Mutex &mutex) LIBCAMERA_TSA_ACQUIRE(mutex)\n+\t\t: lock_(mutex.mutex_)\n+\t{\n+\t}\n+\n+\tMutexLocker(Mutex &mutex, std::defer_lock_t t) noexcept LIBCAMERA_TSA_EXCLUDES(mutex)\n+\t\t: lock_(mutex.mutex_, t)\n+\t{\n+\t}\n+\n+\t~MutexLocker() LIBCAMERA_TSA_RELEASE()\n+\t{\n+\t}\n+\n+\tvoid lock() LIBCAMERA_TSA_ACQUIRE()\n+\t{\n+\t\tlock_.lock();\n+\t}\n+\n+\tbool try_lock() LIBCAMERA_TSA_TRY_ACQUIRE(true)\n+\t{\n+\t\treturn lock_.try_lock();\n+\t}\n+\n+\tvoid unlock() LIBCAMERA_TSA_RELEASE()\n+\t{\n+\t\tlock_.unlock();\n+\t}\n+\n+private:\n+\tfriend ConditionVariable;\n+\n+\tstd::unique_lock<std::mutex> lock_;\n+};\n+\n+class ConditionVariable final\n+{\n+public:\n+\tConditionVariable()\n+\t{\n+\t}\n+\n+\tvoid notify_one() noexcept\n+\t{\n+\t\tcv_.notify_one();\n+\t}\n+\n+\tvoid notify_all() noexcept\n+\t{\n+\t\tcv_.notify_all();\n+\t}\n+\n+\ttemplate<class Predicate>\n+\tvoid wait(MutexLocker &locker, Predicate stopWaiting)\n+\t{\n+\t\tcv_.wait(locker.lock_, stopWaiting);\n+\t}\n+\n+\ttemplate<class Rep, class Period, class Predicate>\n+\tbool wait_for(MutexLocker &locker,\n+\t\t      const std::chrono::duration<Rep, Period> &relTime,\n+\t\t      Predicate stopWaiting)\n+\t{\n+\t\treturn cv_.wait_for(locker.lock_, relTime, stopWaiting);\n+\t}\n+\n+private:\n+\tstd::condition_variable cv_;\n+};\n+\n+} /* namespace libcamera */\ndiff --git a/include/libcamera/base/thread.h b/include/libcamera/base/thread.h\nindex 1ebf8363..44678c34 100644\n--- a/include/libcamera/base/thread.h\n+++ b/include/libcamera/base/thread.h\n@@ -7,15 +7,14 @@\n \n #pragma once\n \n-#include <condition_variable>\n #include <memory>\n-#include <mutex>\n #include <sys/types.h>\n #include <thread>\n \n #include <libcamera/base/private.h>\n \n #include <libcamera/base/message.h>\n+#include <libcamera/base/mutex.h>\n #include <libcamera/base/signal.h>\n #include <libcamera/base/utils.h>\n \n@@ -27,10 +26,6 @@ class Object;\n class ThreadData;\n class ThreadMain;\n \n-using ConditionVariable = std::condition_variable;\n-using Mutex = std::mutex;\n-using MutexLocker = std::unique_lock<std::mutex>;\n-\n class Thread\n {\n public:\ndiff --git a/src/libcamera/base/meson.build b/src/libcamera/base/meson.build\nindex 05fed7ac..b93b8505 100644\n--- a/src/libcamera/base/meson.build\n+++ b/src/libcamera/base/meson.build\n@@ -11,6 +11,7 @@ libcamera_base_sources = files([\n     'flags.cpp',\n     'log.cpp',\n     'message.cpp',\n+    'mutex.cpp',\n     'object.cpp',\n     'semaphore.cpp',\n     'signal.cpp',\ndiff --git a/src/libcamera/base/mutex.cpp b/src/libcamera/base/mutex.cpp\nnew file mode 100644\nindex 00000000..327b90c0\n--- /dev/null\n+++ b/src/libcamera/base/mutex.cpp\n@@ -0,0 +1,121 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2021, Google Inc.\n+ *\n+ * mutex.cpp - Mutex classes with clang thread safety annotation\n+ */\n+\n+#include <libcamera/base/mutex.h>\n+\n+/**\n+ * \\file base/mutex.h\n+ * \\brief Mutex classes with clang thread safety annotation\n+ */\n+\n+namespace libcamera {\n+\n+/**\n+ * \\class Mutex\n+ * \\brief std::mutex wrapper with clang thread safety annotation\n+ */\n+\n+/**\n+ * \\fn Mutex::Mutex()\n+ * \\brief Construct a Mutex instance\n+ */\n+\n+/**\n+ * \\fn Mutex::lock()\n+ * \\brief Locks std::mutex\n+ */\n+\n+/**\n+ * \\fn Mutex::unlock()\n+ * \\brief Unlocks std::mutex\n+ */\n+\n+/**\n+ * \\class MutexLocker\n+ * \\brief std::unique_lock wrapper with clang thread safety annotation\n+ */\n+\n+/**\n+ * \\fn MutexLocker::MutexLocker(Mutex &mutex)\n+ * \\brief Constructs MutexLocker with \\a mutex as as the associated mutex and\n+ * locks \\a mutex\n+ * \\param[in] mutex Mutex to be locked/unlocked by MutexLocker\n+ *\n+ * This blocks until \\a mutex is acquired.\n+ */\n+\n+/**\n+ * \\fn MutexLocker::MutexLocker(Mutex &mutex, std::defer_lock_t t)\n+ * \\brief Constructs MutexLocker with \\a mutex as as the associated mutex but\n+ * does not lock \\a mutex\n+ * \\param[in] mutex Mutex to be locked/unlocked by MutexLocker\n+ * \\param[in] t mark to specify this constructor is called1\n+ *\n+ */\n+\n+/**\n+ * \\fn MutexLocker::~MutexLocker()\n+ * \\brief Destroys MutexLocker and unlock the associated mutex if it is locked\n+ */\n+\n+/**\n+ * \\fn MutexLocker::lock()\n+ * \\brief Locks the associated mutex\n+ */\n+\n+/**\n+ * \\fn MutexLocker::try_lock()\n+ * \\brief Tries to lock the associated mutex\n+ * \\return True if the ownership of the mutex has been acquired successfully,\n+    false otherwise.\n+ */\n+\n+/**\n+ * \\fn MutexLocker::unlock()\n+ * \\brief Unlocks the associated mutex\n+ */\n+\n+/**\n+ * \\class ConditionVariable\n+ * \\brief std::condition_variable wrapper with clang thread safety annotation\n+ */\n+\n+/**\n+ * \\fn ConditionVariable::ConditionVariable()\n+ * \\brief Constructs ConditionVariable\n+ */\n+\n+/**\n+ * \\fn ConditionVariable::notify_one()\n+ * \\brief Delegates std::condition_variable::notify_one()\n+ */\n+\n+/**\n+ * \\fn ConditionVariable::notify_all()\n+ * \\brief Delegates std::condition_variable::notify_all()\n+ */\n+\n+/**\n+ * \\fn ConditionVariable::wait(MutexLocker& locker, Predicate stopWaiting)\n+ * \\brief Call std::condition_variable::wait() with \\a locker and \\a stopWaiting\n+ * \\param[in] locker MutexLocker that is locked/unlocked during wait()\n+ * \\param[in] stopWaiting The predicate to be satisfied\n+ */\n+\n+/**\n+ * \\fn ConditionVariable::wait_for(MutexLocker& locker,\n+                                   const std::chrono::duration<Rep, Period> &relTime,\n+\t\t\t\t   Predicate stopWaiting)\n+ * \\brief Call std::condition_variable::wait_for() with \\a locker, \\a relTime,\n+   \\a stopWaiting\n+ * \\param[in] locker MutexLocker that is locked/unlocked during wait()\n+ * \\param[in] relTime std::chrono::duration representing the maximum time to\n+   spend waiting\n+ * \\param[in] stopWaiting The predicate to be satisfied\n+ */\n+\n+} /* namespace libcamera */\ndiff --git a/src/libcamera/base/thread.cpp b/src/libcamera/base/thread.cpp\nindex b893135f..b2043b7e 100644\n--- a/src/libcamera/base/thread.cpp\n+++ b/src/libcamera/base/thread.cpp\n@@ -204,21 +204,6 @@ ThreadData *ThreadData::current()\n \treturn data;\n }\n \n-/**\n- * \\typedef ConditionVariable\n- * \\brief An alias for std::condition_variable\n- */\n-\n-/**\n- * \\typedef Mutex\n- * \\brief An alias for std::mutex\n- */\n-\n-/**\n- * \\typedef MutexLocker\n- * \\brief An alias for std::unique_lock<std::mutex>\n- */\n-\n /**\n  * \\class Thread\n  * \\brief A thread of execution\ndiff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h\nindex 040954dd..23be995d 100644\n--- a/src/v4l2/v4l2_camera_proxy.h\n+++ b/src/v4l2/v4l2_camera_proxy.h\n@@ -14,7 +14,8 @@\n #include <sys/types.h>\n #include <vector>\n \n-#include <libcamera/base/thread.h>\n+#include <libcamera/base/mutex.h>\n+#include <libcamera/base/thread_annotations.h>\n \n #include <libcamera/camera.h>\n \n@@ -59,7 +60,7 @@ private:\n \tint vidioc_querybuf(V4L2CameraFile *file, struct v4l2_buffer *arg);\n \tint vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg);\n \tint vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg,\n-\t\t\t libcamera::Mutex *lock);\n+\t\t\t libcamera::Mutex *lock) LIBCAMERA_TSA_REQUIRES(*lock);\n \tint vidioc_streamon(V4L2CameraFile *file, int *arg);\n \tint vidioc_streamoff(V4L2CameraFile *file, int *arg);\n \n","prefixes":["libcamera-devel","v3","05/12"]}