From patchwork Sat Aug 17 15:20:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1819 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 5DDD6600F9 for ; Sat, 17 Aug 2019 17:21:13 +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 EF9EF98C for ; Sat, 17 Aug 2019 17:21:12 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055273; bh=+cUeGq6v9LDYO54X80qEGfBMuubBG+fSZnXJC3Ux1jQ=; h=From:To:Subject:Date:In-Reply-To:References:From; b=EuzyjSxmu600CViBGMgP+9tvTjRAIxYWUEeAUb5VsOnAnEvQ1rY/l8o/Qpvrab6bq FZoHl6k8gx5yx1naKvb/pv5hFcrZ+24FVUIch9sJIpPxNGgg+7TldJOrsN+TP7oaF+ H+FZNd1RPdSyxWcjx2a4EqilnXTfJf0g/bOvrsJs= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:20:47 +0300 Message-Id: <20190817152104.10834-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:13 -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: Jacopo Mondi 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 Sat Aug 17 15:20:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1820 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 A9009600F9 for ; Sat, 17 Aug 2019 17:21:13 +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 4F82C556 for ; Sat, 17 Aug 2019 17:21:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055273; bh=fpsYxOAjB6Uptc5Ip+nhbWmh7mpTj04m3sT/Bvl+Q+k=; h=From:To:Subject:Date:In-Reply-To:References:From; b=jhhT4jIbW3g3hfPtuuvK9yj7mzDPezIxcIsGICTOB90vJZ+VBwPzdQ2hl8LfU2cWw SD3KdVq98WbfzyJ48I1icKrEz7sqvhaDpj0q8GtrJuzl1/OfmrR30IvBAO9R7prq7m FD84Q12wPFMJ9TxiWlWCtnNSLJbCg0Mg+iEVWW+s= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:20:48 +0300 Message-Id: <20190817152104.10834-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:13 -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: Jacopo Mondi 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 Sat Aug 17 15:20:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1821 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 0AB15600F9 for ; Sat, 17 Aug 2019 17:21:14 +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 A4F9E98C for ; Sat, 17 Aug 2019 17:21:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055273; bh=jWaQHPYiVdXbmTXAPOfMiZFcMdagOGG4maW9rwlfRGg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=RUsJ0yJ3WrPL1MQGNkIFD+zUreQQuCEtwmspGmL3J3cS3/N4Zd9UUtPBogHLUbIa6 xm+0Oi9aLhyD1baJbTM2J5HLJSYY9t/c9wbjURSM3dpetzifAO1K6W2w1Uv8IZPj/z h+WkxrXWCgGM9lNLGdnZxoqdMjpBdLe+aPxyj2y0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:20:49 +0300 Message-Id: <20190817152104.10834-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:14 -0000 Threads contain message queues and dispatch queued 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: Jacopo Mondi 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 Sat Aug 17 15:20:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1822 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 79581600F9 for ; Sat, 17 Aug 2019 17:21:14 +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 05D2F556 for ; Sat, 17 Aug 2019 17:21:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055274; bh=N1nhpGCceXX233na9XiWqIb0tLQyPSqx5nhPM+nNN58=; h=From:To:Subject:Date:In-Reply-To:References:From; b=vapdTzwpcPofQkj1GCGDqVbdxwIU1f0F5nSR9ite3hPr32L9veeL1KT7OO5U5yiDk Nr41aXyMrKQkPknHZpfluM3kUBDNe4S2I8rFVwYWPZKjo9FgIkEkJgWC8oXxhuU0kD iAUM1RQbj1PYSdODVAi3CrK5MKzQjnMD9BEhvHRc= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:20:50 +0300 Message-Id: <20190817152104.10834-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:14 -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. This is only a move and rename, no functional changes are included. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi 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 Sat Aug 17 15:20:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1823 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C5082600F9 for ; Sat, 17 Aug 2019 17:21:14 +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 6B57998C for ; Sat, 17 Aug 2019 17:21:14 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055274; bh=oD5QHK0Yrq1ylVr09HqOHB99alYYy2U9yIb2fV+c2eE=; h=From:To:Subject:Date:In-Reply-To:References:From; b=isQspv+QCc8o5mRn/ymNgFczLHEQfB0kMCNyj6bgfZvG0H4sCmnN/qjzYot4z/pmF T7aIhE/us7yoOrkH0AB12/+65KgN499bh9pvi+WxH2HrrTDOVnUWcR3p/D3qk8sCqd RAzGX5N+krHtoyoCBHEVlAl7Lgr2ZynvZk1iVMzo= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:20:51 +0300 Message-Id: <20190817152104.10834-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:15 -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: Jacopo Mondi 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 Sat Aug 17 15:20:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1824 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 321956191D for ; Sat, 17 Aug 2019 17:21:15 +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 C0DD3556 for ; Sat, 17 Aug 2019 17:21:14 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055274; bh=99IHcKULPualFbgtnnuFGfw0K+m4RMi8R4+k7pu0gTg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=IjU6azW8BTu3VXf1mbqVtzQeK8j316S5c2tQwKHk9GezvBgEZaJbnpYNIHY8gCiVn Ha1QDjoczS6CyVoOcHyCGfbmyISHpn7DSrn3RHeYmBeyYrp+CAclo2sm5K7jsvKHCH A//H89Os3DofsAHMbVVuMWwem5Zj6cNfU80TxUAE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:20:52 +0300 Message-Id: <20190817152104.10834-7-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:16 -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: Jacopo Mondi 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 Sat Aug 17 15:20:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1825 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7BBC361920 for ; Sat, 17 Aug 2019 17:21:15 +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 228ED98C for ; Sat, 17 Aug 2019 17:21:15 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055275; bh=Mtdd7I7/fCDQdmHSxFkDcsgRcspZAog9hGuiaCKyECY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=tPKVxygq/RUJ2BTFVfG3AluMiac7jkzmeMiHarR2hwgBYt5PkyRaRZ3J2+yQgG8hp C5FYKJZjaaPORztImOjYh1P5iOyG6D7iHwJP4n/u3a2D2Kx6+eAmjCTeyHmcoMXwwr NibHcYsQi2u8I6pizMa1w1kL8IwHkL5W1+C4l950= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:20:53 +0300 Message-Id: <20190817152104.10834-8-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:16 -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: Jacopo Mondi Reviewed-by: Niklas Söderlund --- Changes since v1: - Drop Object::sendMessage() --- include/libcamera/object.h | 2 ++ src/libcamera/include/message.h | 1 + src/libcamera/message.cpp | 2 ++ src/libcamera/object.cpp | 12 ++++++++++++ 4 files changed, 17 insertions(+) diff --git a/include/libcamera/object.h b/include/libcamera/object.h index 869200a57d8c..e128c75e7db8 100644 --- a/include/libcamera/object.h +++ b/include/libcamera/object.h @@ -52,6 +52,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..bbb28f261405 100644 --- a/src/libcamera/object.cpp +++ b/src/libcamera/object.cpp @@ -135,6 +135,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 +147,17 @@ void Object::moveToThread(Thread *thread) if (thread_ == thread) return; + notifyThreadMove(); + thread->moveObject(this); } +void Object::notifyThreadMove() +{ + Message msg(Message::ThreadMoveMessage); + message(&msg); +} + void Object::connect(SignalBase *signal) { signals_.push_back(signal); From patchwork Sat Aug 17 15:20:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1826 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 DD1AB61932 for ; Sat, 17 Aug 2019 17:21:15 +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 778B7556 for ; Sat, 17 Aug 2019 17:21:15 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055275; bh=5I5e4OvS/sL/8yEUrXmn1WlovVKSeJ58DKzXdqlmXXc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=csJD5mMuohY1Gm9LQRsCH9/QU2bV8ObPCcsfWzSJsZ6X7+7xfgyKpbXn9vWEFvGU9 n1AuYG2KLqesd01xLXST3y/WURGpp28SOKKsYNBm5DVYMqA50OoQVuGerq/3Q37eIs EukqFevBfKTLJDIooG1yv+xjYFpmAN2t/EisAKjM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:20:54 +0300 Message-Id: <20190817152104.10834-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:17 -0000 The test verifies correct behaviour of asynchronous method invocation for Object instances. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi 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 Sat Aug 17 15:20:55 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1827 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 344A3600F9 for ; Sat, 17 Aug 2019 17:21:16 +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 CFDD998C for ; Sat, 17 Aug 2019 17:21:15 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055276; bh=4c3IpK8GOvPcQ//PAYBvGPXhGFHrEfs2HidHXuGpxNE=; h=From:To:Subject:Date:In-Reply-To:References:From; b=iyeLhHiMef+YmjhiYpoPMsH21y/MjzgU8tSDMGWbOfihFNDpQjAQAX9fT46jZhsWq PCcOwniKRWuqDZqjyE1lm9bl2QyDl+Ar3iNyvahJdLwPYpyjHc3SrbUI0/Gr5D1Vkb 5FGWHMrjX6coz6f76aVqIRiX4noFzWohzItIq5EA= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:20:55 +0300 Message-Id: <20190817152104.10834-10-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:17 -0000 The test verifies thread affinity and thread move notifications. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi 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 Sat Aug 17 15:20:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1828 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 8D60B61934 for ; Sat, 17 Aug 2019 17:21:16 +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 3001EE70 for ; Sat, 17 Aug 2019 17:21:16 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055276; bh=OY7Dg/cipX23bifMjwzzKjJ3eoAUe6GCfiF8dmYW5+s=; h=From:To:Subject:Date:In-Reply-To:References:From; b=FpkCJLnxPONWinLC9v8hbz7TGebpS/Rt1vS0cKBnkVpD95uZyCYLFgUzMpcYt1aUq QAjXcXYzprJ6YWr/dZtsyqi6C5eB7ghWGiM5nAAGNliTwZW861KpCGmOsx9XkUrSgA uPv6ziDFnHq25i602aVIqHdbhm9yWYCDWtlfrw/0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:20:56 +0300 Message-Id: <20190817152104.10834-11-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:17 -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: Jacopo Mondi 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 Sat Aug 17 15:20:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1829 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EB64361924 for ; Sat, 17 Aug 2019 17:21:16 +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 881C1F78 for ; Sat, 17 Aug 2019 17:21:16 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055276; bh=Qe+25sl2Y4H9mML/iy0rFa+dIx2D5ozY+Oxbrah/Ekw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=APOl39tVk1ODL+XvhHXDMwmJcYK6aWQxrdbAFI3JqIfpoyx68QyzNZIhENUAvFR2N xzkNWkLwhsBhtAFDu8fb6cmq3niGrXrYTT3uU9vQCNaxgb8Xxu5NZNvuyUFDVdYdEi gbvYFYWxTenpyXIKasP3e051/j7L95837DvJySKo= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:20:57 +0300 Message-Id: <20190817152104.10834-12-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:18 -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: Jacopo Mondi Reviewed-by: Niklas Söderlund --- Changes since v1: - Fix invokeMethod() call --- 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..96be27601982 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(&EventNotifier::setEnabled, true); + } + } + + Object::message(msg); +} + } /* namespace libcamera */ From patchwork Sat Aug 17 15:20:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1830 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 4E90761920 for ; Sat, 17 Aug 2019 17:21:17 +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 DB9B5E70 for ; Sat, 17 Aug 2019 17:21:16 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055277; bh=k3lsHINhRA1bC8Q8vyGfm6YEox6cCIeNKhXPKEZincc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=UWDwJfmQcP91gByQYZ+XmbjMzIuLyCugoVWFfXoJs9GL9l9gi1Ne4pvvxD4x1jTEx +RCPHsxUz8cEvuB46bKjveXjgRVoDnrtFds2DhZOSiU0/AQvoeiS1gFlV9b3dyslav v2dRJpb3q2jh9E5iQ+FyXHqan0elg4Xe5cwYTovo= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:20:58 +0300 Message-Id: <20190817152104.10834-13-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:18 -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: Jacopo Mondi Reviewed-by: Niklas Söderlund --- Changes since v1: - Fix invokeMethod() call --- 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..f45061d4c6f6 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(&Timer::registerTimer); + } + } + + Object::message(msg); +} + } /* namespace libcamera */ From patchwork Sat Aug 17 15:20:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1831 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9D0B26193B for ; Sat, 17 Aug 2019 17:21:17 +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 406A7556 for ; Sat, 17 Aug 2019 17:21:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055277; bh=4nCinrB6kTrScXpLH6SubZv6KsP1w5QCYuRcprE7nvI=; h=From:To:Subject:Date:In-Reply-To:References:From; b=COaVat6mfjH8/6EB44apvTbHEyOOMFe+VZqbTCJ5Gr+A8HBDsub+DzzfT9MLoaMls YBWfP4vSZzBM/K40UJyAv1RyeI1abBaJoqEHywX+hNuRuMS1KqSuTdTlW4HI5uAMuh z09tPGVYqjWs4G/C6iGWenfoAsNV495dpSam9Je8= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:20:59 +0300 Message-Id: <20190817152104.10834-14-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:18 -0000 The test verifies correct behaviour of an enabled event notifier moved to a different thread. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Reviewed-by: Niklas Söderlund --- test/event-thread.cpp | 112 ++++++++++++++++++++++++++++++++++++++++++ test/meson.build | 1 + 2 files changed, 113 insertions(+) create mode 100644 test/event-thread.cpp 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 Sat Aug 17 15:21:00 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1832 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0539261934 for ; Sat, 17 Aug 2019 17:21:18 +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 954FC98C for ; Sat, 17 Aug 2019 17:21:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055277; bh=N1mhhFSYqEjSDQUGdhRRh64q6tkmDj+kG6oWe/dACsA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=IlTDc8f6fhA4PQ0vSbKtncdI+5dmbApIVvfZ/0RrNu1u7/vfyrF+3f/8Xo+wLhnw1 VjkR6BrW7tmm1yUyZMiCZOWSV3CjaddMtE1PtlDp/JSoBPGZVtE2TTTEbmtvFiAGS1 mrJz6imz22HMf4s+KNDI6q11vU2f6i3k8Flwez10= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:21:00 +0300 Message-Id: <20190817152104.10834-15-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:18 -0000 The test verifies correct behaviour of a running timer moved to a different thread. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Reviewed-by: Niklas Söderlund --- test/meson.build | 1 + test/timer-thread.cpp | 78 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 test/timer-thread.cpp 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 Sat Aug 17 15:21:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1833 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4FC4E61934 for ; Sat, 17 Aug 2019 17:21:18 +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 EA4BB556 for ; Sat, 17 Aug 2019 17:21:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055278; bh=rajxxP0JYFZz6vqzW1m/fMCMoczU566n4DKH/Hk9Nc0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=KmkY/wjRJWZnzuiNJSI0uS3xOfIYQJQez5XsnzE5+DJARafxbO2y8UTQ5Rq9OW43e EqCnkfLYDiq2R/EzFz95Mw8c65e1pui5zUl0mGqTQWRa0M7gvUkZMrSTB9IVFCxEUg ybNZo58EKtNFGPBwx+XB76+S+OT4WG9cPdcxdy/A= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:21:01 +0300 Message-Id: <20190817152104.10834-16-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:19 -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: Jacopo Mondi Reviewed-by: Niklas Söderlund --- Changes since v1: - Document Object::~Object() --- include/libcamera/object.h | 8 +++- src/libcamera/include/thread.h | 2 + src/libcamera/object.cpp | 72 ++++++++++++++++++++++++++++------ src/libcamera/thread.cpp | 12 +++++- 4 files changed, 81 insertions(+), 13 deletions(-) diff --git a/include/libcamera/object.h b/include/libcamera/object.h index e128c75e7db8..3308330af857 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); @@ -41,6 +42,8 @@ public: Thread *thread() const { return thread_; } void moveToThread(Thread *thread); + Object *parent() const { return parent_; } + protected: virtual void message(Message *msg); @@ -57,6 +60,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 bbb28f261405..98aa0af2f9b9 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,12 +46,29 @@ 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); } +/** + * \brief Destroy an Object instance + * + * Deleting an Object automatically disconnects all signals from the Object's + * slots. All the Object's children are made orphan, but stay bound to their + * current thread. + */ Object::~Object() { for (SignalBase *signal : signals_) @@ -54,6 +76,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; } /** @@ -129,16 +161,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) { @@ -147,6 +182,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); @@ -156,8 +197,17 @@ void Object::notifyThreadMove() { Message msg(Message::ThreadMoveMessage); message(&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 Sat Aug 17 15:21:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1834 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 AF31061942 for ; Sat, 17 Aug 2019 17:21:18 +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 4C89198C for ; Sat, 17 Aug 2019 17:21:18 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055278; bh=tmxMDvEJ8F3jtRI6IXcB4It9W19GRXLvO7EOuPUdDhQ=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Rd1eh1y45Q+GQYWiBAnTL6psZ4lG6AKHlmFZwpjlDHm2RBf2VsEyfA4GzCKGbgUbe tnaQJE1LnPUwgZCsEXHpRzx1Gu/C0FFWxC/c4GT/biVWPh2FMm3AzOlm5JDSgQpgvm c/KfobC830WCmOLTrXY55sjZaH4JGfaV00dooH4M= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:21:02 +0300 Message-Id: <20190817152104.10834-17-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:19 -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: Jacopo Mondi 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 Sat Aug 17 15:21:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1835 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 0FF6A61936 for ; Sat, 17 Aug 2019 17:21:19 +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 A1A43556 for ; Sat, 17 Aug 2019 17:21:18 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055278; bh=dLylKzqflPNpJuG/m2k/mjzkBGECXSMJgQYkxMJKZ/8=; h=From:To:Subject:Date:In-Reply-To:References:From; b=sgCpm02AmszFbWYDsOd6fVKe7lte2Yh4UiZ+KqYHAJn/TbSLr4s2adom3s/RM+nVK yIT8zQd0EUSIqonPHYba8nS70XlpQv1NKYrKL/0feXlLr4p2++fw+y5xoUo8FHvcQQ dVoGQU+v8k11IP6PPjm9LwCyB6R+GY7mqbS80Vm0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:21:03 +0300 Message-Id: <20190817152104.10834-18-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:20 -0000 The test verifies correct behaviour of parent-child relationships in relation to thread affinity. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi 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 Sat Aug 17 15:21:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1836 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 5A8CE61934 for ; Sat, 17 Aug 2019 17:21:19 +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 01CDFF78 for ; Sat, 17 Aug 2019 17:21:18 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1566055279; bh=UQEeFbjsRyzTjI4NOmwfwPm9jZVVigWClodH2XNZflQ=; h=From:To:Subject:Date:In-Reply-To:References:From; b=D4ZarYxd7s+Z39rJHpOJrEsMqYcLBsf3p8ClGZmuUPo3kn6c+YwGXPJT8VdaboKhF kFwjS5fCr1+ofAqJmTFUl+d9cEhBtGv7VVusNYTkKUtnWD0BTEQenGybka2KxR6WmE dvk5Lx0wAf40dPH2qlr+wI0IVByxBBECP7Z9x3NE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 17 Aug 2019 18:21:04 +0300 Message-Id: <20190817152104.10834-19-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> References: <20190817152104.10834-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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: Sat, 17 Aug 2019 15:21:20 -0000 Create object instances with a parent to avoid the need for reparenting objects manually. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi 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) {