summaryrefslogtreecommitdiff
path: root/src/libcamera/signal.cpp
blob: 2532df3c30730e93ba2b531cd0640274a4d8d5d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * signal.cpp - Signal & slot implementation
 */

#include <libcamera/signal.h>

#include "libcamera/internal/thread.h"

/**
 * \file signal.h
 * \brief Signal & slot implementation
 */

namespace libcamera {

namespace {

/*
 * Mutex to protect the SignalBase::slots_ and Object::signals_ lists. If lock
 * contention needs to be decreased, this could be replaced with locks in
 * Object and SignalBase, or with a mutex pool.
 */
Mutex signalsLock;

} /* namespace */

void SignalBase::connect(BoundMethodBase *slot)
{
	MutexLocker locker(signalsLock);

	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)
{
	MutexLocker locker(signalsLock);

	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()
{
	MutexLocker locker(signalsLock);
	return slots_;
}

/**
 * \class Signal
 * \brief Generic signal and slot communication mechanism
 *
 * Signals and slots are a language construct aimed at communication between
 * objects through the observer pattern without the need for boilerplate code.
 * See http://doc.qt.io/qt-5/signalsandslots.html for more information.
 *
 * Signals model events that can be observed from objects unrelated to the event
 * source. Slots are functions that are called in response to a signal. Signals
 * can be connected to and disconnected from slots dynamically at runtime. When
 * a signal is emitted, all connected slots are called sequentially in the order
 * they have been connected.
 *
 * Signals are defined with zero, one or more typed parameters. They are emitted
 * with a value for each of the parameters, and those values are passed to the
 * connected slots.
 *
 * Slots are normal static or class member functions. In order to be connected
 * to a signal, their signature must match the signal type (taking the same
 * arguments as the signal and returning void).
 *
 * Connecting a signal to a slot results in the slot being called with the
 * arguments passed to the emit() function when the signal is emitted. Multiple
 * slots can be connected to the same signal, and multiple signals can connected
 * to the same slot. Duplicate connections between a signal and a slot are
 * allowed and result in the slot being called multiple times for the same
 * signal emission.
 *
 * When a slot belongs to an instance of the Object class, the slot is called
 * in the context of the thread that the object is bound to. If the signal is
 * emitted from the same thread, the slot will be called synchronously, before
 * Signal::emit() returns. If the signal is emitted from a different thread,
 * the slot will be called asynchronously from the object's thread's event
 * loop, after the Signal::emit() method returns, with a copy of the signal's
 * arguments. The emitter shall thus ensure that any pointer or reference
 * passed through the signal will remain valid after the signal is emitted.
 */

/**
 * \fn Signal::connect(T *object, R (T::*func)(Args...))
 * \brief Connect the signal to a member function slot
 * \param[in] object The slot object pointer
 * \param[in] func The slot member function
 *
 * If the typename T inherits from Object, the signal will be automatically
 * disconnected from the \a func slot of \a object when \a object is destroyed.
 * Otherwise the caller shall disconnect signals manually before destroying \a
 * object.
 *
 * \context This function is \threadsafe.
 */

/**
 * \fn Signal::connect(R (*func)(Args...))
 * \brief Connect the signal to a static function slot
 * \param[in] func The slot static function
 *
 * \context This function is \threadsafe.
 */

/**
 * \fn Signal::disconnect()
 * \brief Disconnect the signal from all slots
 *
 * \context This function is \threadsafe.
 */

/**
 * \fn Signal::disconnect(T *object)
 * \brief Disconnect the signal from all slots of the \a object
 * \param[in] object The object pointer whose slots to disconnect
 *
 * \context This function is \threadsafe.
 */

/**
 * \fn Signal::disconnect(T *object, R (T::*func)(Args...))
 * \brief Disconnect the signal from the \a object slot member function \a func
 * \param[in] object The object pointer whose slots to disconnect
 * \param[in] func The slot member function to disconnect
 *
 * \context This function is \threadsafe.
 */

/**
 * \fn Signal::disconnect(R (*func)(Args...))
 * \brief Disconnect the signal from the slot static function \a func
 * \param[in] func The slot static function to disconnect
 *
 * \context This function is \threadsafe.
 */

/**
 * \fn Signal::emit(Args... args)
 * \brief Emit the signal and call all connected slots
 * \param args The arguments passed to the connected slots
 *
 * Emitting a signal calls all connected slots synchronously and sequentially in
 * the order the slots have been connected. The arguments passed to the emit()
 * function are passed to the slot functions unchanged. If a slot modifies one
 * of the arguments (when passed by pointer or reference), the modification is
 * thus visible to all subsequently called slots.
 *
 * This function is not \threadsafe, but thread-safety is guaranteed against
 * concurrent connect() and disconnect() calls.
 */

} /* namespace libcamera */