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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
|
/**
* \file
* \brief DynamicThreadBase class header
*
* \author Copyright (C) 2015-2016 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_SCHEDULER_DYNAMICTHREADBASE_HPP_
#define INCLUDE_DISTORTOS_INTERNAL_SCHEDULER_DYNAMICTHREADBASE_HPP_
#include "distortos/DynamicSignalsReceiver.hpp"
#include "distortos/DynamicThreadParameters.hpp"
#include "distortos/ThreadCommon.hpp"
#include "distortos/internal/memory/storageDeleter.hpp"
namespace distortos
{
#ifdef CONFIG_THREAD_DETACH_ENABLE
class DynamicThread;
#endif // def CONFIG_THREAD_DETACH_ENABLE
namespace internal
{
/**
* \brief DynamicThreadBase class is a type-erased interface for thread that has dynamic storage for bounded function,
* stack and internal DynamicSignalsReceiver object.
*
* If thread detachment is enabled (CONFIG_THREAD_DETACH_ENABLE is defined) then this class is dynamically allocated by
* DynamicThread - which allows it to be "detached". Otherwise - if thread detachment is disabled
* (CONFIG_THREAD_DETACH_ENABLE is not defined) - DynamicThread just inherits from this class.
*/
class DynamicThreadBase : public ThreadCommon
{
public:
#ifdef CONFIG_THREAD_DETACH_ENABLE
/**
* \brief DynamicThreadBase's constructor
*
* \tparam Function is the function that will be executed in separate thread
* \tparam Args are the arguments for \a Function
*
* \param [in] stackSize is the size of stack, bytes
* \param [in] canReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this
* thread
* \param [in] queuedSignals is the max number of queued signals for this thread, relevant only if
* \a canReceiveSignals == true, 0 to disable queuing of signals for this thread
* \param [in] signalActions is the max number of different SignalAction objects for this thread, relevant only if
* \a canReceiveSignals == true, 0 to disable catching of signals for this thread
* \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
* \param [in] schedulingPolicy is the scheduling policy of the thread
* \param [in] owner is a reference to owner DynamicThread object
* \param [in] function is a function that will be executed in separate thread
* \param [in] args are arguments for \a function
*/
template<typename Function, typename... Args>
DynamicThreadBase(size_t stackSize, bool canReceiveSignals, size_t queuedSignals, size_t signalActions,
uint8_t priority, SchedulingPolicy schedulingPolicy, DynamicThread& owner, Function&& function,
Args&&... args);
/**
* \brief Detaches the thread.
*
* Similar to std::thread::detach() - http://en.cppreference.com/w/cpp/thread/thread/detach
* Similar to POSIX pthread_detach() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_detach.html
*
* Detaches the executing thread from the Thread object, allowing execution to continue independently. All resources
* allocated for the thread will be deallocated when the thread terminates.
*
* \return 0 on success, error code otherwise:
* - EINVAL - this thread is already detached;
*/
int detach() override;
#else // !def CONFIG_THREAD_DETACH_ENABLE
/**
* \brief DynamicThreadBase's constructor
*
* \tparam Function is the function that will be executed in separate thread
* \tparam Args are the arguments for \a Function
*
* \param [in] stackSize is the size of stack, bytes
* \param [in] canReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this
* thread
* \param [in] queuedSignals is the max number of queued signals for this thread, relevant only if
* \a canReceiveSignals == true, 0 to disable queuing of signals for this thread
* \param [in] signalActions is the max number of different SignalAction objects for this thread, relevant only if
* \a canReceiveSignals == true, 0 to disable catching of signals for this thread
* \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
* \param [in] schedulingPolicy is the scheduling policy of the thread
* \param [in] function is a function that will be executed in separate thread
* \param [in] args are arguments for \a function
*/
template<typename Function, typename... Args>
DynamicThreadBase(size_t stackSize, bool canReceiveSignals, size_t queuedSignals, size_t signalActions,
uint8_t priority, SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args);
/**
* \brief DynamicThreadBase's constructor
*
* \tparam Function is the function that will be executed in separate thread
* \tparam Args are the arguments for \a Function
*
* \param [in] parameters is a DynamicThreadParameters struct with thread parameters
* \param [in] function is a function that will be executed in separate thread
* \param [in] args are arguments for \a function
*/
template<typename Function, typename... Args>
DynamicThreadBase(const DynamicThreadParameters parameters, Function&& function, Args&&... args) :
DynamicThreadBase{parameters.stackSize, parameters.canReceiveSignals, parameters.queuedSignals,
parameters.signalActions, parameters.priority, parameters.schedulingPolicy,
std::forward<Function>(function), std::forward<Args>(args)...}
{
}
#endif // !def CONFIG_THREAD_DETACH_ENABLE
DynamicThreadBase(const DynamicThreadBase&) = delete;
DynamicThreadBase(DynamicThreadBase&&) = default;
const DynamicThreadBase& operator=(const DynamicThreadBase&) = delete;
DynamicThreadBase& operator=(DynamicThreadBase&&) = delete;
protected:
#ifdef CONFIG_THREAD_DETACH_ENABLE
/**
* \brief Pre-termination hook function of thread
*
* If thread is detached, locks object used for deferred deletion.
*
* \param [in] thread is a reference to Thread object, this must be DynamicThreadBase!
*/
static void preTerminationHook(Thread& thread);
/**
* \brief Termination hook function of thread
*
* Calls ThreadCommon::terminationHook() and - if thread is detached - schedules itself for deferred deletion.
*
* \param [in] thread is a reference to Thread object, this must be DynamicThreadBase!
*/
static void terminationHook(Thread& thread);
#endif // def CONFIG_THREAD_DETACH_ENABLE
private:
/**
* \brief Thread's "run" function.
*
* Executes bound function object.
*
* \param [in] thread is a reference to Thread object, this must be DynamicThreadBase!
*/
static void run(Thread& thread);
/// internal DynamicSignalsReceiver object
DynamicSignalsReceiver dynamicSignalsReceiver_;
/// bound function object
std::function<void()> boundFunction_;
#ifdef CONFIG_THREAD_DETACH_ENABLE
/// pointer to owner DynamicThread object, nullptr if thread is detached
DynamicThread* owner_;
#endif // def CONFIG_THREAD_DETACH_ENABLE
};
#ifdef CONFIG_THREAD_DETACH_ENABLE
template<typename Function, typename... Args>
DynamicThreadBase::DynamicThreadBase(const size_t stackSize, const bool canReceiveSignals, const size_t queuedSignals,
const size_t signalActions, const uint8_t priority, const SchedulingPolicy schedulingPolicy,
DynamicThread& owner, Function&& function, Args&&... args) :
ThreadCommon{{{new uint8_t[stackSize], storageDeleter<uint8_t>}, stackSize, *this, run,
preTerminationHook, terminationHook}, priority, schedulingPolicy, nullptr,
canReceiveSignals == true ? &dynamicSignalsReceiver_ : nullptr},
dynamicSignalsReceiver_{canReceiveSignals == true ? queuedSignals : 0,
canReceiveSignals == true ? signalActions : 0},
boundFunction_{std::bind(std::forward<Function>(function), std::forward<Args>(args)...)},
owner_{&owner}
{
}
#else // !def CONFIG_THREAD_DETACH_ENABLE
template<typename Function, typename... Args>
DynamicThreadBase::DynamicThreadBase(const size_t stackSize, const bool canReceiveSignals, const size_t queuedSignals,
const size_t signalActions, const uint8_t priority, const SchedulingPolicy schedulingPolicy,
Function&& function, Args&&... args) :
ThreadCommon{{{new uint8_t[stackSize], storageDeleter<uint8_t>}, stackSize, *this, run, nullptr,
terminationHook}, priority, schedulingPolicy, nullptr,
canReceiveSignals == true ? &dynamicSignalsReceiver_ : nullptr},
dynamicSignalsReceiver_{canReceiveSignals == true ? queuedSignals : 0,
canReceiveSignals == true ? signalActions : 0},
boundFunction_{std::bind(std::forward<Function>(function), std::forward<Args>(args)...)}
{
}
#endif // !def CONFIG_THREAD_DETACH_ENABLE
} // namespace internal
} // namespace distortos
#endif // INCLUDE_DISTORTOS_INTERNAL_SCHEDULER_DYNAMICTHREADBASE_HPP_
|