From patchwork Tue Jan 23 01:12:49 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 19460 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 7612FC324D for ; Tue, 23 Jan 2024 01:13:06 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0A92562950; Tue, 23 Jan 2024 02:13:06 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="K5SE5yQB"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0D65A62973 for ; Tue, 23 Jan 2024 02:13:02 +0100 (CET) Received: from pendragon.ideasonboard.com (89-27-53-110.bb.dnainternet.fi [89.27.53.110]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B6143188E; Tue, 23 Jan 2024 02:11:48 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1705972308; bh=vWwEaa5AmxWhUWEB93AXIdNgpOby95jk/FitnDlkli8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=K5SE5yQBa/kX2VQviFIaUSEoaH3ZczUHzWDzF4bJYwx3xRCjHe5QW3ZbdK/Xj4FzM y8EJJ/wztUWK7HjR4Yr4I8p9SDPESUscpYLhhFVYYhToH89m+6AwdW7X4xODn6/440 2z+eqDOWrm50ttuaL0swETP0chQLjHJ3/vc2QT7I= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Subject: [PATCH v2 12/12] libcamera: object: Add and use thread-bound assertion Date: Tue, 23 Jan 2024 03:12:49 +0200 Message-ID: <20240123011249.22716-13-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240123011249.22716-1-laurent.pinchart@ideasonboard.com> References: <20240123011249.22716-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Several functions in libcamera classes are marked as thread-bound, restricting the contexts in which those functions can be called. There is no infrastructure to enforce these restrictions, causing difficult to debug race conditions when they are not met by callers. As a first step to solve this, add an assertThreadBound() protected function to the Object class to test if the calling thread context is valid, and use it in member functions of Object subclasses marked as thread-bound. This replaces manual tests in a few locations. The thread-bound member functions of classes that do not inherit from Object are not checked, and neither are the functions of classes marked as thread-bound at the class level. These issue should be addressed in the future. Signed-off-by: Laurent Pinchart Reviewed-by: Milan Zamazal --- Changes since v1: - Fix typo in commit message --- include/libcamera/base/object.h | 2 ++ src/libcamera/base/event_notifier.cpp | 6 +++++ src/libcamera/base/object.cpp | 32 ++++++++++++++++++++++++++- src/libcamera/base/timer.cpp | 10 +++------ 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/include/libcamera/base/object.h b/include/libcamera/base/object.h index 933336361155..cb7e0a132be2 100644 --- a/include/libcamera/base/object.h +++ b/include/libcamera/base/object.h @@ -49,6 +49,8 @@ public: protected: virtual void message(Message *msg); + bool assertThreadBound(const char *message); + private: friend class SignalBase; friend class Thread; diff --git a/src/libcamera/base/event_notifier.cpp b/src/libcamera/base/event_notifier.cpp index fd93c0878c6f..a519aec38efb 100644 --- a/src/libcamera/base/event_notifier.cpp +++ b/src/libcamera/base/event_notifier.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -20,6 +21,8 @@ namespace libcamera { +LOG_DECLARE_CATEGORY(Event) + /** * \class EventNotifier * \brief Notify of activity on a file descriptor @@ -104,6 +107,9 @@ EventNotifier::~EventNotifier() */ void EventNotifier::setEnabled(bool enable) { + if (!assertThreadBound("EventNotifier can't be enabled from another thread")) + return; + if (enabled_ == enable) return; diff --git a/src/libcamera/base/object.cpp b/src/libcamera/base/object.cpp index c6040fc6a78b..81054b5833a3 100644 --- a/src/libcamera/base/object.cpp +++ b/src/libcamera/base/object.cpp @@ -225,6 +225,35 @@ void Object::message(Message *msg) } } +/** + * \fn Object::assertThreadBound() + * \brief Check if the caller complies with thread-bound constraints + * \param[in] message The message to be printed on error + * + * This function verifies the calling constraints required by the \threadbound + * definition. It shall be called at the beginning of member functions of an + * Object subclass that are explicitly marked as thread-bound in their + * documentation. + * + * If the thread-bound constraints are not met, the function prints \a message + * as an error message. For debug builds, it additionally causes an assertion + * error. + * + * \todo Verify the thread-bound requirements for functions marked as + * thread-bound at the class level. + * + * \return True if the call is thread-bound compliant, false otherwise + */ +bool Object::assertThreadBound(const char *message) +{ + if (Thread::current() == thread_) + return true; + + LOG(Object, Error) << message; + ASSERT(false); + return false; +} + /** * \fn R Object::invokeMethod() * \brief Invoke a method asynchronously on an Object instance @@ -276,7 +305,8 @@ void Object::message(Message *msg) */ void Object::moveToThread(Thread *thread) { - ASSERT(Thread::current() == thread_); + if (!assertThreadBound("Object can't be moved from another thread")) + return; if (thread_ == thread) return; diff --git a/src/libcamera/base/timer.cpp b/src/libcamera/base/timer.cpp index 74b060af32ff..24dbf1e892c3 100644 --- a/src/libcamera/base/timer.cpp +++ b/src/libcamera/base/timer.cpp @@ -85,10 +85,8 @@ void Timer::start(std::chrono::milliseconds duration) */ void Timer::start(std::chrono::steady_clock::time_point deadline) { - if (Thread::current() != thread()) { - LOG(Timer, Error) << "Timer " << this << " << can't be started from another thread"; + if (!assertThreadBound("Timer can't be started from another thread")) return; - } deadline_ = deadline; @@ -114,13 +112,11 @@ void Timer::start(std::chrono::steady_clock::time_point deadline) */ void Timer::stop() { - if (!isRunning()) + if (!assertThreadBound("Timer can't be stopped from another thread")) return; - if (Thread::current() != thread()) { - LOG(Timer, Error) << "Timer " << this << " can't be stopped from another thread"; + if (!isRunning()) return; - } unregisterTimer(); }