-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy paths_task.c
More file actions
330 lines (282 loc) · 9.26 KB
/
Copy paths_task.c
File metadata and controls
330 lines (282 loc) · 9.26 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
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
/* Copyright xhawk, MIT license */
#include "s_task.h"
#include <limits.h>
#include <setjmp.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "s_list.h"
#include "s_rbtree.h"
#define S_TASK_STACK_MAGIC ((int)0x5AA55AA5)
THREAD_LOCAL s_task_globals_t g_globals;
#include "s_port_stm32.inc.h"
/*******************************************************************/
/* tasks */
/*******************************************************************/
int s_task_msleep(__async__, uint32_t msec) {
my_clock_t ticks = msec_to_ticks(msec);
return s_task_sleep_ticks(__await__, ticks);
}
int s_task_sleep(__async__, uint32_t sec) {
my_clock_t ticks = sec_to_ticks(sec);
return s_task_sleep_ticks(__await__, ticks);
}
my_clock_t msec_to_ticks(uint32_t msec) {
uint64_t ret =
(uint64_t)((uint64_t)msec *
(1024 * (uint64_t)MY_CLOCKS_PER_SEC / 1000) / 1024);
if (ret >= ((my_clock_t)-1))
return (my_clock_t)-1;
else
return (my_clock_t)ret;
}
my_clock_t sec_to_ticks(uint32_t sec) {
uint64_t ret = (uint64_t)((uint64_t)sec * (uint64_t)MY_CLOCKS_PER_SEC);
if (ret >= (my_clock_t)-1)
return (my_clock_t)-1;
else
return (my_clock_t)ret;
}
#define TICKS_DEVIDER (uint32_t)(4096 * 1024)
#define TICKS_PER_SEC_1 (uint32_t)(TICKS_DEVIDER / MY_CLOCKS_PER_SEC)
uint32_t ticks_to_msec(my_clock_t ticks) {
#if INT_MAX < 65536 /* it seems that stm8 uint64 is uint32 */
uint32_t msec = 1000 * (uint32_t)ticks / MY_CLOCKS_PER_SEC;
return msec;
#else
uint64_t u64_msec =
1000 * (uint64_t)ticks * TICKS_PER_SEC_1 / TICKS_DEVIDER;
uint32_t msec = (u64_msec > (uint64_t) ~(uint32_t)0 ? ~(uint32_t)0
: (uint32_t)u64_msec);
return msec;
#endif
}
uint32_t ticks_to_sec(my_clock_t ticks) {
#if INT_MAX < 65536 /* it seems that stm8 uint64 is uint32 */
uint32_t sec = (uint32_t)ticks / MY_CLOCKS_PER_SEC;
return sec;
#else
uint64_t u64_sec = (uint64_t)ticks * TICKS_PER_SEC_1 / TICKS_DEVIDER;
uint32_t sec =
(u64_sec > (uint64_t) ~(uint32_t)0 ? ~(uint32_t)0 : (uint32_t)u64_sec);
return sec;
#endif
}
/*
*timeout, wait timeout
return, true on task run
*/
static void s_task_call_next(__async__) {
/* get next task and run it */
s_list_t* next;
s_task_t* old_task;
(void)__awaiter_dummy__;
/* Check active tasks */
if (s_list_is_empty(&g_globals.active_tasks)) {
#ifndef NDEBUG
fprintf(stderr, "error: must has one task to run\n");
#endif
return;
}
old_task = g_globals.current_task;
next = s_list_get_next(&g_globals.active_tasks);
/* printf("next = %p %p\n", g_globals.current_task, next); */
g_globals.current_task = GET_PARENT_ADDR(next, s_task_t, node);
s_list_detach(next);
if (old_task != g_globals.current_task) {
#if defined USE_SWAP_CONTEXT
swapcontext(&old_task->uc, &g_globals.current_task->uc);
#elif defined USE_JUMP_FCONTEXT
s_jump_t jump;
jump.from = &old_task->fc;
jump.to = &g_globals.current_task->fc;
transfer_t t = jump_fcontext(g_globals.current_task->fc, (void*)&jump);
s_jump_t* ret = (s_jump_t*)t.data;
*ret->from = t.fctx;
#endif
}
#ifdef USE_STACK_DEBUG
if (g_globals.current_task->stack_size > 0) {
s_task_t* task = g_globals.current_task;
void* real_stack = (void*)&task[1];
size_t real_stack_size = task->stack_size - sizeof(task[0]);
size_t int_stack_size = real_stack_size / sizeof(int);
if (((int*)real_stack)[0] != S_TASK_STACK_MAGIC) {
#ifndef NDEBUG
fprintf(stderr, "stack overflow in lower bits");
#endif
while (1)
; /* dead */
}
if (((int*)real_stack)[int_stack_size - 1] != S_TASK_STACK_MAGIC) {
#ifndef NDEBUG
fprintf(stderr, "stack overflow in higher bits");
#endif
while (1)
; /* dead */
}
}
#endif
}
void s_task_next(__async__) {
g_globals.current_task->waiting_cancelled = false;
while (true) {
#ifdef USE_IN_EMBEDDED
if (g_globals.irq_actived) {
S_IRQ_DISABLE();
g_globals.irq_actived = 0;
s_list_attach(&g_globals.active_tasks, &g_globals.irq_active_tasks);
s_list_detach(&g_globals.irq_active_tasks);
S_IRQ_ENABLE();
}
#endif
s_timer_run();
if (!s_list_is_empty(&g_globals.active_tasks)) {
s_task_call_next(__await__);
return;
}
/* Check timers */
#ifndef USE_LIST_TIMER_CONTAINER
if (!rbt_is_empty(&g_globals.timers)) {
#else
if (!s_list_is_empty(&g_globals.timers)) {
#endif
/* Wait for the recent timer */
uint64_t timeout = s_timer_wait_recent();
my_on_idle(timeout);
} else if (s_task_cancel_dead() == 0) {
#ifndef NDEBUG
fprintf(stderr, "error: must not wait so long!\n");
#endif
my_on_idle((uint64_t)-1);
}
}
}
void s_task_yield(__async__) {
/* Put current task to the waiting list */
s_list_attach(&g_globals.active_tasks, &g_globals.current_task->node);
s_task_next(__await__);
g_globals.current_task->waiting_cancelled = false;
}
void s_task_init_system_() {
#if defined USE_IN_EMBEDDED
s_list_init(&g_globals.irq_active_tasks);
g_globals.irq_actived = 0;
#endif
s_list_init(&g_globals.active_tasks);
#ifdef USE_DEAD_TASK_CHECKING
s_list_init(&g_globals.waiting_mutexes);
s_list_init(&g_globals.waiting_events);
#endif
#ifndef USE_LIST_TIMER_CONTAINER
rbt_create(&g_globals.timers, s_timer_comparator, NULL);
#else
s_list_init(&g_globals.timers);
#endif
my_clock_init();
s_list_init(&g_globals.main_task.node);
s_event_init(&g_globals.main_task.join_event);
g_globals.main_task.stack_size = 0;
g_globals.main_task.closed = false;
g_globals.main_task.waiting_cancelled = false;
g_globals.current_task = &g_globals.main_task;
}
void s_task_create(void* stack, size_t stack_size, s_task_fn_t task_entry,
void* task_arg) {
void* real_stack;
size_t real_stack_size;
s_task_t* task = (s_task_t*)stack;
s_list_init(&task->node);
s_event_init(&task->join_event);
task->task_entry = task_entry;
task->task_arg = task_arg;
task->stack_size = stack_size;
task->closed = false;
task->waiting_cancelled = false;
s_list_attach(&g_globals.active_tasks, &task->node);
real_stack = (void*)&task[1];
real_stack_size = stack_size - sizeof(task[0]);
#ifdef USE_STACK_DEBUG
{
/* Fill magic number so as to check stack size */
size_t int_stack_size = real_stack_size / sizeof(int);
if (int_stack_size <= 2) {
#ifndef NDEBUG
fprintf(stderr, "stack size too small");
return;
#endif
}
((int*)real_stack)[0] = S_TASK_STACK_MAGIC;
((int*)real_stack)[int_stack_size - 1] = S_TASK_STACK_MAGIC;
real_stack = (char*)real_stack + sizeof(int);
real_stack_size = (int_stack_size - 2) * sizeof(int);
}
#endif
#if defined USE_SWAP_CONTEXT
create_context(&task->uc, real_stack, real_stack_size);
#elif defined USE_JUMP_FCONTEXT
create_fcontext(&task->fc, real_stack, real_stack_size,
s_task_fcontext_entry);
#endif
}
int s_task_join(__async__, void* stack) {
s_task_t* task = (s_task_t*)stack;
while (!task->closed) {
int ret = s_event_wait(__await__, &task->join_event);
if (ret != 0)
return ret;
}
return 0;
}
/* timer conflict with this function!!!
Do NOT call s_task_kill, and let the task exit by itself! */
void s_task_kill__remove(void* stack) {
s_task_t* task = (s_task_t*)stack;
s_list_detach(&task->node);
}
void s_task_cancel_wait(void* stack) {
s_task_t* task = (s_task_t*)stack;
task->waiting_cancelled = true;
s_list_detach(&task->node);
s_list_attach(&g_globals.active_tasks, &task->node);
}
unsigned int s_task_cancel_dead() {
#ifdef USE_DEAD_TASK_CHECKING
return s_event_cancel_dead_waiting_tasks_() +
s_mutex_cancel_dead_waiting_tasks_();
#else
return 0;
#endif
}
static size_t s_task_get_stack_free_size_ex_by_stack(void* stack) {
uint32_t* check;
for (check = (uint32_t*)stack;; ++check) {
if (*check != 0xFFFFFFFF)
return (char*)check - (char*)stack;
}
}
static size_t s_task_get_stack_free_size_by_task(s_task_t* task) {
return s_task_get_stack_free_size_ex_by_stack(&task[1]);
}
size_t s_task_get_stack_free_size() {
return s_task_get_stack_free_size_by_task(g_globals.current_task);
}
void s_task_context_entry() {
struct tag_s_task_t* task = g_globals.current_task;
s_task_fn_t task_entry = task->task_entry;
void* task_arg = task->task_arg;
__async__ = 0;
(*task_entry)(__await__, task_arg);
task->closed = true;
s_event_set(&task->join_event);
s_task_next(__await__);
}
#ifdef USE_JUMP_FCONTEXT
void s_task_fcontext_entry(transfer_t arg) {
/* printf("=== s_task_helper_entry = %p\n", arg.fctx); */
s_jump_t* jump = (s_jump_t*)arg.data;
*jump->from = arg.fctx;
/* printf("%p %p %p\n", jump, jump->to, g_globals.current_task); */
s_task_context_entry();
}
#endif