From patchwork Mon Aug 12 12:46:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1779 Return-Path: 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 3261460E38 for ; Mon, 12 Aug 2019 14:46:49 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B379F594 for ; Mon, 12 Aug 2019 14:46:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614008; bh=LfgV2vhRtVXJJcIX5MHhgR4vFf2+h2aRWcl99FF73IM=; h=From:To:Subject:Date:In-Reply-To:References:From; b=MpsiwLdpKAtzqTNqGET5qcEThE+J32ZLrsmWETjWrcfwaYHc47qSTauao9SstJHNi Nif2hfSIXpzertv94tPadfjz4Ctt90syOSeAs3ZXPaPuzbLumqOXQG1nQ2EXp9pf1v WTgFufaKCpEWdlXuMxPTSqIyox846F7Adq9+4NFE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:25 +0300 Message-Id: <20190812124642.24287-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 01/18] libcamera: object: Make message() method protected X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:49 -0000 The message() method shouldn't be called externally (except by a few friend classes), make it protected. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- include/libcamera/object.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/libcamera/object.h b/include/libcamera/object.h index 5c251a822d9a..3d08d69a9044 100644 --- a/include/libcamera/object.h +++ b/include/libcamera/object.h @@ -26,11 +26,13 @@ public: virtual ~Object(); void postMessage(std::unique_ptr msg); - virtual void message(Message *msg); Thread *thread() const { return thread_; } void moveToThread(Thread *thread); +protected: + virtual void message(Message *msg); + private: template friend class Signal; From patchwork Mon Aug 12 12:46:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1780 Return-Path: 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 80EA760E38 for ; Mon, 12 Aug 2019 14:46:49 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 22C62327 for ; Mon, 12 Aug 2019 14:46:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614009; bh=Pkpe1AGRDZvfElHXqq10DdD+hhUbrz6k0xRC16ZrQRw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=q4h8d3hcoGYWHN69XwAzoEs86Q//au0VMWyG73zbaPOrBOMGqRh81/GfdwxBCAmey BmFN6e5PYDz4hDbm0EUSNiCHrDDy5O6u/WvKYto+ks71EJnDv39YZmg1i5+3v+28aT ctsvUHKWFmHyVA0k1T/yrHbWt4OBjHF0MEcn0dPw= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:26 +0300 Message-Id: <20190812124642.24287-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 02/18] libcamera: thread: Wake up target thread when moving objects X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:49 -0000 When moving an object to a different thread, messages posted for the object are moved to the message queue of the new thread. Wake up the new thread to ensure it processes the moved messages. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- src/libcamera/thread.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libcamera/thread.cpp b/src/libcamera/thread.cpp index 5d46eeb8d3a5..6f86e4a90a05 100644 --- a/src/libcamera/thread.cpp +++ b/src/libcamera/thread.cpp @@ -464,6 +464,8 @@ void Thread::moveObject(Object *object) /* Move pending messages to the message queue of the new thread. */ if (object->pendingMessages_) { + unsigned int movedMessages = 0; + for (std::unique_ptr &msg : currentData->messages_.list_) { if (!msg) continue; @@ -471,6 +473,14 @@ void Thread::moveObject(Object *object) continue; targetData->messages_.list_.push_back(std::move(msg)); + movedMessages++; + } + + if (movedMessages) { + EventDispatcher *dispatcher = + targetData->dispatcher_.load(std::memory_order_acquire); + if (dispatcher) + dispatcher->interrupt(); } } From patchwork Mon Aug 12 12:46:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1781 Return-Path: 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 EAE2C60E38 for ; Mon, 12 Aug 2019 14:46:49 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 86B3C594 for ; Mon, 12 Aug 2019 14:46:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614009; bh=JL6icfRv59UQAMHOVt8DJGpk6nFLqIeWcf4xWR2Z+kA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=tb/wR2Ip6NXZIX4e4K7xlus0eJ/6QGyDK6FemeUXdDcj0FpuyP5sOQO6ue0dS0S4T 5UzYpR2sGDxDGTah4LOUMZEJx+6U4oC5w6DxlW719+4uAgg0NzmCa++Luwf7r1RVj2 s5tcM3tILws9HqRSZLJ4aDMU+kCMAud/aCJji5fM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:27 +0300 Message-Id: <20190812124642.24287-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 03/18] libcamera: thread: Support dispatching messages to main thread X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:50 -0000 Threads contain message queues and dispatch queue messages in their event loop, in Thread::exec(). This mechanism prevents the main thread from dispatching messages as it doesn't run Thread::exec(). Fix this by moving message dispatching from Thread::exec() to EventDispatcher::processEvents(). Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- src/libcamera/event_dispatcher_poll.cpp | 3 +++ src/libcamera/include/thread.h | 3 ++- src/libcamera/thread.cpp | 4 +--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libcamera/event_dispatcher_poll.cpp b/src/libcamera/event_dispatcher_poll.cpp index 4f15f3e3269b..281f37bdbb16 100644 --- a/src/libcamera/event_dispatcher_poll.cpp +++ b/src/libcamera/event_dispatcher_poll.cpp @@ -19,6 +19,7 @@ #include #include "log.h" +#include "thread.h" /** * \file event_dispatcher_poll.h @@ -143,6 +144,8 @@ void EventDispatcherPoll::processEvents() { int ret; + Thread::current()->dispatchMessages(); + /* Create the pollfd array. */ std::vector pollfds; pollfds.reserve(notifiers_.size() + 1); diff --git a/src/libcamera/include/thread.h b/src/libcamera/include/thread.h index acae91cb6457..630abb49534f 100644 --- a/src/libcamera/include/thread.h +++ b/src/libcamera/include/thread.h @@ -43,6 +43,8 @@ public: EventDispatcher *eventDispatcher(); void setEventDispatcher(std::unique_ptr dispatcher); + void dispatchMessages(); + protected: int exec(); virtual void run(); @@ -53,7 +55,6 @@ private: void postMessage(std::unique_ptr msg, Object *receiver); void removeMessages(Object *receiver); - void dispatchMessages(); friend class Object; friend class ThreadData; diff --git a/src/libcamera/thread.cpp b/src/libcamera/thread.cpp index 6f86e4a90a05..24422f7b7bd0 100644 --- a/src/libcamera/thread.cpp +++ b/src/libcamera/thread.cpp @@ -212,10 +212,8 @@ int Thread::exec() locker.unlock(); - while (!data_->exit_.load(std::memory_order_acquire)) { - dispatchMessages(); + while (!data_->exit_.load(std::memory_order_acquire)) dispatcher->processEvents(); - } locker.lock(); From patchwork Mon Aug 12 12:46:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1782 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6232760E38 for ; Mon, 12 Aug 2019 14:46:50 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E130D327 for ; Mon, 12 Aug 2019 14:46:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614010; bh=n9M1fZ+58duTiTj7ajfnt8ZHBoYWVcO9iMDMQoQ/2c0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Q9o49AhAz2mnl/WLIXiS00IMDKNr5CiSBag8ecitSlQWYk3d3K9j1ZrQWECPsoONH hOGiapfbjshGrEJk4dV2NJE0SmSUZtKIbJ/KNI8p7ZtEK0hm91HlxP3/8Tnt4CZpAx 4UNcIApzK/77RJbdqNaqPzYYqbG/r2rt/d1T1ekE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:28 +0300 Message-Id: <20190812124642.24287-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 04/18] libcamera: signal: Split Slot implementation to reusable classes X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:50 -0000 Move the Slot* classes to bound_method.{h,cpp} and rename them to Bound*Method*. They will be reused to implement asynchronous method invocation similar to cross-thread signal delivery. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- Documentation/Doxyfile.in | 10 +-- include/libcamera/bound_method.h | 131 ++++++++++++++++++++++++++++ include/libcamera/meson.build | 1 + include/libcamera/object.h | 5 +- include/libcamera/signal.h | 145 ++++--------------------------- src/libcamera/bound_method.cpp | 33 +++++++ src/libcamera/include/message.h | 8 +- src/libcamera/meson.build | 1 + src/libcamera/message.cpp | 4 +- src/libcamera/object.cpp | 2 +- src/libcamera/signal.cpp | 23 ----- 11 files changed, 197 insertions(+), 166 deletions(-) create mode 100644 include/libcamera/bound_method.h create mode 100644 src/libcamera/bound_method.cpp diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in index 3d94623a4b8f..a9596c2a32d8 100644 --- a/Documentation/Doxyfile.in +++ b/Documentation/Doxyfile.in @@ -865,11 +865,11 @@ EXCLUDE_PATTERNS = # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = libcamera::SignalBase \ - libcamera::SlotArgs \ - libcamera::SlotBase \ - libcamera::SlotMember \ - libcamera::SlotStatic \ +EXCLUDE_SYMBOLS = libcamera::BoundMemberMethod \ + libcamera::BoundMethodArgs \ + libcamera::BoundMethodBase \ + libcamera::BoundStaticMethod \ + libcamera::SignalBase \ std::* # The EXAMPLE_PATH tag can be used to specify one or more files or directories diff --git a/include/libcamera/bound_method.h b/include/libcamera/bound_method.h new file mode 100644 index 000000000000..38c44b923ba1 --- /dev/null +++ b/include/libcamera/bound_method.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * bound_method.h - Method bind and invocation + */ +#ifndef __LIBCAMERA_BOUND_METHOD_H__ +#define __LIBCAMERA_BOUND_METHOD_H__ + +#include +#include + +namespace libcamera { + +class Object; +template +class Signal; +class SignalBase; + +class BoundMethodBase +{ +public: + BoundMethodBase(void *obj, Object *object) + : obj_(obj), object_(object) {} + virtual ~BoundMethodBase() {} + + template::value>::type * = nullptr> + bool match(T *obj) { return obj == obj_; } + bool match(Object *object) { return object == object_; } + + void disconnect(SignalBase *signal); + + void activatePack(void *pack); + virtual void invokePack(void *pack) = 0; + +protected: + void *obj_; + Object *object_; +}; + +template +class BoundMethodArgs : public BoundMethodBase +{ +private: +#ifndef __DOXYGEN__ + /* + * This is a cheap partial implementation of std::integer_sequence<> + * from C++14. + */ + template + struct sequence { + }; + + template + struct generator : generator { + }; + + template + struct generator<0, S...> { + typedef sequence type; + }; +#endif + + using PackType = std::tuple::type...>; + + template + void invokePack(void *pack, sequence) + { + PackType *args = static_cast(pack); + invoke(std::get(*args)...); + delete args; + } + +public: + BoundMethodArgs(void *obj, Object *object) + : BoundMethodBase(obj, object) {} + + void invokePack(void *pack) override + { + invokePack(pack, typename generator::type()); + } + + virtual void activate(Args... args) = 0; + virtual void invoke(Args... args) = 0; +}; + +template +class BoundMemberMethod : public BoundMethodArgs +{ +public: + using PackType = std::tuple::type...>; + + BoundMemberMethod(T *obj, Object *object, void (T::*func)(Args...)) + : BoundMethodArgs(obj, object), func_(func) {} + + void activate(Args... args) + { + if (this->object_) + BoundMethodBase::activatePack(new PackType{ args... }); + else + (static_cast(this->obj_)->*func_)(args...); + } + + void invoke(Args... args) + { + (static_cast(this->obj_)->*func_)(args...); + } + +private: + friend class Signal; + void (T::*func_)(Args...); +}; + +template +class BoundStaticMethod : public BoundMethodArgs +{ +public: + BoundStaticMethod(void (*func)(Args...)) + : BoundMethodArgs(nullptr, nullptr), func_(func) {} + + void activate(Args... args) { (*func_)(args...); } + void invoke(Args... args) {} + +private: + friend class Signal; + void (*func_)(Args...); +}; + +}; /* namespace libcamera */ + +#endif /* __LIBCAMERA_BOUND_METHOD_H__ */ diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index 920eb5fcbfd1..a8a38a9b1db7 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -1,4 +1,5 @@ libcamera_api = files([ + 'bound_method.h', 'buffer.h', 'camera.h', 'camera_manager.h', diff --git a/include/libcamera/object.h b/include/libcamera/object.h index 3d08d69a9044..e3b39cf547b0 100644 --- a/include/libcamera/object.h +++ b/include/libcamera/object.h @@ -10,13 +10,14 @@ #include #include +#include + namespace libcamera { class Message; template class Signal; class SignalBase; -class SlotBase; class Thread; class Object @@ -36,7 +37,7 @@ protected: private: template friend class Signal; - friend class SlotBase; + friend class BoundMethodBase; friend class Thread; void connect(SignalBase *signal); diff --git a/include/libcamera/signal.h b/include/libcamera/signal.h index 8f6db700cd80..3b6de30f7d35 100644 --- a/include/libcamera/signal.h +++ b/include/libcamera/signal.h @@ -8,127 +8,14 @@ #define __LIBCAMERA_SIGNAL_H__ #include -#include #include #include +#include #include namespace libcamera { -template -class Signal; -class SignalBase; - -class SlotBase -{ -public: - SlotBase(void *obj, Object *object) - : obj_(obj), object_(object) {} - virtual ~SlotBase() {} - - template::value>::type * = nullptr> - bool match(T *obj) { return obj == obj_; } - bool match(Object *object) { return object == object_; } - - void disconnect(SignalBase *signal); - - void activatePack(void *pack); - virtual void invokePack(void *pack) = 0; - -protected: - void *obj_; - Object *object_; -}; - -template -class SlotArgs : public SlotBase -{ -private: -#ifndef __DOXYGEN__ - /* - * This is a cheap partial implementation of std::integer_sequence<> - * from C++14. - */ - template - struct sequence { - }; - - template - struct generator : generator { - }; - - template - struct generator<0, S...> { - typedef sequence type; - }; -#endif - - using PackType = std::tuple::type...>; - - template - void invokePack(void *pack, sequence) - { - PackType *args = static_cast(pack); - invoke(std::get(*args)...); - delete args; - } - -public: - SlotArgs(void *obj, Object *object) - : SlotBase(obj, object) {} - - void invokePack(void *pack) override - { - invokePack(pack, typename generator::type()); - } - - virtual void activate(Args... args) = 0; - virtual void invoke(Args... args) = 0; -}; - -template -class SlotMember : public SlotArgs -{ -public: - using PackType = std::tuple::type...>; - - SlotMember(T *obj, Object *object, void (T::*func)(Args...)) - : SlotArgs(obj, object), func_(func) {} - - void activate(Args... args) - { - if (this->object_) - SlotBase::activatePack(new PackType{ args... }); - else - (static_cast(this->obj_)->*func_)(args...); - } - - void invoke(Args... args) - { - (static_cast(this->obj_)->*func_)(args...); - } - -private: - friend class Signal; - void (T::*func_)(Args...); -}; - -template -class SlotStatic : public SlotArgs -{ -public: - SlotStatic(void (*func)(Args...)) - : SlotArgs(nullptr, nullptr), func_(func) {} - - void activate(Args... args) { (*func_)(args...); } - void invoke(Args... args) {} - -private: - friend class Signal; - void (*func_)(Args...); -}; - class SignalBase { public: @@ -136,7 +23,7 @@ public: void disconnect(T *obj) { for (auto iter = slots_.begin(); iter != slots_.end(); ) { - SlotBase *slot = *iter; + BoundMethodBase *slot = *iter; if (slot->match(obj)) { iter = slots_.erase(iter); delete slot; @@ -148,7 +35,7 @@ public: protected: friend class Object; - std::list slots_; + std::list slots_; }; template @@ -158,7 +45,7 @@ public: Signal() {} ~Signal() { - for (SlotBase *slot : slots_) { + for (BoundMethodBase *slot : slots_) { slot->disconnect(this); delete slot; } @@ -170,7 +57,7 @@ public: { Object *object = static_cast(obj); object->connect(this); - slots_.push_back(new SlotMember(obj, object, func)); + slots_.push_back(new BoundMemberMethod(obj, object, func)); } template::value>::type * = nullptr> @@ -179,17 +66,17 @@ public: #endif void connect(T *obj, void (T::*func)(Args...)) { - slots_.push_back(new SlotMember(obj, nullptr, func)); + slots_.push_back(new BoundMemberMethod(obj, nullptr, func)); } void connect(void (*func)(Args...)) { - slots_.push_back(new SlotStatic(func)); + slots_.push_back(new BoundStaticMethod(func)); } void disconnect() { - for (SlotBase *slot : slots_) + for (BoundMethodBase *slot : slots_) delete slot; slots_.clear(); } @@ -204,15 +91,15 @@ public: void disconnect(T *obj, void (T::*func)(Args...)) { for (auto iter = slots_.begin(); iter != slots_.end(); ) { - SlotArgs *slot = static_cast *>(*iter); + BoundMethodArgs *slot = static_cast *>(*iter); /* * If the object matches the slot, the slot is * guaranteed to be a member slot, so we can safely - * cast it to SlotMember and access its + * cast it to BoundMemberMethod and access its * func_ member. */ if (slot->match(obj) && - static_cast *>(slot)->func_ == func) { + static_cast *>(slot)->func_ == func) { iter = slots_.erase(iter); delete slot; } else { @@ -224,9 +111,9 @@ public: void disconnect(void (*func)(Args...)) { for (auto iter = slots_.begin(); iter != slots_.end(); ) { - SlotArgs *slot = *iter; + BoundMethodArgs *slot = *iter; if (slot->match(nullptr) && - static_cast *>(slot)->func_ == func) { + static_cast *>(slot)->func_ == func) { iter = slots_.erase(iter); delete slot; } else { @@ -241,9 +128,9 @@ public: * Make a copy of the slots list as the slot could call the * disconnect operation, invalidating the iterator. */ - std::vector slots{ slots_.begin(), slots_.end() }; - for (SlotBase *slot : slots) - static_cast *>(slot)->activate(args...); + std::vector slots{ slots_.begin(), slots_.end() }; + for (BoundMethodBase *slot : slots) + static_cast *>(slot)->activate(args...); } }; diff --git a/src/libcamera/bound_method.cpp b/src/libcamera/bound_method.cpp new file mode 100644 index 000000000000..0a2d61a6c805 --- /dev/null +++ b/src/libcamera/bound_method.cpp @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * bound_method.cpp - Method bind and invocation + */ + +#include + +#include "message.h" +#include "thread.h" +#include "utils.h" + +namespace libcamera { + +void BoundMethodBase::disconnect(SignalBase *signal) +{ + if (object_) + object_->disconnect(signal); +} + +void BoundMethodBase::activatePack(void *pack) +{ + if (Thread::current() == object_->thread()) { + invokePack(pack); + } else { + std::unique_ptr msg = + utils::make_unique(this, pack); + object_->postMessage(std::move(msg)); + } +} + +} /* namespace libcamera */ diff --git a/src/libcamera/include/message.h b/src/libcamera/include/message.h index 416fe74b10ad..b4670c0eab76 100644 --- a/src/libcamera/include/message.h +++ b/src/libcamera/include/message.h @@ -11,8 +11,8 @@ namespace libcamera { +class BoundMethodBase; class Object; -class SlotBase; class Thread; class Message @@ -44,12 +44,12 @@ private: class SignalMessage : public Message { public: - SignalMessage(SlotBase *slot, void *pack) - : Message(Message::SignalMessage), slot_(slot), pack_(pack) + SignalMessage(BoundMethodBase *method, void *pack) + : Message(Message::SignalMessage), method_(method), pack_(pack) { } - SlotBase *slot_; + BoundMethodBase *method_; void *pack_; }; diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 7d5d3c04fba0..c5d8f116ffc6 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -1,4 +1,5 @@ libcamera_sources = files([ + 'bound_method.cpp', 'buffer.cpp', 'camera.cpp', 'camera_manager.cpp', diff --git a/src/libcamera/message.cpp b/src/libcamera/message.cpp index d44d2a4c73a8..8d3376d8a533 100644 --- a/src/libcamera/message.cpp +++ b/src/libcamera/message.cpp @@ -114,12 +114,12 @@ Message::Type Message::registerMessageType() /** * \fn SignalMessage::SignalMessage() * \brief Construct a SignalMessage - * \param[in] slot The slot that the signal targets + * \param[in] method The slot that the signal targets * \param[in] pack The signal arguments */ /** - * \var SignalMessage::slot_ + * \var SignalMessage::method_ * \brief The slot that the signal targets */ diff --git a/src/libcamera/object.cpp b/src/libcamera/object.cpp index 61787fadac0b..0adbc203add8 100644 --- a/src/libcamera/object.cpp +++ b/src/libcamera/object.cpp @@ -90,7 +90,7 @@ void Object::message(Message *msg) switch (msg->type()) { case Message::SignalMessage: { SignalMessage *smsg = static_cast(msg); - smsg->slot_->invokePack(smsg->pack_); + smsg->method_->invokePack(smsg->pack_); break; } diff --git a/src/libcamera/signal.cpp b/src/libcamera/signal.cpp index ab7dba508dfb..6ee348acc8d4 100644 --- a/src/libcamera/signal.cpp +++ b/src/libcamera/signal.cpp @@ -7,10 +7,6 @@ #include -#include "message.h" -#include "thread.h" -#include "utils.h" - /** * \file signal.h * \brief Signal & slot implementation @@ -57,25 +53,6 @@ namespace libcamera { * passed through the signal will remain valid after the signal is emitted. */ -void SlotBase::disconnect(SignalBase *signal) -{ - if (object_) - object_->disconnect(signal); -} - -void SlotBase::activatePack(void *pack) -{ - Object *obj = static_cast(object_); - - if (Thread::current() == obj->thread()) { - invokePack(pack); - } else { - std::unique_ptr msg = - utils::make_unique(this, pack); - obj->postMessage(std::move(msg)); - } -} - /** * \fn Signal::connect(T *object, void(T::*func)(Args...)) * \brief Connect the signal to a member function slot From patchwork Mon Aug 12 12:46:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1783 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C2D7B61636 for ; Mon, 12 Aug 2019 14:46:50 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 568C2594 for ; Mon, 12 Aug 2019 14:46:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614010; bh=2SZrUbhnrxIu5ZgHJv1Puo1eaAVdKs877QcMW84CIiY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=IpqMv7nVi+5e0ECQXlC7Dt7C3w/xUtuO/oBefInGdRV2ZGbQOswvPi7XP7JvpPxxR YK0+tYpmXcLsCds6M+mX0n/SutIkjaR8nl9OZr19EShORtkL55JpCxDtOOS4NSK8hh ThI0cr8c61tIOCtY00TrXTk2tAf8BEjdj6lpVTXk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:29 +0300 Message-Id: <20190812124642.24287-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 05/18] libcamera: bound_method: Decouple from Signal implementation X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:51 -0000 To make the BoundMethod classes more generic, replace direct access to private member from Signal classes with accessors or helper functions. This allows removal of friend statements from the BoundMethod classes. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- include/libcamera/bound_method.h | 11 +++++------ include/libcamera/signal.h | 12 +++++++----- src/libcamera/bound_method.cpp | 6 ------ 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/include/libcamera/bound_method.h b/include/libcamera/bound_method.h index 38c44b923ba1..54c40fc52e3b 100644 --- a/include/libcamera/bound_method.h +++ b/include/libcamera/bound_method.h @@ -13,9 +13,6 @@ namespace libcamera { class Object; -template -class Signal; -class SignalBase; class BoundMethodBase { @@ -28,7 +25,7 @@ public: bool match(T *obj) { return obj == obj_; } bool match(Object *object) { return object == object_; } - void disconnect(SignalBase *signal); + Object *object() const { return object_; } void activatePack(void *pack); virtual void invokePack(void *pack) = 0; @@ -93,6 +90,8 @@ public: BoundMemberMethod(T *obj, Object *object, void (T::*func)(Args...)) : BoundMethodArgs(obj, object), func_(func) {} + bool match(void (T::*func)(Args...)) const { return func == func_; } + void activate(Args... args) { if (this->object_) @@ -107,7 +106,6 @@ public: } private: - friend class Signal; void (T::*func_)(Args...); }; @@ -118,11 +116,12 @@ public: BoundStaticMethod(void (*func)(Args...)) : BoundMethodArgs(nullptr, nullptr), func_(func) {} + bool match(void (*func)(Args...)) const { return func == func_; } + void activate(Args... args) { (*func_)(args...); } void invoke(Args... args) {} private: - friend class Signal; void (*func_)(Args...); }; diff --git a/include/libcamera/signal.h b/include/libcamera/signal.h index 3b6de30f7d35..b8a60281cceb 100644 --- a/include/libcamera/signal.h +++ b/include/libcamera/signal.h @@ -46,7 +46,9 @@ public: ~Signal() { for (BoundMethodBase *slot : slots_) { - slot->disconnect(this); + Object *object = slot->object(); + if (object) + object->disconnect(this); delete slot; } } @@ -95,11 +97,11 @@ public: /* * If the object matches the slot, the slot is * guaranteed to be a member slot, so we can safely - * cast it to BoundMemberMethod and access its - * func_ member. + * cast it to BoundMemberMethod to match + * func. */ if (slot->match(obj) && - static_cast *>(slot)->func_ == func) { + static_cast *>(slot)->match(func)) { iter = slots_.erase(iter); delete slot; } else { @@ -113,7 +115,7 @@ public: for (auto iter = slots_.begin(); iter != slots_.end(); ) { BoundMethodArgs *slot = *iter; if (slot->match(nullptr) && - static_cast *>(slot)->func_ == func) { + static_cast *>(slot)->match(func)) { iter = slots_.erase(iter); delete slot; } else { diff --git a/src/libcamera/bound_method.cpp b/src/libcamera/bound_method.cpp index 0a2d61a6c805..23b8f4122283 100644 --- a/src/libcamera/bound_method.cpp +++ b/src/libcamera/bound_method.cpp @@ -13,12 +13,6 @@ namespace libcamera { -void BoundMethodBase::disconnect(SignalBase *signal) -{ - if (object_) - object_->disconnect(signal); -} - void BoundMethodBase::activatePack(void *pack) { if (Thread::current() == object_->thread()) { From patchwork Mon Aug 12 12:46:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1784 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3154861635 for ; Mon, 12 Aug 2019 14:46:51 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BB943327 for ; Mon, 12 Aug 2019 14:46:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614010; bh=iuLdtWKEVieryLA80WUYWCZO2UZ2xXRIq/eFXDG6lhE=; h=From:To:Subject:Date:In-Reply-To:References:From; b=ZmJOxkLBGFQDEf8jU1XDbdGtX9NVQQkBK8VlYIlXSt3KIpR5iW+B7djz6rmrkQmuU XC65eNzjswRokJfS3AunFwe9Bsjh7BHH2J7v3jE8aimNG9/jMT6uj0eKIZyNMLpl6U JsBXnSD0NntcGp34tvyuPt7YCRm6VSIpfQIgYUas= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:30 +0300 Message-Id: <20190812124642.24287-7-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 06/18] libcamera: object: Add an asynchronous method invocation method X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:52 -0000 Add a helper invokeMethod() to the Object class that allows asynchrnous invocation of any method of an Object instance. Asynchronous invocation occurs when control returns to the event dispatcher of the target object's thread, in the context of that thread. To support this, generalise the SignalMessage implementation to support automatic deletion of the associated BoundMethod, and rename the message to InvokeMessage to reflect the more generic purpose. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- include/libcamera/object.h | 12 +++++++++ src/libcamera/bound_method.cpp | 2 +- src/libcamera/include/message.h | 17 +++++++----- src/libcamera/message.cpp | 48 ++++++++++++++++++++++++--------- src/libcamera/object.cpp | 29 +++++++++++++++++--- 5 files changed, 86 insertions(+), 22 deletions(-) diff --git a/include/libcamera/object.h b/include/libcamera/object.h index e3b39cf547b0..869200a57d8c 100644 --- a/include/libcamera/object.h +++ b/include/libcamera/object.h @@ -28,6 +28,16 @@ public: void postMessage(std::unique_ptr msg); + template::value>::type * = nullptr> + void invokeMethod(void (T::*func)(Args...), Args... args) + { + T *obj = static_cast(this); + BoundMethodBase *method = new BoundMemberMethod(obj, this, func); + void *pack = new typename BoundMemberMethod::PackType{ args... }; + + invokeMethod(method, pack); + } + Thread *thread() const { return thread_; } void moveToThread(Thread *thread); @@ -40,6 +50,8 @@ private: friend class BoundMethodBase; friend class Thread; + void invokeMethod(BoundMethodBase *method, void *pack); + void connect(SignalBase *signal); void disconnect(SignalBase *signal); diff --git a/src/libcamera/bound_method.cpp b/src/libcamera/bound_method.cpp index 23b8f4122283..d89f84c03f4d 100644 --- a/src/libcamera/bound_method.cpp +++ b/src/libcamera/bound_method.cpp @@ -19,7 +19,7 @@ void BoundMethodBase::activatePack(void *pack) invokePack(pack); } else { std::unique_ptr msg = - utils::make_unique(this, pack); + utils::make_unique(this, pack); object_->postMessage(std::move(msg)); } } diff --git a/src/libcamera/include/message.h b/src/libcamera/include/message.h index b4670c0eab76..92717e316cc3 100644 --- a/src/libcamera/include/message.h +++ b/src/libcamera/include/message.h @@ -9,6 +9,8 @@ #include +#include + namespace libcamera { class BoundMethodBase; @@ -20,7 +22,7 @@ class Message public: enum Type { None = 0, - SignalMessage = 1, + InvokeMessage = 1, UserMessage = 1000, }; @@ -41,16 +43,19 @@ private: static std::atomic_uint nextUserType_; }; -class SignalMessage : public Message +class InvokeMessage : public Message { public: - SignalMessage(BoundMethodBase *method, void *pack) - : Message(Message::SignalMessage), method_(method), pack_(pack) - { - } + InvokeMessage(BoundMethodBase *method, void *pack, + bool deleteMethod = false); + ~InvokeMessage(); + void invoke(); + +private: BoundMethodBase *method_; void *pack_; + bool deleteMethod_; }; } /* namespace libcamera */ diff --git a/src/libcamera/message.cpp b/src/libcamera/message.cpp index 8d3376d8a533..f6c39d40fc73 100644 --- a/src/libcamera/message.cpp +++ b/src/libcamera/message.cpp @@ -7,6 +7,8 @@ #include "message.h" +#include + #include "log.h" /** @@ -43,8 +45,8 @@ std::atomic_uint Message::nextUserType_{ Message::UserMessage }; * \brief The message type * \var Message::None * \brief Invalid message type - * \var Message::SignalMessage - * \brief Asynchronous signal delivery across threads + * \var Message::InvokeMessage + * \brief Asynchronous method invocation across threads * \var Message::UserMessage * \brief First value available for user-defined messages */ @@ -107,25 +109,47 @@ Message::Type Message::registerMessageType() } /** - * \class SignalMessage - * \brief A message carrying a Signal across threads + * \class InvokeMessage + * \brief A message carrying a method invocation across threads */ /** - * \fn SignalMessage::SignalMessage() - * \brief Construct a SignalMessage - * \param[in] method The slot that the signal targets - * \param[in] pack The signal arguments + * \brief Construct an InvokeMessage for method invocation on an Object + * \param[in] method The bound method + * \param[in] pack The packed method arguments + * \param[in] deleteMethod True to delete the \a method when the message is + * destroyed */ +InvokeMessage::InvokeMessage(BoundMethodBase *method, void *pack, + bool deleteMethod) + : Message(Message::InvokeMessage), method_(method), pack_(pack), + deleteMethod_(deleteMethod) +{ +} + +InvokeMessage::~InvokeMessage() +{ + if (deleteMethod_) + delete method_; +} + +/** + * \brief Invoke the method bound to InvokeMessage::method_ with arguments + * InvokeMessage::pack_ + */ +void InvokeMessage::invoke() +{ + method_->invokePack(pack_); +} /** - * \var SignalMessage::method_ - * \brief The slot that the signal targets + * \var InvokeMessage::method_ + * \brief The method to be invoked */ /** - * \var SignalMessage::pack_ - * \brief The signal arguments + * \var InvokeMessage::pack_ + * \brief The packed method invocation arguments */ }; /* namespace libcamera */ diff --git a/src/libcamera/object.cpp b/src/libcamera/object.cpp index 0adbc203add8..7d70ce21b5d0 100644 --- a/src/libcamera/object.cpp +++ b/src/libcamera/object.cpp @@ -12,6 +12,7 @@ #include "log.h" #include "message.h" #include "thread.h" +#include "utils.h" /** * \file object.h @@ -88,9 +89,9 @@ void Object::postMessage(std::unique_ptr msg) void Object::message(Message *msg) { switch (msg->type()) { - case Message::SignalMessage: { - SignalMessage *smsg = static_cast(msg); - smsg->method_->invokePack(smsg->pack_); + case Message::InvokeMessage: { + InvokeMessage *iMsg = static_cast(msg); + iMsg->invoke(); break; } @@ -99,6 +100,28 @@ void Object::message(Message *msg) } } +/** + * \fn void Object::invokeMethod(void (T::*func)(Args...), Args... args) + * \brief Invoke a method asynchronously on an Object instance + * \param[in] func The object method to invoke + * \param[in] args The method arguments + * + * This method invokes the member method \a func when control returns to the + * event loop of the object's thread. The method is executed in the object's + * thread with arguments \a args. + * + * Arguments \a args passed by value or reference are copied, while pointers + * are passed untouched. The caller shall ensure that any pointer argument + * remains valid until the method is invoked. + */ + +void Object::invokeMethod(BoundMethodBase *method, void *args) +{ + std::unique_ptr msg = + utils::make_unique(method, args, true); + postMessage(std::move(msg)); +} + /** * \fn Object::thread() * \brief Retrieve the thread the object is bound to From patchwork Mon Aug 12 12:46:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1785 Return-Path: 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 8487D61948 for ; Mon, 12 Aug 2019 14:46:51 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 2532F594 for ; Mon, 12 Aug 2019 14:46:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614011; bh=FIDTwUk9LGgahplfudWCBnnAVDIp1mC/B2/Ibk8v/Pk=; h=From:To:Subject:Date:In-Reply-To:References:From; b=UCg+Fasa3YhVGjUZEH/oVG+Qo2jU5HqmShYiEPSCp0vTvZte3vfj9eP9nVEQxkbnd rA7VysMs7xhDG6Y7cVGlvC6WmVb/iFgLp1+aU7M+1WA+bluhwR9GWq0EIyuLduIgKI yC5nYvpRp4Yu+lGqmmDYba2ibyhNRYxlyN8R+xhg= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:31 +0300 Message-Id: <20190812124642.24287-8-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 07/18] libcamera: object: Notify objects of thread move X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:53 -0000 Send a synchronous message to objects just before they get moved to a new thread. This allows the object to perform any required processing. EventNotifier and Timer objects will use this mechanism to move themselves to the new thread's event disaptcher. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- include/libcamera/object.h | 3 +++ src/libcamera/include/message.h | 1 + src/libcamera/message.cpp | 2 ++ src/libcamera/object.cpp | 26 ++++++++++++++++++++++++++ 4 files changed, 32 insertions(+) diff --git a/include/libcamera/object.h b/include/libcamera/object.h index 869200a57d8c..14b939a9bd3d 100644 --- a/include/libcamera/object.h +++ b/include/libcamera/object.h @@ -27,6 +27,7 @@ public: virtual ~Object(); void postMessage(std::unique_ptr msg); + void sendMessage(Message *msg); template::value>::type * = nullptr> void invokeMethod(void (T::*func)(Args...), Args... args) @@ -52,6 +53,8 @@ private: void invokeMethod(BoundMethodBase *method, void *pack); + void notifyThreadMove(); + void connect(SignalBase *signal); void disconnect(SignalBase *signal); diff --git a/src/libcamera/include/message.h b/src/libcamera/include/message.h index 92717e316cc3..1cfde5669ede 100644 --- a/src/libcamera/include/message.h +++ b/src/libcamera/include/message.h @@ -23,6 +23,7 @@ public: enum Type { None = 0, InvokeMessage = 1, + ThreadMoveMessage = 2, UserMessage = 1000, }; diff --git a/src/libcamera/message.cpp b/src/libcamera/message.cpp index f6c39d40fc73..efafb655c17e 100644 --- a/src/libcamera/message.cpp +++ b/src/libcamera/message.cpp @@ -47,6 +47,8 @@ std::atomic_uint Message::nextUserType_{ Message::UserMessage }; * \brief Invalid message type * \var Message::InvokeMessage * \brief Asynchronous method invocation across threads + * \var Message::ThreadMoveMessage + * \brief Object is being moved to a different thread * \var Message::UserMessage * \brief First value available for user-defined messages */ diff --git a/src/libcamera/object.cpp b/src/libcamera/object.cpp index 7d70ce21b5d0..7c68ec01f78c 100644 --- a/src/libcamera/object.cpp +++ b/src/libcamera/object.cpp @@ -74,6 +74,20 @@ void Object::postMessage(std::unique_ptr msg) thread()->postMessage(std::move(msg), this); } +/** + * \brief Send a message directly to the object + * \param[in] msg The message + * + * This method sends the message \a msg directly to the object, delivering it + * synchronously through the message() method in the current thread. Message + * ownership is not passed to the method, and the caller shall delete the + * message after this call. + */ +void Object::sendMessage(Message *msg) +{ + message(msg); +} + /** * \brief Message handler for the object * \param[in] msg The message @@ -135,6 +149,10 @@ void Object::invokeMethod(BoundMethodBase *method, void *args) * This method moves the object from the current thread to the new \a thread. * It shall be called from the thread in which the object currently lives, * otherwise the behaviour is undefined. + * + * Before the object is moved, a Message::ThreadMoveMessage message is sent to + * it. The message() method can be reimplement in derived classes to be notified + * of the upcoming thread move and perform any required processing. */ void Object::moveToThread(Thread *thread) { @@ -143,9 +161,17 @@ void Object::moveToThread(Thread *thread) if (thread_ == thread) return; + notifyThreadMove(); + thread->moveObject(this); } +void Object::notifyThreadMove() +{ + Message msg(Message::ThreadMoveMessage); + sendMessage(&msg); +} + void Object::connect(SignalBase *signal) { signals_.push_back(signal); From patchwork Mon Aug 12 12:46:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1786 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id ED8226162C for ; Mon, 12 Aug 2019 14:46:51 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 81915327 for ; Mon, 12 Aug 2019 14:46:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614011; bh=kmVYcc9nis1ryUT0ovS1IW2Zz7iLEbw0YytBD+VbYH4=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Um/h2NY41mVPKpC079eRhc/OSEr2oVWI1NR5md5zqFGZLjGKaVlSdBhVTzfnxxdv3 oEPoUrVTbSwmBBdWUOyjMvTarqw1KezwsR9ytAdzxHe7mcCa1TZeB7q4vsuqyucXvG vDs44fiBlLeL4j8Q4ngWBPXPdsi5q2CeS3pFBf4s= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:32 +0300 Message-Id: <20190812124642.24287-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 08/18] test: Add Object::invokeMethod() test X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:53 -0000 The test verifies correct behaviour of asynchronous method invocation for Object instances. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- test/meson.build | 1 + test/object-invoke.cpp | 137 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 test/object-invoke.cpp diff --git a/test/meson.build b/test/meson.build index b2f809e60986..7c9abc630230 100644 --- a/test/meson.build +++ b/test/meson.build @@ -24,6 +24,7 @@ public_tests = [ internal_tests = [ ['camera-sensor', 'camera-sensor.cpp'], ['message', 'message.cpp'], + ['object-invoke', 'object-invoke.cpp'], ['signal-threads', 'signal-threads.cpp'], ['threads', 'threads.cpp'], ] diff --git a/test/object-invoke.cpp b/test/object-invoke.cpp new file mode 100644 index 000000000000..7221930f4380 --- /dev/null +++ b/test/object-invoke.cpp @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * object-invoke.cpp - Cross-thread Object method invocation test + */ + +#include +#include +#include + +#include +#include +#include + +#include "thread.h" +#include "test.h" + +using namespace std; +using namespace libcamera; + +class InvokedObject : public Object +{ +public: + enum Status { + NoCall, + InvalidThread, + CallReceived, + }; + + InvokedObject() + : status_(NoCall) + { + } + + Status status() const { return status_; } + int value() const { return value_; } + void reset() + { + status_ = NoCall; + value_ = 0; + } + + void method(int value) + { + if (Thread::current() != thread()) + status_ = InvalidThread; + else + status_ = CallReceived; + + value_ = value; + } + +private: + Status status_; + int value_; +}; + +class ObjectInvokeTest : public Test +{ +protected: + int run() + { + EventDispatcher *dispatcher = CameraManager::instance()->eventDispatcher(); + InvokedObject object; + + /* + * Test that method invocation in the same thread goes through + * the event dispatcher. + */ + object.invokeMethod(&InvokedObject::method, 42); + + if (object.status() != InvokedObject::NoCall) { + cerr << "Method not invoked asynchronously" << endl; + return TestFail; + } + + dispatcher->processEvents(); + + switch (object.status()) { + case InvokedObject::NoCall: + cout << "Method not invoked for main thread" << endl; + return TestFail; + case InvokedObject::InvalidThread: + cout << "Method invoked in incorrect thread for main thread" << endl; + return TestFail; + default: + break; + } + + if (object.value() != 42) { + cout << "Method invoked with incorrect value for main thread" << endl; + return TestFail; + } + + /* + * Move the object to a thread and verify that the method is + * delivered in the correct thread. + */ + object.reset(); + object.moveToThread(&thread_); + + thread_.start(); + + object.invokeMethod(&InvokedObject::method, 42); + this_thread::sleep_for(chrono::milliseconds(100)); + + switch (object.status()) { + case InvokedObject::NoCall: + cout << "Method not invoked for custom thread" << endl; + return TestFail; + case InvokedObject::InvalidThread: + cout << "Method invoked in incorrect thread for custom thread" << endl; + return TestFail; + default: + break; + } + + if (object.value() != 42) { + cout << "Method invoked with incorrect value for custom thread" << endl; + return TestFail; + } + + return TestPass; + } + + void cleanup() + { + thread_.exit(0); + thread_.wait(); + } + +private: + Thread thread_; +}; + +TEST_REGISTER(ObjectInvokeTest) From patchwork Mon Aug 12 12:46:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1787 Return-Path: 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 5327A61630 for ; Mon, 12 Aug 2019 14:46:52 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E0EE2124E for ; Mon, 12 Aug 2019 14:46:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614012; bh=WJa+p8PRwFmv9fu9KCs0M+Vph6mf0XLI6ujdPy3yOxs=; h=From:To:Subject:Date:In-Reply-To:References:From; b=d25IRJ2WckX41Lxh7BlCnTkm9sr1B/ndc2h1K2x+3cBM+xTcDeLzNMFe4yaOwIRQK 3oAr/MXJYTUSd6Ao2FeFGpvT2dkkY6WzXxrPux9DXcZRb4bpkBSHz6/q7+FkcqA14I LTcYL1+8UgiaxRtzz9BoKboVGP9yJgQE1uzkmIJ8= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:33 +0300 Message-Id: <20190812124642.24287-10-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 09/18] test: Add Object class thread affinity test X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:53 -0000 The test verifies thread affinity and thread move notifications. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- test/meson.build | 1 + test/object.cpp | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 test/object.cpp diff --git a/test/meson.build b/test/meson.build index 7c9abc630230..c6601813db78 100644 --- a/test/meson.build +++ b/test/meson.build @@ -24,6 +24,7 @@ public_tests = [ internal_tests = [ ['camera-sensor', 'camera-sensor.cpp'], ['message', 'message.cpp'], + ['object', 'object.cpp'], ['object-invoke', 'object-invoke.cpp'], ['signal-threads', 'signal-threads.cpp'], ['threads', 'threads.cpp'], diff --git a/test/object.cpp b/test/object.cpp new file mode 100644 index 000000000000..3f1f700d1b39 --- /dev/null +++ b/test/object.cpp @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * object.cpp - Object tests + */ + +#include + +#include + +#include "message.h" +#include "thread.h" + +#include "test.h" + +using namespace std; +using namespace libcamera; + +class InstrumentedObject : public Object +{ +public: + enum Status { + NoMessage, + MessageReceived, + }; + + InstrumentedObject() + : status_(NoMessage) + { + } + + Status status() const { return status_; } + void reset() { status_ = NoMessage; } + +protected: + void message(Message *msg) override + { + if (msg->type() == Message::ThreadMoveMessage) + status_ = MessageReceived; + + Object::message(msg); + } + +private: + Status status_; +}; + +class ObjectTest : public Test +{ +protected: + int init() + { + a_ = new InstrumentedObject(); + return TestPass; + } + + int run() + { + /* Verify that moving an object to a different thread succeeds. */ + a_->moveToThread(&thread_); + + if (a_->thread() != &thread_ || a_->thread() == Thread::current()) { + cout << "Failed to move object to thread" << endl; + return TestFail; + } + + /* Verify that objects receive a ThreadMoveMessage when moved. */ + if (a_->status() != InstrumentedObject::MessageReceived) { + cout << "Moving object didn't deliver ThreadMoveMessage" << endl; + return TestFail; + } + + return TestPass; + } + + void cleanup() + { + delete a_; + } + +private: + InstrumentedObject *a_; + + Thread thread_; +}; + +TEST_REGISTER(ObjectTest) From patchwork Mon Aug 12 12:46:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1788 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B99D86162B for ; Mon, 12 Aug 2019 14:46:52 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 49578327 for ; Mon, 12 Aug 2019 14:46:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614012; bh=GJPQyM1vOKlrUvUVGpr/bK32laCc2K+ei1Mz7VaXxYk=; h=From:To:Subject:Date:In-Reply-To:References:From; b=K9GGxKkv8UH/NAt0HRPNu5OCg/B9yRA4EmwNw9M6J7HGEsZOLcbbO7M3sD2NyVjot Myb4gFYrzJdNRo9xzMGCep3OgedFqpEy7ALnQFZw/Ar4YTzuuhe+ixHOCXNC+e+S/i bciQAkNM5J//FYiyBS4YwQoWe+t7eKj2VrdJALjg= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:34 +0300 Message-Id: <20190812124642.24287-11-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 10/18] libcamera: camera_manager: Bind CameraManager to threads X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:53 -0000 The CameraManager class uses the event dispatcher of the current thread. This makes the CameraManager::eventDispatcher() and CameraManager::setEventDispatcher() methods inconsistent, as they access different event dispatcher instances depending on the calling thread. Fix this by inheriting from the Object class, which binds the CameraManager to a thread, and use the event dispatcher of the bound thread. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- include/libcamera/camera_manager.h | 4 +++- src/libcamera/camera_manager.cpp | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/libcamera/camera_manager.h b/include/libcamera/camera_manager.h index 0e8881baba40..ff7d4c7c6745 100644 --- a/include/libcamera/camera_manager.h +++ b/include/libcamera/camera_manager.h @@ -11,6 +11,8 @@ #include #include +#include + namespace libcamera { class Camera; @@ -18,7 +20,7 @@ class DeviceEnumerator; class EventDispatcher; class PipelineHandler; -class CameraManager +class CameraManager : public Object { public: int start(); diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index 2cf014233b05..4a880684c5cb 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -248,7 +248,7 @@ CameraManager *CameraManager::instance() */ void CameraManager::setEventDispatcher(std::unique_ptr dispatcher) { - Thread::current()->setEventDispatcher(std::move(dispatcher)); + thread()->setEventDispatcher(std::move(dispatcher)); } /** @@ -264,7 +264,7 @@ void CameraManager::setEventDispatcher(std::unique_ptr dispatch */ EventDispatcher *CameraManager::eventDispatcher() { - return Thread::current()->eventDispatcher(); + return thread()->eventDispatcher(); } } /* namespace libcamera */ From patchwork Mon Aug 12 12:46:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1789 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2A3396194E for ; Mon, 12 Aug 2019 14:46:53 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id AD236133B for ; Mon, 12 Aug 2019 14:46:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614012; bh=yCQTUfaNdbhyLf+PSvrMPNrHxp/XsLuLe8mKG+u8mG4=; h=From:To:Subject:Date:In-Reply-To:References:From; b=t/s2fZcUXH03MW4BnYpHeuo78JvC+Cug8/XQpB/Yc6dqx89xKoVmewV0liPdTt7tl EchIu1QwXoI8Qx2OcBYupGnXkEkA5M0XX3KOJS9AhCOHd26D/EbcSO6v5GFxhxWRBr z38wAwECpMXhcOyd1S7iYASqRv4bAkhAluJBG5/U= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:35 +0300 Message-Id: <20190812124642.24287-12-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 11/18] libcamera: event_notifier: Bind event notifiers to threads X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:53 -0000 The EventNotifier instances are registered with the event dispatcher instance of the CameraManager. This makes it impossible to use event notifiers in other threads. Fix this by inheriting from Object, which allows binding instances to a thread, and register them with the event dispatcher for the thread they are bound to. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- include/libcamera/event_notifier.h | 8 +++++++- src/libcamera/event_notifier.cpp | 17 ++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/include/libcamera/event_notifier.h b/include/libcamera/event_notifier.h index 1e9b6da1340c..f80945c743dc 100644 --- a/include/libcamera/event_notifier.h +++ b/include/libcamera/event_notifier.h @@ -7,11 +7,14 @@ #ifndef __LIBCAMERA_EVENT_NOTIFIER_H__ #define __LIBCAMERA_EVENT_NOTIFIER_H__ +#include #include namespace libcamera { -class EventNotifier +class Message; + +class EventNotifier : public Object { public: enum Type { @@ -31,6 +34,9 @@ public: Signal activated; +protected: + void message(Message *msg) override; + private: int fd_; Type type_; diff --git a/src/libcamera/event_notifier.cpp b/src/libcamera/event_notifier.cpp index b32c7ed2d315..515e6d1770a1 100644 --- a/src/libcamera/event_notifier.cpp +++ b/src/libcamera/event_notifier.cpp @@ -10,6 +10,9 @@ #include #include +#include "message.h" +#include "thread.h" + /** * \file event_notifier.h * \brief File descriptor event notifier @@ -103,7 +106,7 @@ void EventNotifier::setEnabled(bool enable) enabled_ = enable; - EventDispatcher *dispatcher = CameraManager::instance()->eventDispatcher(); + EventDispatcher *dispatcher = thread()->eventDispatcher(); if (enable) dispatcher->registerEventNotifier(this); else @@ -119,4 +122,16 @@ void EventNotifier::setEnabled(bool enable) * parameter. */ +void EventNotifier::message(Message *msg) +{ + if (msg->type() == Message::ThreadMoveMessage) { + if (enabled_) { + setEnabled(false); + invokeMethod(this, &EventNotifier::setEnabled, true); + } + } + + Object::message(msg); +} + } /* namespace libcamera */ From patchwork Mon Aug 12 12:46:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1790 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A653D6194D for ; Mon, 12 Aug 2019 14:46:53 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 3C086594 for ; Mon, 12 Aug 2019 14:46:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614013; bh=ZlbB3R8I8PLgHfRPqB6j65JLevL/YJbu2SIQ8Nl4tpM=; h=From:To:Subject:Date:In-Reply-To:References:From; b=hulO7jW+kcEr3mrdZthWqUfwseM01SW4UGYQBgWHmxSy7Nnq9kfMtuZhANgN/CH2s RMvNFWA1zrTEGVgdyHDl+XE2xLPU78Ue7dL2chzFbDx+iTUzyHHW8UBDuid7Xi6YYr nO5s0iIOsLcTb/NWrh2Gg99V5pCFzqe2duYQJY8M= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:36 +0300 Message-Id: <20190812124642.24287-13-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 12/18] libcamera: timer: Bind timers to threads X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:54 -0000 The Timer instances are registered with the event dispatcher instance of the CameraManager. This makes it impossible to use timers in other threads. Fix this by inheriting from Object, which allows binding instances to a thread, and register them with the event dispatcher for the thread they are bound to. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- include/libcamera/timer.h | 11 ++++++++++- src/libcamera/timer.cpp | 28 ++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/include/libcamera/timer.h b/include/libcamera/timer.h index f082339b1fed..853808e07da8 100644 --- a/include/libcamera/timer.h +++ b/include/libcamera/timer.h @@ -9,11 +9,14 @@ #include +#include #include namespace libcamera { -class Timer +class Message; + +class Timer : public Object { public: Timer(); @@ -28,7 +31,13 @@ public: Signal timeout; +protected: + void message(Message *msg) override; + private: + void registerTimer(); + void unregisterTimer(); + unsigned int interval_; uint64_t deadline_; }; diff --git a/src/libcamera/timer.cpp b/src/libcamera/timer.cpp index 0dcb4e767be3..21c0a444cdce 100644 --- a/src/libcamera/timer.cpp +++ b/src/libcamera/timer.cpp @@ -13,6 +13,8 @@ #include #include "log.h" +#include "message.h" +#include "thread.h" /** * \file timer.h @@ -66,7 +68,7 @@ void Timer::start(unsigned int msec) << "Starting timer " << this << " with interval " << msec << ": deadline " << deadline_; - CameraManager::instance()->eventDispatcher()->registerTimer(this); + registerTimer(); } /** @@ -79,11 +81,21 @@ void Timer::start(unsigned int msec) */ void Timer::stop() { - CameraManager::instance()->eventDispatcher()->unregisterTimer(this); + unregisterTimer(); deadline_ = 0; } +void Timer::registerTimer() +{ + thread()->eventDispatcher()->registerTimer(this); +} + +void Timer::unregisterTimer() +{ + thread()->eventDispatcher()->unregisterTimer(this); +} + /** * \brief Check if the timer is running * \return True if the timer is running, false otherwise @@ -112,4 +124,16 @@ bool Timer::isRunning() const * The timer pointer is passed as a parameter. */ +void Timer::message(Message *msg) +{ + if (msg->type() == Message::ThreadMoveMessage) { + if (deadline_) { + unregisterTimer(); + invokeMethod(this, &Timer::registerTimer); + } + } + + Object::message(msg); +} + } /* namespace libcamera */ From patchwork Mon Aug 12 12:46:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1791 Return-Path: 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 10E9461623 for ; Mon, 12 Aug 2019 14:46:54 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 9893A124E for ; Mon, 12 Aug 2019 14:46:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614013; bh=VSXTWHfirqfgjeX+OumSYkxyH4jZlyyj00vsHloC1fE=; h=From:To:Subject:Date:In-Reply-To:References:From; b=rqKDMwoebnjrzJpwmOQ6b9+iGUpoYzYw8qTRMzw0B7dIVt+8uYV1zHpdzYBotV+tm A/7RPUzSv0Zt+ATwYoMqz5YSPyP5JaYCH3N4KnNxoU35GRYJLRZ6nEIyoXwSX0LNet Xsv3YSOI/bGaGfkmvknRHtpOBB7dyVBQfSOgpvoI= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:37 +0300 Message-Id: <20190812124642.24287-14-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 13/18] test: Add EventNotifier thread move test X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:54 -0000 The test verifies correct behaviour of an enabled event notifier moved to a different thread. Signed-off-by: Laurent Pinchart --- src/libcamera/event_notifier.cpp | 2 +- test/event-thread.cpp | 112 +++++++++++++++++++++++++++++++ test/meson.build | 1 + 3 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 test/event-thread.cpp diff --git a/src/libcamera/event_notifier.cpp b/src/libcamera/event_notifier.cpp index 515e6d1770a1..96be27601982 100644 --- a/src/libcamera/event_notifier.cpp +++ b/src/libcamera/event_notifier.cpp @@ -127,7 +127,7 @@ void EventNotifier::message(Message *msg) if (msg->type() == Message::ThreadMoveMessage) { if (enabled_) { setEnabled(false); - invokeMethod(this, &EventNotifier::setEnabled, true); + invokeMethod(&EventNotifier::setEnabled, true); } } diff --git a/test/event-thread.cpp b/test/event-thread.cpp new file mode 100644 index 000000000000..4a82d49b94f1 --- /dev/null +++ b/test/event-thread.cpp @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * event-thread.cpp - Threaded event test + */ + +#include +#include +#include +#include + +#include +#include + +#include "test.h" +#include "thread.h" + +using namespace std; +using namespace libcamera; + +class EventHandler : public Object +{ +public: + EventHandler() + { + pipe(pipefd_); + + notifier_ = new EventNotifier(pipefd_[0], EventNotifier::Read); + notifier_->activated.connect(this, &EventHandler::readReady); + } + + ~EventHandler() + { + delete notifier_; + + close(pipefd_[0]); + close(pipefd_[1]); + } + + int notify() + { + std::string data("H2G2"); + ssize_t ret; + + memset(data_, 0, sizeof(data_)); + size_ = 0; + + ret = write(pipefd_[1], data.data(), data.size()); + if (ret < 0) { + cout << "Pipe write failed" << endl; + return TestFail; + } + + return TestPass; + } + + bool notified() const + { + return notified_; + } + + void moveToThread(Thread *thread) + { + Object::moveToThread(thread); + notifier_->moveToThread(thread); + } + +private: + void readReady(EventNotifier *notifier) + { + size_ = read(notifier->fd(), data_, sizeof(data_)); + notified_ = true; + } + + EventNotifier *notifier_; + + int pipefd_[2]; + + bool notified_; + char data_[16]; + ssize_t size_; +}; + +class EventThreadTest : public Test +{ +protected: + int run() + { + Thread thread; + thread.start(); + + EventHandler handler; + handler.notify(); + handler.moveToThread(&thread); + + this_thread::sleep_for(chrono::milliseconds(100)); + + /* Must stop thread before destroying the handler. */ + thread.exit(0); + thread.wait(); + + if (!handler.notified()) { + cout << "Thread event handling test failed" << endl; + return TestFail; + } + + return TestPass; + } +}; + +TEST_REGISTER(EventThreadTest) diff --git a/test/meson.build b/test/meson.build index c6601813db78..f695ffd7be44 100644 --- a/test/meson.build +++ b/test/meson.build @@ -23,6 +23,7 @@ public_tests = [ internal_tests = [ ['camera-sensor', 'camera-sensor.cpp'], + ['event-thread', 'event-thread.cpp'], ['message', 'message.cpp'], ['object', 'object.cpp'], ['object-invoke', 'object-invoke.cpp'], From patchwork Mon Aug 12 12:46:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1792 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7156F6195A for ; Mon, 12 Aug 2019 14:46:54 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 052AC133B for ; Mon, 12 Aug 2019 14:46:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614014; bh=is3HMNAflaXmLUYuYampcgBRRq3YdRYnFz1/UWukpqo=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Eq34mV9BPVCPMSlKNWIzE3tEZhH+wt1On5xJApB+z+1Z/VTFPvoXY6ruNd5WvyxKE i3c0jRV/ApgGkrdWVwK7PM00m6eoGc4Fw/D0nOtWho9YFvwDrrbCygJ8BR21fHBzjx wa50B79A9rWs5alA72icLA96L9p5fRCaCvpGiius= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:38 +0300 Message-Id: <20190812124642.24287-15-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 14/18] test: Add Timer thread move test X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:55 -0000 The test verifies correct behaviour of a running timer moved to a different thread. Signed-off-by: Laurent Pinchart --- src/libcamera/timer.cpp | 2 +- test/meson.build | 1 + test/timer-thread.cpp | 78 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 test/timer-thread.cpp diff --git a/src/libcamera/timer.cpp b/src/libcamera/timer.cpp index 21c0a444cdce..f45061d4c6f6 100644 --- a/src/libcamera/timer.cpp +++ b/src/libcamera/timer.cpp @@ -129,7 +129,7 @@ void Timer::message(Message *msg) if (msg->type() == Message::ThreadMoveMessage) { if (deadline_) { unregisterTimer(); - invokeMethod(this, &Timer::registerTimer); + invokeMethod(&Timer::registerTimer); } } diff --git a/test/meson.build b/test/meson.build index f695ffd7be44..05265b7d4976 100644 --- a/test/meson.build +++ b/test/meson.build @@ -29,6 +29,7 @@ internal_tests = [ ['object-invoke', 'object-invoke.cpp'], ['signal-threads', 'signal-threads.cpp'], ['threads', 'threads.cpp'], + ['timer-thread', 'timer-thread.cpp'], ] foreach t : public_tests diff --git a/test/timer-thread.cpp b/test/timer-thread.cpp new file mode 100644 index 000000000000..b9373050068c --- /dev/null +++ b/test/timer-thread.cpp @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * timer-thread.cpp - Threaded timer test + */ + +#include +#include + +#include + +#include "test.h" +#include "thread.h" + +using namespace std; +using namespace libcamera; + +class TimeoutHandler : public Object +{ +public: + TimeoutHandler() + : timeout_(false) + { + timer_.timeout.connect(this, &TimeoutHandler::timeoutHandler); + timer_.start(100); + } + + bool timeout() const + { + return timeout_; + } + + void moveToThread(Thread *thread) + { + Object::moveToThread(thread); + timer_.moveToThread(thread); + } + +private: + void timeoutHandler(Timer *timer) + { + timeout_ = true; + } + + Timer timer_; + bool timeout_; +}; + +class TimerThreadTest : public Test +{ +protected: + int run() + { + Thread thread; + thread.start(); + + TimeoutHandler timeout; + timeout.moveToThread(&thread); + + this_thread::sleep_for(chrono::milliseconds(100)); + + /* Must stop thread before destroying timeout. */ + thread.exit(0); + thread.wait(); + + if (!timeout.timeout()) { + cout << "Timer expiration test failed" << endl; + return TestFail; + } + + return TestPass; + } + +private: +}; + +TEST_REGISTER(TimerThreadTest) From patchwork Mon Aug 12 12:46:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1793 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C5B6461965 for ; Mon, 12 Aug 2019 14:46:54 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 62720327 for ; Mon, 12 Aug 2019 14:46:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614014; bh=Olctu71DA8JkmR8208+oSL5X2yoXETwUTiYkft+WM6Q=; h=From:To:Subject:Date:In-Reply-To:References:From; b=I2+z4YElnuWqOTA4iSKJJtwVclPcCY0sstp7BdlYNljCizBb5dQHzj6SF53Np/94C uq+C67YLEyM1PyuQOjtYE6fGUGA5NOawkBrYuTaPq9gXqezuQAuKVXWoS+LieTnya4 JBcRSjESbUpUrYCttrn5RWxjb693UGPXSYxvGPTM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:39 +0300 Message-Id: <20190812124642.24287-16-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 15/18] libcamera: object: Create parent-child relationships X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:56 -0000 Add a parent Object to Object instances, and track the parent-children relationships. Children are bound to the same thread as their parent, and moving an Object to a thread automatically moves all its children. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- include/libcamera/object.h | 8 ++++- src/libcamera/include/thread.h | 2 ++ src/libcamera/object.cpp | 65 ++++++++++++++++++++++++++++------ src/libcamera/thread.cpp | 12 ++++++- 4 files changed, 74 insertions(+), 13 deletions(-) diff --git a/include/libcamera/object.h b/include/libcamera/object.h index 14b939a9bd3d..4a0a272b875a 100644 --- a/include/libcamera/object.h +++ b/include/libcamera/object.h @@ -9,6 +9,7 @@ #include #include +#include #include @@ -23,7 +24,7 @@ class Thread; class Object { public: - Object(); + Object(Object *parent = nullptr); virtual ~Object(); void postMessage(std::unique_ptr msg); @@ -42,6 +43,8 @@ public: Thread *thread() const { return thread_; } void moveToThread(Thread *thread); + Object *parent() const { return parent_; } + protected: virtual void message(Message *msg); @@ -58,6 +61,9 @@ private: void connect(SignalBase *signal); void disconnect(SignalBase *signal); + Object *parent_; + std::vector children_; + Thread *thread_; std::list signals_; unsigned int pendingMessages_; diff --git a/src/libcamera/include/thread.h b/src/libcamera/include/thread.h index 630abb49534f..37edd4f5138b 100644 --- a/src/libcamera/include/thread.h +++ b/src/libcamera/include/thread.h @@ -61,6 +61,8 @@ private: friend class ThreadMain; void moveObject(Object *object); + void moveObject(Object *object, ThreadData *currentData, + ThreadData *targetData); std::thread thread_; ThreadData *data_; diff --git a/src/libcamera/object.cpp b/src/libcamera/object.cpp index 7c68ec01f78c..57cd6fefe20f 100644 --- a/src/libcamera/object.cpp +++ b/src/libcamera/object.cpp @@ -7,6 +7,8 @@ #include +#include + #include #include "log.h" @@ -21,6 +23,8 @@ namespace libcamera { +LOG_DEFINE_CATEGORY(Object) + /** * \class Object * \brief Base object to support automatic signal disconnection @@ -29,10 +33,11 @@ namespace libcamera { * slots. By inheriting from Object, an object is automatically disconnected * from all connected signals when it gets destroyed. * - * Object instances are bound to the thread in which they're created. When a - * message is posted to an object, its handler will run in the object's thread. - * This allows implementing easy message passing between threads by inheriting - * from the Object class. + * Object instances are bound to the thread of their parent, or the thread in + * which they're created when they have no parent. When a message is posted to + * an object, its handler will run in the object's thread. This allows + * implementing easy message passing between threads by inheriting from the + * Object class. * * Object slots connected to signals will also run in the context of the * object's thread, regardless of whether the signal is emitted in the same or @@ -41,10 +46,20 @@ namespace libcamera { * \sa Message, Signal, Thread */ -Object::Object() - : pendingMessages_(0) +/** + * \brief Construct an Object instance + * \param[in] parent The object parent + * + * The new Object instance is bound to the thread of its \a parent, or to the + * current thread if the \a parent is nullptr. + */ +Object::Object(Object *parent) + : parent_(parent), pendingMessages_(0) { - thread_ = Thread::current(); + thread_ = parent ? parent->thread() : Thread::current(); + + if (parent) + parent->children_.push_back(this); } Object::~Object() @@ -54,6 +69,16 @@ Object::~Object() if (pendingMessages_) thread()->removeMessages(this); + + if (parent_) { + auto it = std::find(parent_->children_.begin(), + parent_->children_.end(), this); + ASSERT(it != parent_->children_.end()); + parent_->children_.erase(it); + } + + for (auto child : children_) + child->parent_ = nullptr; } /** @@ -143,16 +168,19 @@ void Object::invokeMethod(BoundMethodBase *method, void *args) */ /** - * \brief Move the object to a different thread + * \brief Move the object and all its children to a different thread * \param[in] thread The target thread * - * This method moves the object from the current thread to the new \a thread. - * It shall be called from the thread in which the object currently lives, - * otherwise the behaviour is undefined. + * This method moves the object and all its children from the current thread to + * the new \a thread. It shall be called from the thread in which the object + * currently lives, otherwise the behaviour is undefined. * * Before the object is moved, a Message::ThreadMoveMessage message is sent to * it. The message() method can be reimplement in derived classes to be notified * of the upcoming thread move and perform any required processing. + * + * Moving an object that has a parent is not allowed, and causes undefined + * behaviour. */ void Object::moveToThread(Thread *thread) { @@ -161,6 +189,12 @@ void Object::moveToThread(Thread *thread) if (thread_ == thread) return; + if (parent_) { + LOG(Object, Error) + << "Moving object to thread with a parent is not permitted"; + return; + } + notifyThreadMove(); thread->moveObject(this); @@ -170,8 +204,17 @@ void Object::notifyThreadMove() { Message msg(Message::ThreadMoveMessage); sendMessage(&msg); + + for (auto child : children_) + child->notifyThreadMove(); } +/** + * \fn Object::parent() + * \brief Retrieve the object's parent + * \return The object's parent + */ + void Object::connect(SignalBase *signal) { signals_.push_back(signal); diff --git a/src/libcamera/thread.cpp b/src/libcamera/thread.cpp index 24422f7b7bd0..872ad1bd9d69 100644 --- a/src/libcamera/thread.cpp +++ b/src/libcamera/thread.cpp @@ -448,7 +448,7 @@ void Thread::dispatchMessages() } /** - * \brief Move an \a object to the thread + * \brief Move an \a object and all its children to the thread * \param[in] object The object */ void Thread::moveObject(Object *object) @@ -460,6 +460,12 @@ void Thread::moveObject(Object *object) MutexLocker lockerTo(targetData->mutex_, std::defer_lock); std::lock(lockerFrom, lockerTo); + moveObject(object, currentData, targetData); +} + +void Thread::moveObject(Object *object, ThreadData *currentData, + ThreadData *targetData) +{ /* Move pending messages to the message queue of the new thread. */ if (object->pendingMessages_) { unsigned int movedMessages = 0; @@ -483,6 +489,10 @@ void Thread::moveObject(Object *object) } object->thread_ = this; + + /* Move all children. */ + for (auto child : object->children_) + moveObject(child, currentData, targetData); } }; /* namespace libcamera */ From patchwork Mon Aug 12 12:46:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1794 Return-Path: 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 2B1EF6195A for ; Mon, 12 Aug 2019 14:46:55 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BC2DE594 for ; Mon, 12 Aug 2019 14:46:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614014; bh=M0+wN8yq297lrDRjgJjjSAmy51AbU9mkRLAcXzzjGDI=; h=From:To:Subject:Date:In-Reply-To:References:From; b=ZMiOx9O+uTHXCJR96vQ8ra6snEW25jW1fHCuJ0PLs/44s+o0FWhSGp/aYDgOcY/NQ EL1YBnJxzTk16yWC47Y9ZNqCbVYG9Wc5jHMqmVhSPCid2bIVncYQJod8KcIt/+0kVK 2NCpiEii3U4pdkWNciVew9ckGD1oTnRsAEcxqVCE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:40 +0300 Message-Id: <20190812124642.24287-17-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 16/18] libcamera: Add parent argument to constructors of Object-derived classes X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:56 -0000 Now that the Object class implements parent-child relationships, make it possible to create EventNotifier and Timer instances with a parent by adding a parent argument to their constructors. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- include/libcamera/event_notifier.h | 2 +- include/libcamera/timer.h | 2 +- src/libcamera/event_notifier.cpp | 5 +++-- src/libcamera/timer.cpp | 5 +++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/libcamera/event_notifier.h b/include/libcamera/event_notifier.h index f80945c743dc..a37b02eee4b7 100644 --- a/include/libcamera/event_notifier.h +++ b/include/libcamera/event_notifier.h @@ -23,7 +23,7 @@ public: Exception, }; - EventNotifier(int fd, Type type); + EventNotifier(int fd, Type type, Object *parent = nullptr); virtual ~EventNotifier(); Type type() const { return type_; } diff --git a/include/libcamera/timer.h b/include/libcamera/timer.h index 853808e07da8..f47b6a58404f 100644 --- a/include/libcamera/timer.h +++ b/include/libcamera/timer.h @@ -19,7 +19,7 @@ class Message; class Timer : public Object { public: - Timer(); + Timer(Object *parent = nullptr); ~Timer(); void start(unsigned int msec); diff --git a/src/libcamera/event_notifier.cpp b/src/libcamera/event_notifier.cpp index 96be27601982..687969b0a8d1 100644 --- a/src/libcamera/event_notifier.cpp +++ b/src/libcamera/event_notifier.cpp @@ -61,9 +61,10 @@ namespace libcamera { * \brief Construct an event notifier with a file descriptor and event type * \param[in] fd The file descriptor to monitor * \param[in] type The event type to monitor + * \param[in] parent The parent Object */ -EventNotifier::EventNotifier(int fd, Type type) - : fd_(fd), type_(type), enabled_(false) +EventNotifier::EventNotifier(int fd, Type type, Object *parent) + : Object(parent), fd_(fd), type_(type), enabled_(false) { setEnabled(true); } diff --git a/src/libcamera/timer.cpp b/src/libcamera/timer.cpp index f45061d4c6f6..c61d77e5128f 100644 --- a/src/libcamera/timer.cpp +++ b/src/libcamera/timer.cpp @@ -39,9 +39,10 @@ LOG_DEFINE_CATEGORY(Timer) /** * \brief Construct a timer + * \param[in] parent The parent Object */ -Timer::Timer() - : interval_(0), deadline_(0) +Timer::Timer(Object *parent) + : Object(parent), interval_(0), deadline_(0) { } From patchwork Mon Aug 12 12:46:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1795 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A9D6A61624 for ; Mon, 12 Aug 2019 14:46:55 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 286BA124E for ; Mon, 12 Aug 2019 14:46:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614015; bh=M5yZZhIyI6A0vTz7PBhZBRtlmsxekZjqXs1jGxI2tMQ=; h=From:To:Subject:Date:In-Reply-To:References:From; b=tGZir4OZfo4zL++omNCFZ2LAy6CAZ0IPc54/4pzLRrngUDsgMGLFFEmOo+V4Jvl7m feM6GNpUPm7kQUTQN1vH3K/N7naU0WsJZrfSLaHS/TcSkdvMytMuq+jvjMQcyxzmMv inZUIQlwsDREBPfdI9bgJGNMW+LR+RwoSc2zlUY0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:41 +0300 Message-Id: <20190812124642.24287-18-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 17/18] test: object: Extend object test to verify parent-child relationships X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:56 -0000 The test verifies correct behaviour of parent-child relationships in relation to thread affinity. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- test/object.cpp | 82 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 6 deletions(-) diff --git a/test/object.cpp b/test/object.cpp index 3f1f700d1b39..16118971c755 100644 --- a/test/object.cpp +++ b/test/object.cpp @@ -25,8 +25,8 @@ public: MessageReceived, }; - InstrumentedObject() - : status_(NoMessage) + InstrumentedObject(Object *parent = nullptr) + : Object(parent), status_(NoMessage) { } @@ -51,22 +51,82 @@ class ObjectTest : public Test protected: int init() { + /* + * Create a hierarchy of objects: + * A -> B -> C + * \->D + * E + */ a_ = new InstrumentedObject(); + b_ = new InstrumentedObject(a_); + c_ = new InstrumentedObject(b_); + d_ = new InstrumentedObject(a_); + e_ = new InstrumentedObject(); + f_ = nullptr; + return TestPass; } int run() { - /* Verify that moving an object to a different thread succeeds. */ - a_->moveToThread(&thread_); + /* Verify the parent-child relationships. */ + if (a_->parent() != nullptr || b_->parent() != a_ || + c_->parent() != b_ || d_->parent() != a_ || + e_->parent() != nullptr) { + cout << "Incorrect parent-child relationships" << endl; + return TestFail; + } - if (a_->thread() != &thread_ || a_->thread() == Thread::current()) { + /* + * Verify that moving an object with no parent to a different + * thread succeeds. + */ + e_->moveToThread(&thread_); + + if (e_->thread() != &thread_ || e_->thread() == Thread::current()) { cout << "Failed to move object to thread" << endl; return TestFail; } + /* + * Verify that moving an object with a parent to a different + * thread fails. This results in an undefined behaviour, the + * test thus depends on the internal implementation returning + * without performing any change. + */ + b_->moveToThread(&thread_); + + if (b_->thread() != Thread::current()) { + cout << "Moving object with parent to thread shouldn't succeed" << endl; + return TestFail; + } + + /* + * Verify that moving an object with children to a different + * thread moves all the children. + */ + a_->moveToThread(&thread_); + + if (a_->thread() != &thread_ || b_->thread() != &thread_ || + c_->thread() != &thread_ || d_->thread() != &thread_) { + cout << "Failed to move children to thread" << endl; + return TestFail; + } + + /* Verify that objects are bound to the thread of their parent. */ + f_ = new InstrumentedObject(d_); + + if (f_->thread() != &thread_) { + cout << "Failed to bind child to parent thread" << endl; + return TestFail; + } + /* Verify that objects receive a ThreadMoveMessage when moved. */ - if (a_->status() != InstrumentedObject::MessageReceived) { + if (a_->status() != InstrumentedObject::MessageReceived || + b_->status() != InstrumentedObject::MessageReceived || + c_->status() != InstrumentedObject::MessageReceived || + d_->status() != InstrumentedObject::MessageReceived || + e_->status() != InstrumentedObject::MessageReceived) { cout << "Moving object didn't deliver ThreadMoveMessage" << endl; return TestFail; } @@ -77,10 +137,20 @@ protected: void cleanup() { delete a_; + delete b_; + delete c_; + delete d_; + delete e_; + delete f_; } private: InstrumentedObject *a_; + InstrumentedObject *b_; + InstrumentedObject *c_; + InstrumentedObject *d_; + InstrumentedObject *e_; + InstrumentedObject *f_; Thread thread_; }; From patchwork Mon Aug 12 12:46:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1796 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0A34260E38 for ; Mon, 12 Aug 2019 14:46:56 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 95E7713CC for ; Mon, 12 Aug 2019 14:46:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1565614015; bh=9FXzsXVjHAzgwSwp7ID6YmB7uFpW5JN8wCJsYD6umN0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Tub1ZnCwvvJqz9fCpxVY/GMcNUt1fVxEFRROjncMn7R7VZ6bQ1N4Iqn81rr6tYRf/ FfmGYqP2qaGVtNlt7m8uBGTc+WJUuvXBTkNsPd30J0yOU1dWkKmZdmx0ksRB5VgOm+ S9LZyjAw1SxfJZTHRR1cXnzH2xOVJy6kpF7NFbzU= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 12 Aug 2019 15:46:42 +0300 Message-Id: <20190812124642.24287-19-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> References: <20190812124642.24287-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 18/18] test: Simplify tests with parent-child relationships X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 12:46:56 -0000 Create object instances with a parent to avoid the need for reparenting objects manually. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- test/event-thread.cpp | 8 +------- test/timer-thread.cpp | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/test/event-thread.cpp b/test/event-thread.cpp index 4a82d49b94f1..58f452339f87 100644 --- a/test/event-thread.cpp +++ b/test/event-thread.cpp @@ -26,7 +26,7 @@ public: { pipe(pipefd_); - notifier_ = new EventNotifier(pipefd_[0], EventNotifier::Read); + notifier_ = new EventNotifier(pipefd_[0], EventNotifier::Read, this); notifier_->activated.connect(this, &EventHandler::readReady); } @@ -60,12 +60,6 @@ public: return notified_; } - void moveToThread(Thread *thread) - { - Object::moveToThread(thread); - notifier_->moveToThread(thread); - } - private: void readReady(EventNotifier *notifier) { diff --git a/test/timer-thread.cpp b/test/timer-thread.cpp index b9373050068c..5c1b4ac4a401 100644 --- a/test/timer-thread.cpp +++ b/test/timer-thread.cpp @@ -20,7 +20,7 @@ class TimeoutHandler : public Object { public: TimeoutHandler() - : timeout_(false) + : timer_(this), timeout_(false) { timer_.timeout.connect(this, &TimeoutHandler::timeoutHandler); timer_.start(100); @@ -31,12 +31,6 @@ public: return timeout_; } - void moveToThread(Thread *thread) - { - Object::moveToThread(thread); - timer_.moveToThread(thread); - } - private: void timeoutHandler(Timer *timer) {