-
Notifications
You must be signed in to change notification settings - Fork 167
Expand file tree
/
Copy pathpios_thread.c
More file actions
305 lines (269 loc) · 7.62 KB
/
pios_thread.c
File metadata and controls
305 lines (269 loc) · 7.62 KB
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
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
/**
******************************************************************************
* @file pios_thread.c
* @author Tau Labs, http://taulabs.org, Copyright (C) 2014
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_Thread Thread Abstraction
* @{
* @brief Abstracts the concept of a thread to hide different implementations
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>
*/
#include "pios.h"
#include "pios_thread.h"
#if !defined(PIOS_INCLUDE_CHIBIOS)
#error "pios_thread.c requires PIOS_INCLUDE_CHIBIOS"
#endif
#if !defined(CH_CFG_USE_MEMCORE) || CH_CFG_USE_MEMCORE != TRUE
#error "pios_thread: Need to use memcore with ChibiOS."
#endif
#if defined(PIOS_INCLUDE_CHIBIOS)
struct pios_thread
{
thread_t *threadp;
uint32_t *stack;
};
#define CVT_MS2ST(msec) ((systime_t)(((((uint32_t)(msec)) * ((uint64_t)CH_CFG_ST_FREQUENCY) - 1UL) / 1000UL) + 1UL))
#define CVT_ST2MS(n) (((((n) - 1ULL) * 1000ULL) / ((uint64_t)CH_CFG_ST_FREQUENCY)) + 1UL)
/**
* Compute size that is at rounded up to the nearest
* multiple of 8
*/
static uint32_t ceil_size(uint32_t size)
{
const uint32_t a = sizeof(stkalign_t);
size = size + (a - size % a);
return size;
}
/**
* @brief Creates a handle for the current thread.
*
* @param[in] namep pointer to thread name
*
* @returns instance of @p struct pios_thread or NULL on failure
*/
struct pios_thread *PIOS_Thread_WrapCurrentThread(const char *namep)
{
struct pios_thread *thread = PIOS_malloc_no_dma(sizeof(struct pios_thread));
if (thread) {
thread->threadp = chThdGetSelfX();
extern uint32_t __main_thread_stack_base__;
thread->stack = &__main_thread_stack_base__;
#if CH_CFG_USE_REGISTRY
thread->threadp->name = namep;
#endif /* CH_USE_REGISTRY */
}
return thread;
}
/**
* @brief Changes the priority of this thread.
*
* @param[in] prio The new priority.
*/
void PIOS_Thread_ChangePriority(enum pios_thread_prio_e prio)
{
chThdSetPriority(prio);
}
/**
*
* @brief Creates a thread.
*
* @param[in] fp pointer to thread function
* @param[in] namep pointer to thread name
* @param[in] stack_bytes stack size in bytes
* @param[in] argp pointer to argument which will be passed to thread function
* @param[in] prio thread priority
*
* @returns instance of @p struct pios_thread or NULL on failure
*
*/
struct pios_thread *PIOS_Thread_Create(void (*fp)(void *), const char *namep, size_t stack_bytes, void *argp, enum pios_thread_prio_e prio)
{
struct pios_thread *thread = PIOS_malloc_no_dma(sizeof(struct pios_thread));
if (thread == NULL)
return NULL;
// Use special functions to ensure ChibiOS stack requirements
stack_bytes = ceil_size(stack_bytes);
uint8_t *wap = chCoreAllocAligned(stack_bytes, PORT_STACK_ALIGN);
if (wap == NULL)
{
PIOS_free(thread);
return NULL;
}
thread->threadp = chThdCreateStatic(wap, stack_bytes, prio, (tfunc_t)fp, argp);
if (thread->threadp == NULL)
{
PIOS_free(thread);
PIOS_free(wap);
return NULL;
}
#if CH_CFG_USE_REGISTRY
thread->threadp->name = namep;
#endif /* CH_CFG_USE_REGISTRY */
/* Newer ChibiOS versions store the thread struct at the bottom of the stack allocation
instead of the top. */
thread->stack = (uint32_t*)wap;
return thread;
}
#if (CH_CFG_USE_WAITEXIT == TRUE)
/**
*
* @brief Destroys an instance of @p struct pios_thread.
*
* @param[in] threadp pointer to instance of @p struct pios_thread
*
*/
void PIOS_Thread_Delete(struct pios_thread *threadp)
{
if (threadp == NULL)
{
chThdExit(0);
}
else
{
chThdTerminate(threadp->threadp);
chThdWait(threadp->threadp);
}
}
#else
#error "PIOS_Thread_Delete requires CH_USE_WAITEXIT to be defined TRUE"
#endif /* (CH_CFG_USE_WAITEXIT == TRUE) */
/**
*
* @brief Returns the current system time.
*
* @returns current system time
*
*/
uint32_t PIOS_Thread_Systime(void)
{
return (uint32_t)CVT_ST2MS(chVTGetSystemTime());
}
/**
*
* @brief Suspends execution of current thread at least for specified time.
*
* @param[in] time_ms time in milliseconds to suspend thread execution
*
*/
void PIOS_Thread_Sleep(uint32_t time_ms)
{
if (time_ms == PIOS_THREAD_TIMEOUT_MAX)
chThdSleep(TIME_INFINITE);
else
chThdSleep(MS2ST(time_ms));
}
/**
*
* @brief Suspends execution of current thread for a regular interval.
*
* @param[in] previous_ms pointer to system time of last execution,
* must have been initialized with PIOS_Thread_Systime() on first invocation
* @param[in] increment_ms time of regular interval in milliseconds
*
*/
void PIOS_Thread_Sleep_Until(uint32_t *previous_ms, uint32_t increment_ms)
{
// Do the math in the millisecond domain.
*previous_ms += increment_ms;
systime_t future = CVT_MS2ST(*previous_ms);
systime_t increment_st = CVT_MS2ST(increment_ms);
chSysLock();
systime_t now = chVTGetSystemTime();
systime_t sleep_time = future - now;
if (sleep_time > increment_st) {
// OK, the calculated sleep time is much longer than
// the desired interval. There's two possibilities:
// 1) We were already late! If so just don't sleep.
// 2) The timer wrapped. (at 49 days) Just don't sleep.
if ((now - future) > increment_st) {
// However, in this particular case we need to fix up
// the clock. If we're very late, OR WRAPPED,
// don't try and keep on the previous timebase.
*previous_ms = CVT_ST2MS(now);
}
} else if (sleep_time > 0) {
// Be sure not to request a sleep_time of 0, as that's
// IMMEDIATE and makes chTdSleepS panic.
chThdSleepS(sleep_time);
}
chSysUnlock();
}
bool PIOS_Thread_Period_Elapsed(const uint32_t prev_systime, const uint32_t increment_ms)
{
/* TODO: make PIOS_Thread_Systime return opaque type to avoid ms conversion */
return CVT_MS2ST(increment_ms) <= chVTTimeElapsedSinceX(CVT_MS2ST(prev_systime));
}
/**
*
* @brief Returns stack usage of a thread.
*
* @param[in] threadp pointer to instance of @p struct pios_thread
*
* @return stack usage in bytes
*/
uint32_t PIOS_Thread_Get_Stack_Usage(struct pios_thread *threadp)
{
#if CH_DBG_FILL_THREADS
uint32_t *stack = threadp->stack;
uint32_t *stklimit = stack;
while (*stack ==
((CH_DBG_STACK_FILL_VALUE << 24) |
(CH_DBG_STACK_FILL_VALUE << 16) |
(CH_DBG_STACK_FILL_VALUE << 8) |
(CH_DBG_STACK_FILL_VALUE << 0)))
++stack;
return (stack - stklimit) * 4;
#else
return 0;
#endif /* CH_DBG_FILL_THREADS */
}
/**
*
* @brief Returns runtime of a thread.
*
* @param[in] threadp pointer to instance of @p struct pios_thread
*
* @return runtime in milliseconds
*
*/
uint32_t PIOS_Thread_Get_Runtime(struct pios_thread *threadp)
{
chSysLock();
uint32_t result = threadp->threadp->ticks_total;
threadp->threadp->ticks_total = 0;
chSysUnlock();
return result;
}
/**
*
* @brief Suspends execution of all threads.
*
*/
void PIOS_Thread_Scheduler_Suspend(void)
{
chSysLock();
}
/**
*
* @brief Resumes execution of all threads.
*
*/
void PIOS_Thread_Scheduler_Resume(void)
{
chSysUnlock();
}
#endif /* defined(PIOS_INCLUDE_CHIBIOS) */