Dawn Framework 1.0
Universal data acquisition framework for embedded systems
thread.cxx
1// dawn/src/common/thread.cxx
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6#include "dawn/common/thread.hxx"
7
8#include <cerrno>
9#include <cstring>
10#include <sched.h>
11
12#include "dawn/debug.hxx"
13
14using namespace dawn;
15
17{
18 if (thCreated)
19 {
20 thQuit = true;
21 (void)joinThread();
22 }
23
24 thQuitDone = true;
25}
26
27int CThreadedObject::joinThread()
28{
29 int ret;
30
31 if (!thCreated)
32 {
33 return OK;
34 }
35
36 ret = pthread_join(th, nullptr);
37 if (ret != 0)
38 {
39 DAWNERR("Failed to join worker thread (%d)\n", ret);
40 return -ret;
41 }
42
43 thCreated = false;
44 std::memset(&th, 0, sizeof(th));
45 return OK;
46}
47
48int CThreadedObject::buildThreadAttr(pthread_attr_t &attr, bool &needsDestroy) const
49{
50 struct sched_param param;
51 int maxPrio;
52 int minPrio;
53 int policy;
54 int priority;
55 int ret;
56
57 needsDestroy = false;
58
59 if (threadConfig.priority < THREAD_PRIORITY_DEFAULT)
60 {
61 DAWNERR("Invalid worker thread priority %d\n", threadConfig.priority);
62 return -EINVAL;
63 }
64
65 if (threadConfig.scheduler < THREAD_SCHEDULER_DEFAULT)
66 {
67 DAWNERR("Invalid worker thread scheduler %d\n", threadConfig.scheduler);
68 return -EINVAL;
69 }
70
71 ret = pthread_attr_init(&attr);
72 if (ret != 0)
73 {
74 DAWNERR("Failed to initialize worker thread attributes (%d)\n", ret);
75 return -ret;
76 }
77
78 needsDestroy = true;
79
80 if (threadConfig.stackSize > 0)
81 {
82 ret = pthread_attr_setstacksize(&attr, threadConfig.stackSize);
83 if (ret != 0)
84 {
85 /* The requested size may be below the platform's
86 * PTHREAD_STACK_MIN (e.g. very large on some 64-bit targets).
87 * Keep the platform default stack (which is >= PTHREAD_STACK_MIN)
88 * instead of failing thread creation.
89 */
90
91 DAWNWARN("worker thread stack size %zu rejected (%d), using default\n",
92 threadConfig.stackSize,
93 ret);
94 }
95 }
96
97 if (threadConfig.priority == THREAD_PRIORITY_DEFAULT &&
98 threadConfig.scheduler == THREAD_SCHEDULER_DEFAULT)
99 {
100 return OK;
101 }
102
103 ret = pthread_getschedparam(pthread_self(), &policy, &param);
104 if (ret != 0)
105 {
106 DAWNERR("Failed to read creator thread scheduler (%d)\n", ret);
107 return -ret;
108 }
109
110 if (threadConfig.scheduler != THREAD_SCHEDULER_DEFAULT)
111 {
112 policy = threadConfig.scheduler;
113 }
114
115 minPrio = sched_get_priority_min(policy);
116 maxPrio = sched_get_priority_max(policy);
117 if (minPrio < 0 || maxPrio < 0)
118 {
119 int err;
120
121 err = errno != 0 ? errno : EINVAL;
122 DAWNERR("Failed to query priority range for scheduler %d\n", policy);
123 return -err;
124 }
125
126 priority = param.sched_priority;
127 if (threadConfig.priority != THREAD_PRIORITY_DEFAULT)
128 {
129 priority = threadConfig.priority;
130 }
131 else if (priority < minPrio || priority > maxPrio)
132 {
133 priority = minPrio;
134 }
135
136 if (priority < minPrio || priority > maxPrio)
137 {
138 DAWNERR("Worker thread priority %d is outside scheduler %d range [%d, %d]\n",
139 priority,
140 policy,
141 minPrio,
142 maxPrio);
143 return -EINVAL;
144 }
145
146 param.sched_priority = priority;
147
148 ret = pthread_attr_setschedpolicy(&attr, policy);
149 if (ret != 0)
150 {
151 DAWNERR("Failed to set worker thread scheduler %d (%d)\n", policy, ret);
152 return -ret;
153 }
154
155 ret = pthread_attr_setschedparam(&attr, &param);
156 if (ret != 0)
157 {
158 DAWNERR("Failed to set worker thread priority %d (%d)\n", priority, ret);
159 return -ret;
160 }
161
162 ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
163 if (ret != 0)
164 {
165 DAWNERR("Failed to enable explicit worker thread scheduling (%d)\n", ret);
166 return -ret;
167 }
168
169 return OK;
170}
171
173{
174 pthread_attr_t attr;
175 bool needsDestroy;
176 int ret;
177
178 if (thCreated)
179 {
180 if (!thQuitDone)
181 {
182 DAWNERR("Thread already running\n");
183 return -EBUSY;
184 }
185
186 ret = joinThread();
187 if (ret != OK)
188 {
189 return ret;
190 }
191 }
192
193 if (!threadFunc)
194 {
195 DAWNERR("Thread function not set before calling threadStart()\n");
196 return -EINVAL;
197 }
198
199 thQuit = false;
200 thQuitDone = false;
201
202 ret = buildThreadAttr(attr, needsDestroy);
203 if (ret != OK)
204 {
205 if (needsDestroy)
206 {
207 int destroyRet;
208
209 destroyRet = pthread_attr_destroy(&attr);
210 if (destroyRet != 0)
211 {
212 DAWNERR("Failed to destroy worker thread attributes (%d)\n", destroyRet);
213 }
214 }
215
216 thQuit = true;
217 thQuitDone = true;
218 return ret;
219 }
220
221 ret = pthread_create(&th, needsDestroy ? &attr : nullptr, &CThreadedObject::threadEntry, this);
222
223 if (needsDestroy)
224 {
225 int destroyRet;
226
227 destroyRet = pthread_attr_destroy(&attr);
228 if (destroyRet != 0)
229 {
230 DAWNERR("Failed to destroy worker thread attributes (%d)\n", destroyRet);
231 }
232 }
233
234 if (ret != 0)
235 {
236 DAWNERR("Failed to create worker thread (%d)\n", ret);
237 thQuit = true;
238 thQuitDone = true;
239 return -ret;
240 }
241
242 thCreated = true;
243 return OK;
244}
245
247{
248 int ret;
249
250 thQuit = true;
251
252 ret = joinThread();
253 if (ret != OK)
254 {
255 return ret;
256 }
257
258 thQuitDone = true;
259 return OK;
260}
261
263{
264 return !thQuitDone;
265}
266
267void CThreadedObject::threadWrapper()
268{
269 if (threadFunc)
270 {
271 threadFunc();
272 }
273
274 thQuitDone = true;
275}
276
277void *CThreadedObject::threadEntry(void *arg)
278{
279 CThreadedObject *self;
280
281 self = static_cast<CThreadedObject *>(arg);
282 if (self != nullptr)
283 {
284 self->threadWrapper();
285 }
286
287 return nullptr;
288}
Portable thread owner abstraction for Dawn components.
Definition thread.hxx:32
bool isRunning() const
Check if the worker thread is running.
Definition thread.cxx:262
int threadStop()
Stop the worker thread.
Definition thread.cxx:246
virtual ~CThreadedObject()
Destructor - cleans up thread resources.
Definition thread.cxx:16
static int THREAD_SCHEDULER_DEFAULT
Default scheduler behavior.
Definition thread.hxx:48
int threadStart()
Start the worker thread.
Definition thread.cxx:172
static int THREAD_PRIORITY_DEFAULT
Default thread priority behavior.
Definition thread.hxx:40
Out-of-tree user-extension hooks for Dawn.
Definition bindable.hxx:13
int priority
Requested thread priority (0 = creator default).
Definition thread.hxx:57
size_t stackSize
Requested stack size in bytes (0 = OS default).
Definition thread.hxx:56
int scheduler
Requested scheduler policy (-1 = creator default).
Definition thread.hxx:58