aboutsummaryrefslogtreecommitdiffstats
path: root/include/distortos/internal/synchronization/SignalsCatcherControlBlock.hpp
blob: 6676216c0872dc8bda6febea3f3d8239191557a7 (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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/**
 * \file
 * \brief SignalsCatcherControlBlock class header
 *
 * \author Copyright (C) 2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef INCLUDE_DISTORTOS_INTERNAL_SYNCHRONIZATION_SIGNALSCATCHERCONTROLBLOCK_HPP_
#define INCLUDE_DISTORTOS_INTERNAL_SYNCHRONIZATION_SIGNALSCATCHERCONTROLBLOCK_HPP_

#include "distortos/SignalAction.hpp"

#include <memory>

namespace distortos
{

namespace internal
{

class SignalsReceiverControlBlock;
class ThreadControlBlock;

/// SignalsCatcherControlBlock class is a structure required by threads for "catching" and "handling" of signals
class SignalsCatcherControlBlock
{
public:

	/// association of signal numbers (as SignalSet) with SignalAction
	using Association = std::pair<SignalSet, SignalAction>;

	/// type of uninitialized storage for Association objects
	using Storage = std::aligned_storage<sizeof(Association), alignof(Association)>::type;

	/// unique_ptr (with deleter) to Storage[]
	using StorageUniquePointer = std::unique_ptr<Storage[], void(&)(Storage*)>;

	/**
	 * \brief SignalsCatcherControlBlock's constructor
	 *
	 * \param [in] storageUniquePointer is a rvalue reference to StorageUniquePointer with storage for Association
	 * objects (sufficiently large for \a storageSize elements) and appropriate deleter
	 * \param [in] storageSize is the number of elements in \a storage array
	 */

	SignalsCatcherControlBlock(StorageUniquePointer&& storageUniquePointer, size_t storageSize);

	/**
	 * \brief SignalsCatcherControlBlock's destructor
	 */

	~SignalsCatcherControlBlock();

	/**
	 * \brief Hook function executed when delivery of signals is started.
	 *
	 * Clears "delivery pending" flag.
	 *
	 * \attention This function should be called only by SignalsReceiverControlBlock::deliveryOfSignalsFinishedHook().
	 */

	void deliveryOfSignalsStartedHook()
	{
		deliveryIsPending_ = false;
	}

	/**
	 * \brief Gets SignalAction associated with given signal number.
	 *
	 * \param [in] signalNumber is the signal for which the association is requested, [0; 31]
	 *
	 * \return pair with return code (0 on success, error code otherwise) and SignalAction that is associated with
	 * \a signalNumber, default-constructed object if no association was found;
	 * error codes:
	 * - EINVAL - \a signalNumber value is invalid;
	 */

	std::pair<int, SignalAction> getAssociation(uint8_t signalNumber) const;

	/**
	 * \return SignalSet with signal mask for associated thread
	 */

	SignalSet getSignalMask() const
	{
		return signalMask_;
	}

	/**
	 * \brief Part of SignalsReceiverControlBlock::postGenerate() specific to catching unmasked signals.
	 *
	 * Requests delivery of signals to associated thread if there is some non-default signal handler for the signal.
	 *
	 * \param [in] signalNumber is the unmasked signal that was generated, [0; 31]
	 * \param [in] threadControlBlock is a reference to associated ThreadControlBlock
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - \a signalNumber value is invalid;
	 */

	int postGenerate(uint8_t signalNumber, ThreadControlBlock& threadControlBlock);

	/**
	 * \brief Sets association for given signal number.
	 *
	 * \param [in] signalNumber is the signal for which the association will be set, [0; 31]
	 * \param [in] signalAction is a reference to SignalAction that will be associated with given signal number, object
	 * in internal storage is copy-constructed
	 *
	 * \return pair with return code (0 on success, error code otherwise) and SignalAction that was associated with
	 * \a signalNumber, default-constructed object if no association was found;
	 * error codes:
	 * - EAGAIN - no resources are available to associate \a signalNumber with \a signalAction;
	 * - EINVAL - \a signalNumber value is invalid;
	 */

	std::pair<int, SignalAction> setAssociation(uint8_t signalNumber, const SignalAction& signalAction);

	/**
	 * \brief Sets signal mask for associated thread.
	 *
	 * If any pending signal is unblocked and \a owner doesn't equal nullptr, then delivery of signals to associated
	 * thread will be requested.
	 *
	 * \param [in] signalMask is the SignalSet with new signal mask for associated thread
	 * \param [in] owner selects whether delivery of signals will be requested if any pending signal is unblocked
	 * (pointer to owner SignalsReceiverControlBlock object) or not (nullptr)
	 */

	void setSignalMask(SignalSet signalMask, const SignalsReceiverControlBlock* owner);

	SignalsCatcherControlBlock(const SignalsCatcherControlBlock&) = delete;
	SignalsCatcherControlBlock(SignalsCatcherControlBlock&&) = default;
	const SignalsCatcherControlBlock& operator=(const SignalsCatcherControlBlock&) = delete;
	SignalsCatcherControlBlock& operator=(SignalsCatcherControlBlock&&) = delete;

private:

	/**
	 * \brief Clears association for given signal number.
	 *
	 * \param [in] signalNumber is the signal for which the association will be cleared, [0; 31]
	 *
	 * \return SignalAction that was associated with \a signalNumber, default-constructed object if no association was
	 * found
	 */

	SignalAction clearAssociation(uint8_t signalNumber);

	/**
	 * \brief Clears given association for given signal number.
	 *
	 * \param [in] signalNumber is the signal for which the association will be cleared, [0; 31]
	 * \param [in] association is a reference to Association object from <em>[associationsBegin_; associationsEnd_)</em>
	 * range that will be removed
	 *
	 * \return SignalAction from \a association
	 */

	SignalAction clearAssociation(uint8_t signalNumber, Association& association);

	/**
	 * \return pointer to first element of range of Association objects
	 */

	Association* getAssociationsBegin() const
	{
		return reinterpret_cast<Association*>(storageUniquePointer_.get());
	}

	/**
	 * \brief Requests delivery of signals to associated thread.
	 *
	 * Delivery of signals (via special function executed in the associated thread) is requested only if it's not
	 * already pending. The thread is unblocked if it was blocked.
	 *
	 * \param [in] threadControlBlock is a reference to associated ThreadControlBlock
	 */

	void requestDeliveryOfSignals(ThreadControlBlock& threadControlBlock);

	/// storage for Association objects
	StorageUniquePointer storageUniquePointer_;

	/// SignalSet with signal mask for associated thread
	SignalSet signalMask_;

	/// union binds \a associationsEnd_ and \a storageBegin_ - these point to the same address
	union
	{
		/// pointer to "one past the last" element of range of Association objects
		Association* associationsEnd_;

		/// pointer to first element of range of Storage objects
		Storage* storageBegin_;
	};

	/// pointer to "one past the last" element of range of Storage objects
	Storage* storageEnd_;

	/// true if signal delivery is pending, false otherwise
	bool deliveryIsPending_;
};

}	// namespace internal

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_INTERNAL_SYNCHRONIZATION_SIGNALSCATCHERCONTROLBLOCK_HPP_