libcamera: bound_method: Manage BoundMethodPack through std::shared_ptr
The bound method arguments pack will need to be accessed by the method invoker in order to retrieve the method return value when using a blocking connection type. We thus can't delete the pack unconditionally in the bound method target thread. We also can't delete it unconditionally in the invoker's thread, as for queued connections the pack will be used in the target thread after the invoker completes. This shows that ownership of the arguments pack is shared between two contexts. As a result, manage it using std::shared_ptr<>. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
This commit is contained in:
parent
621edb2367
commit
b0135a1522
5 changed files with 43 additions and 27 deletions
|
@ -874,6 +874,7 @@ EXCLUDE_SYMBOLS = libcamera::BoundMemberMethod \
|
||||||
libcamera::BoundMethodArgs \
|
libcamera::BoundMethodArgs \
|
||||||
libcamera::BoundMethodBase \
|
libcamera::BoundMethodBase \
|
||||||
libcamera::BoundMethodPack \
|
libcamera::BoundMethodPack \
|
||||||
|
libcamera::BoundMethodPackBase \
|
||||||
libcamera::BoundStaticMethod \
|
libcamera::BoundStaticMethod \
|
||||||
libcamera::SignalBase \
|
libcamera::SignalBase \
|
||||||
std::*
|
std::*
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#ifndef __LIBCAMERA_BOUND_METHOD_H__
|
#ifndef __LIBCAMERA_BOUND_METHOD_H__
|
||||||
#define __LIBCAMERA_BOUND_METHOD_H__
|
#define __LIBCAMERA_BOUND_METHOD_H__
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
@ -21,6 +22,24 @@ enum ConnectionType {
|
||||||
ConnectionTypeBlocking,
|
ConnectionTypeBlocking,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BoundMethodPackBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~BoundMethodPackBase() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
class BoundMethodPack : public BoundMethodPackBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BoundMethodPack(const Args &... args)
|
||||||
|
: args_(args...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<typename std::remove_reference<Args>::type...> args_;
|
||||||
|
};
|
||||||
|
|
||||||
class BoundMethodBase
|
class BoundMethodBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -36,7 +55,7 @@ public:
|
||||||
|
|
||||||
Object *object() const { return object_; }
|
Object *object() const { return object_; }
|
||||||
|
|
||||||
virtual void invokePack(void *pack) = 0;
|
virtual void invokePack(BoundMethodPackBase *pack) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
#ifndef __DOXYGEN__
|
#ifndef __DOXYGEN__
|
||||||
|
@ -58,7 +77,8 @@ protected:
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void activatePack(void *pack, bool deleteMethod);
|
void activatePack(std::shared_ptr<BoundMethodPackBase> pack,
|
||||||
|
bool deleteMethod);
|
||||||
|
|
||||||
void *obj_;
|
void *obj_;
|
||||||
Object *object_;
|
Object *object_;
|
||||||
|
@ -67,18 +87,6 @@ private:
|
||||||
ConnectionType connectionType_;
|
ConnectionType connectionType_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
class BoundMethodPack
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BoundMethodPack(const Args &... args)
|
|
||||||
: args_(args...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<typename std::remove_reference<Args>::type...> args_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename R, typename... Args>
|
template<typename R, typename... Args>
|
||||||
class BoundMethodArgs : public BoundMethodBase
|
class BoundMethodArgs : public BoundMethodBase
|
||||||
{
|
{
|
||||||
|
@ -87,18 +95,18 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<int... S>
|
template<int... S>
|
||||||
void invokePack(void *pack, BoundMethodBase::sequence<S...>)
|
void invokePack(BoundMethodPackBase *pack, BoundMethodBase::sequence<S...>)
|
||||||
{
|
{
|
||||||
PackType *args = static_cast<PackType *>(pack);
|
/* args is effectively unused when the sequence S is empty. */
|
||||||
|
PackType *args [[gnu::unused]] = static_cast<PackType *>(pack);
|
||||||
invoke(std::get<S>(args->args_)...);
|
invoke(std::get<S>(args->args_)...);
|
||||||
delete args;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BoundMethodArgs(void *obj, Object *object, ConnectionType type)
|
BoundMethodArgs(void *obj, Object *object, ConnectionType type)
|
||||||
: BoundMethodBase(obj, object, type) {}
|
: BoundMethodBase(obj, object, type) {}
|
||||||
|
|
||||||
void invokePack(void *pack) override
|
void invokePack(BoundMethodPackBase *pack) override
|
||||||
{
|
{
|
||||||
invokePack(pack, typename BoundMethodBase::generator<sizeof...(Args)>::type());
|
invokePack(pack, typename BoundMethodBase::generator<sizeof...(Args)>::type());
|
||||||
}
|
}
|
||||||
|
@ -123,10 +131,14 @@ public:
|
||||||
|
|
||||||
void activate(Args... args, bool deleteMethod = false) override
|
void activate(Args... args, bool deleteMethod = false) override
|
||||||
{
|
{
|
||||||
if (this->object_)
|
if (!this->object_) {
|
||||||
BoundMethodBase::activatePack(new PackType{ args... }, deleteMethod);
|
|
||||||
else
|
|
||||||
(static_cast<T *>(this->obj_)->*func_)(args...);
|
(static_cast<T *>(this->obj_)->*func_)(args...);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<BoundMethodPackBase> pack =
|
||||||
|
std::make_shared<typename BoundMemberMethod<T, R, Args...>::PackType>(args...);
|
||||||
|
BoundMethodBase::activatePack(pack, deleteMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
void invoke(Args... args) override
|
void invoke(Args... args) override
|
||||||
|
|
|
@ -48,7 +48,8 @@ namespace libcamera {
|
||||||
* deadlock will occur.
|
* deadlock will occur.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void BoundMethodBase::activatePack(void *pack, bool deleteMethod)
|
void BoundMethodBase::activatePack(std::shared_ptr<BoundMethodPackBase> pack,
|
||||||
|
bool deleteMethod)
|
||||||
{
|
{
|
||||||
ConnectionType type = connectionType_;
|
ConnectionType type = connectionType_;
|
||||||
if (type == ConnectionTypeAuto) {
|
if (type == ConnectionTypeAuto) {
|
||||||
|
@ -61,7 +62,7 @@ void BoundMethodBase::activatePack(void *pack, bool deleteMethod)
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ConnectionTypeDirect:
|
case ConnectionTypeDirect:
|
||||||
default:
|
default:
|
||||||
invokePack(pack);
|
invokePack(pack.get());
|
||||||
if (deleteMethod)
|
if (deleteMethod)
|
||||||
delete this;
|
delete this;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -48,7 +48,8 @@ private:
|
||||||
class InvokeMessage : public Message
|
class InvokeMessage : public Message
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InvokeMessage(BoundMethodBase *method, void *pack,
|
InvokeMessage(BoundMethodBase *method,
|
||||||
|
std::shared_ptr<BoundMethodPackBase> pack,
|
||||||
Semaphore *semaphore = nullptr,
|
Semaphore *semaphore = nullptr,
|
||||||
bool deleteMethod = false);
|
bool deleteMethod = false);
|
||||||
~InvokeMessage();
|
~InvokeMessage();
|
||||||
|
@ -59,7 +60,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BoundMethodBase *method_;
|
BoundMethodBase *method_;
|
||||||
void *pack_;
|
std::shared_ptr<BoundMethodPackBase> pack_;
|
||||||
Semaphore *semaphore_;
|
Semaphore *semaphore_;
|
||||||
bool deleteMethod_;
|
bool deleteMethod_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -123,7 +123,8 @@ Message::Type Message::registerMessageType()
|
||||||
* \param[in] deleteMethod True to delete the \a method when the message is
|
* \param[in] deleteMethod True to delete the \a method when the message is
|
||||||
* destroyed
|
* destroyed
|
||||||
*/
|
*/
|
||||||
InvokeMessage::InvokeMessage(BoundMethodBase *method, void *pack,
|
InvokeMessage::InvokeMessage(BoundMethodBase *method,
|
||||||
|
std::shared_ptr<BoundMethodPackBase> pack,
|
||||||
Semaphore *semaphore, bool deleteMethod)
|
Semaphore *semaphore, bool deleteMethod)
|
||||||
: Message(Message::InvokeMessage), method_(method), pack_(pack),
|
: Message(Message::InvokeMessage), method_(method), pack_(pack),
|
||||||
semaphore_(semaphore), deleteMethod_(deleteMethod)
|
semaphore_(semaphore), deleteMethod_(deleteMethod)
|
||||||
|
@ -148,7 +149,7 @@ InvokeMessage::~InvokeMessage()
|
||||||
*/
|
*/
|
||||||
void InvokeMessage::invoke()
|
void InvokeMessage::invoke()
|
||||||
{
|
{
|
||||||
method_->invokePack(pack_);
|
method_->invokePack(pack_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue