libcamera: signal: Make slots list private

The slots list is touched from most of the Signal template functions. In
order to prepare for thread-safety, move handling of the list to a small
number of non-template functions in the SignalBase class.

This incidently fixes a bug in signal disconnection handling where the
signal wasn't removed from the object's signals list, as pointed out by
the signals unit test.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
This commit is contained in:
Laurent Pinchart 2020-01-19 04:29:33 +02:00
parent b6d93f9772
commit 667f53b522
4 changed files with 81 additions and 54 deletions

View file

@ -76,7 +76,12 @@ Object::Object(Object *parent)
*/
Object::~Object()
{
for (SignalBase *signal : signals_)
/*
* Move signals to a private list to avoid concurrent iteration and
* deletion of items from Signal::disconnect().
*/
std::list<SignalBase *> signals(std::move(signals_));
for (SignalBase *signal : signals)
signal->disconnect(this);
if (pendingMessages_)

View file

@ -14,6 +14,42 @@
namespace libcamera {
void SignalBase::connect(BoundMethodBase *slot)
{
Object *object = slot->object();
if (object)
object->connect(this);
slots_.push_back(slot);
}
void SignalBase::disconnect(Object *object)
{
disconnect([object](SlotList::iterator &iter) {
return (*iter)->match(object);
});
}
void SignalBase::disconnect(std::function<bool(SlotList::iterator &)> match)
{
for (auto iter = slots_.begin(); iter != slots_.end(); ) {
if (match(iter)) {
Object *object = (*iter)->object();
if (object)
object->disconnect(this);
delete *iter;
iter = slots_.erase(iter);
} else {
++iter;
}
}
}
SignalBase::SlotList SignalBase::slots()
{
return slots_;
}
/**
* \class Signal
* \brief Generic signal and slot communication mechanism