-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtask.h
More file actions
302 lines (265 loc) · 11.4 KB
/
task.h
File metadata and controls
302 lines (265 loc) · 11.4 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
/*******************************************************************************
Copyright 2014 Matthew Thiffault
This file is part of HeatheRTOS.
HeatheRTOS 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 2 of the License, or
(at your option) any later version.
HeatheRTOS 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 HeatheRTOS. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
#ifndef TASK_H
#define TASK_H
#include "xint.h"
#include "xdef.h"
#include "static_assert.h"
#include "u_tid.h"
#include "config.h"
struct kern;
struct task_regs;
struct task_fpu_regs;
/* Conversion to/from */
#define TASK_IX2PTR(kern, tix) (&(kern)->tasks[(tix)])
#define TASK_PTR2IX(kern, tdp) ((tdp) - (kern)->tasks)
#define TASK_IX_NULL 0xff /* invalid index value */
#define TASK_IX_NOTINQUEUE 0xfe /* invalid index value */
/* Task ID is 16 bits:
* - low byte is task descriptor index, high byte is a sequence number */
#define TID_SEQ_OFFS 8
#define TID_IX_MASK 0xff
#define TASK_TID(kern, tdp) \
(((tdp)->tid_seq << TID_SEQ_OFFS) | TASK_PTR2IX(kern, tdp))
/* Task descriptor stores state and priority in a single byte */
#define TASK_STATE_MASK 0xf0
#define TASK_PRIO_MASK 0x0f
#define TASK_STATE(tdp) ((tdp)->state_prio & TASK_STATE_MASK)
#define TASK_PRIO(tdp) ((tdp)->state_prio & TASK_PRIO_MASK)
#define TASK_SET_STATE(tdp, state) \
((tdp)->state_prio = ((tdp)->state_prio & ~TASK_STATE_MASK) | (state))
#define TASK_SET_PRIO(tdp, prio) \
((tdp)->state_prio = ((tdp)->state_prio & ~TASK_PRIO_MASK) | (prio))
/* Task state constants */
enum {
TASK_STATE_FREE = 0x00, /* Unused task descriptor */
TASK_STATE_READY = 0x10, /* Ready to run; is in ready queue */
TASK_STATE_ACTIVE = 0x20, /* 'Currently' running */
TASK_STATE_ZOMBIE = 0x30, /* Exited */
TASK_STATE_SEND_BLOCKED = 0x40, /* Blocked: Receive waiting for Send */
TASK_STATE_RECEIVE_BLOCKED = 0x50, /* Blocked: Send waiting for Receive */
TASK_STATE_REPLY_BLOCKED = 0x60, /* Blocked: Send waiting for Reply */
TASK_STATE_EVENT_BLOCKED = 0x70 /* Blocked: AwaitEvent */
};
/* Singly-linked task queue */
struct task_queue {
uint8_t head_ix;
uint8_t tail_ix;
};
STATIC_ASSERT(task_queue_size, sizeof (struct task_queue) == 2);
struct task_desc {
/* Points into the task's stack. The task's stack pointer is
* state + sizeof (task_regs). Context switch assumes this is
* the first member of struct task_desc. */
volatile struct task_regs *regs;
/* Task info */
uint8_t state_prio; /* sssspppp : s state, p priority */
uint8_t tid_seq; /* high byte of tid */
uint8_t parent_ix; /* parent task descriptor index */
uint8_t next_ix; /* next pointer task descriptor index */
/* NB. no spsr - use regs->spsr
* no return value - use regs->r0. */
/* Send queue for this task */
struct task_queue senders;
/* Registered cleanup function */
void (*cleanup)(void);
/* Registered event (IRQ number) */
int8_t irq;
/* Time spent in task. */
uint32_t time;
/* Flag which is set to true if the task has a floating
point context saved on it's stack. */
uint8_t fpu_ctx_on_stack;
/* Points to FPU Context on stack, if not null. */
volatile struct task_fpu_regs *fpu_regs;
};
STATIC_ASSERT(task_desc_size, sizeof (struct task_desc) == 32);
/* Context switch assumes this memory layout */
struct task_regs {
uint32_t spsr;
uint32_t pc;
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r4;
uint32_t r5;
uint32_t r6;
uint32_t r7;
uint32_t r8;
uint32_t r9;
uint32_t r10;
uint32_t r11;
uint32_t r12;
uint32_t sp;
uint32_t lr;
};
/* Check memory layout is as assumed by context switch */
STATIC_ASSERT(task_regs_spsr, offsetof (struct task_regs, spsr) == 0x0);
STATIC_ASSERT(task_regs_pc, offsetof (struct task_regs, pc) == 0x4);
STATIC_ASSERT(task_regs_r0, offsetof (struct task_regs, r0) == 0x8);
STATIC_ASSERT(task_regs_r1, offsetof (struct task_regs, r1) == 0xc);
STATIC_ASSERT(task_regs_r2, offsetof (struct task_regs, r2) == 0x10);
STATIC_ASSERT(task_regs_r3, offsetof (struct task_regs, r3) == 0x14);
STATIC_ASSERT(task_regs_r4, offsetof (struct task_regs, r4) == 0x18);
STATIC_ASSERT(task_regs_r5, offsetof (struct task_regs, r5) == 0x1c);
STATIC_ASSERT(task_regs_r6, offsetof (struct task_regs, r6) == 0x20);
STATIC_ASSERT(task_regs_r7, offsetof (struct task_regs, r7) == 0x24);
STATIC_ASSERT(task_regs_r8, offsetof (struct task_regs, r8) == 0x28);
STATIC_ASSERT(task_regs_r9, offsetof (struct task_regs, r9) == 0x2c);
STATIC_ASSERT(task_regs_r10, offsetof (struct task_regs, r10) == 0x30);
STATIC_ASSERT(task_regs_r11, offsetof (struct task_regs, r11) == 0x34);
STATIC_ASSERT(task_regs_r12, offsetof (struct task_regs, r12) == 0x38);
STATIC_ASSERT(task_regs_sp, offsetof (struct task_regs, sp) == 0x3c);
STATIC_ASSERT(task_regs_lr, offsetof (struct task_regs, lr) == 0x40);
STATIC_ASSERT(task_regs_size, sizeof (struct task_regs) == 0x44);
/* Context switch assumes this memory layout */
struct task_fpu_regs {
uint32_t FPSCR;
uint32_t D0_low;
uint32_t D0_high;
uint32_t D1_low;
uint32_t D1_high;
uint32_t D2_low;
uint32_t D2_high;
uint32_t D3_low;
uint32_t D3_high;
uint32_t D4_low;
uint32_t D4_high;
uint32_t D5_low;
uint32_t D5_high;
uint32_t D6_low;
uint32_t D6_high;
uint32_t D7_low;
uint32_t D7_high;
uint32_t D8_low;
uint32_t D8_high;
uint32_t D9_low;
uint32_t D9_high;
uint32_t D10_low;
uint32_t D10_high;
uint32_t D11_low;
uint32_t D11_high;
uint32_t D12_low;
uint32_t D12_high;
uint32_t D13_low;
uint32_t D13_high;
uint32_t D14_low;
uint32_t D14_high;
uint32_t D15_low;
uint32_t D15_high;
uint32_t D16_low;
uint32_t D16_high;
uint32_t D17_low;
uint32_t D17_high;
uint32_t D18_low;
uint32_t D18_high;
uint32_t D19_low;
uint32_t D19_high;
uint32_t D20_low;
uint32_t D20_high;
uint32_t D21_low;
uint32_t D21_high;
uint32_t D22_low;
uint32_t D22_high;
uint32_t D23_low;
uint32_t D23_high;
uint32_t D24_low;
uint32_t D24_high;
uint32_t D25_low;
uint32_t D25_high;
uint32_t D26_low;
uint32_t D26_high;
uint32_t D27_low;
uint32_t D27_high;
uint32_t D28_low;
uint32_t D28_high;
uint32_t D29_low;
uint32_t D29_high;
uint32_t D30_low;
uint32_t D30_high;
uint32_t D31_low;
uint32_t D31_high;
};
/* Check memory layout is as assumed by context switch */
STATIC_ASSERT(task_fpu_regs_fpscr, offsetof (struct task_fpu_regs, FPSCR) == 0x0);
STATIC_ASSERT(task_fpu_regs_d0, offsetof (struct task_fpu_regs, D0_low) == 0x4);
STATIC_ASSERT(task_fpu_regs_d1, offsetof (struct task_fpu_regs, D1_low) == 0xC);
STATIC_ASSERT(task_fpu_regs_d2, offsetof (struct task_fpu_regs, D2_low) == 0x14);
STATIC_ASSERT(task_fpu_regs_d3, offsetof (struct task_fpu_regs, D3_low) == 0x1C);
STATIC_ASSERT(task_fpu_regs_d4, offsetof (struct task_fpu_regs, D4_low) == 0x24);
STATIC_ASSERT(task_fpu_regs_d5, offsetof (struct task_fpu_regs, D5_low) == 0x2C);
STATIC_ASSERT(task_fpu_regs_d6, offsetof (struct task_fpu_regs, D6_low) == 0x34);
STATIC_ASSERT(task_fpu_regs_d7, offsetof (struct task_fpu_regs, D7_low) == 0x3C);
STATIC_ASSERT(task_fpu_regs_d8, offsetof (struct task_fpu_regs, D8_low) == 0x44);
STATIC_ASSERT(task_fpu_regs_d9, offsetof (struct task_fpu_regs, D9_low) == 0x4c);
STATIC_ASSERT(task_fpu_regs_d10, offsetof (struct task_fpu_regs, D10_low) == 0x54);
STATIC_ASSERT(task_fpu_regs_d11, offsetof (struct task_fpu_regs, D11_low) == 0x5c);
STATIC_ASSERT(task_fpu_regs_d12, offsetof (struct task_fpu_regs, D12_low) == 0x64);
STATIC_ASSERT(task_fpu_regs_d13, offsetof (struct task_fpu_regs, D13_low) == 0x6c);
STATIC_ASSERT(task_fpu_regs_d14, offsetof (struct task_fpu_regs, D14_low) == 0x74);
STATIC_ASSERT(task_fpu_regs_d15, offsetof (struct task_fpu_regs, D15_low) == 0x7c);
STATIC_ASSERT(task_fpu_regs_d16, offsetof (struct task_fpu_regs, D16_low) == 0x84);
STATIC_ASSERT(task_fpu_regs_d17, offsetof (struct task_fpu_regs, D17_low) == 0x8c);
STATIC_ASSERT(task_fpu_regs_d18, offsetof (struct task_fpu_regs, D18_low) == 0x94);
STATIC_ASSERT(task_fpu_regs_d19, offsetof (struct task_fpu_regs, D19_low) == 0x9c);
STATIC_ASSERT(task_fpu_regs_d20, offsetof (struct task_fpu_regs, D20_low) == 0xa4);
STATIC_ASSERT(task_fpu_regs_d21, offsetof (struct task_fpu_regs, D21_low) == 0xac);
STATIC_ASSERT(task_fpu_regs_d22, offsetof (struct task_fpu_regs, D22_low) == 0xb4);
STATIC_ASSERT(task_fpu_regs_d23, offsetof (struct task_fpu_regs, D23_low) == 0xbc);
STATIC_ASSERT(task_fpu_regs_d24, offsetof (struct task_fpu_regs, D24_low) == 0xc4);
STATIC_ASSERT(task_fpu_regs_d25, offsetof (struct task_fpu_regs, D25_low) == 0xcc);
STATIC_ASSERT(task_fpu_regs_d26, offsetof (struct task_fpu_regs, D26_low) == 0xd4);
STATIC_ASSERT(task_fpu_regs_d27, offsetof (struct task_fpu_regs, D27_low) == 0xdc);
STATIC_ASSERT(task_fpu_regs_d28, offsetof (struct task_fpu_regs, D28_low) == 0xe4);
STATIC_ASSERT(task_fpu_regs_d29, offsetof (struct task_fpu_regs, D29_low) == 0xec);
STATIC_ASSERT(task_fpu_regs_d30, offsetof (struct task_fpu_regs, D30_low) == 0xf4);
STATIC_ASSERT(task_fpu_regs_d31, offsetof (struct task_fpu_regs, D31_low) == 0xfc);
STATIC_ASSERT(task_fpu_regs_size, sizeof (struct task_fpu_regs) == 0x104);
/* Find a task by its TID. Returns one of the following error codes. */
int get_task(struct kern *k, tid_t tid, struct task_desc **td_out);
enum {
GET_TASK_SUCCESS = 0,
GET_TASK_IMPOSSIBLE_TID = -1,
GET_TASK_NO_SUCH_TASK = -2,
};
/* Create a new task. Returns the TID of the newly created task,
* or an error code: -1 for invalid priority, -2 if out of task
* descriptors.
*
* Valid priorities are 0 <= p < N_PRIORITIES, where lower numbers
* indicate higher priority. */
tid_t task_create(
struct kern *k,
uint8_t parent_ix,
int priority,
void (*task_entry)(void));
/* Add a task to the ready queue for its priority. */
void task_ready(struct kern *k, struct task_desc *td);
/* Schedule the highest priority ready task.
* The scheduled task is marked active and removed from ready queue.
* If no tasks are ready, returns NULL. */
struct task_desc *task_schedule(struct kern *k);
/* Initialize a task queue to be empty. */
void taskq_init(struct task_queue *q);
/* Free a task descriptor so that it can be reused later. */
void task_free(struct kern *k, struct task_desc *td);
/* Enqueue a task on a task queue.
* A task can only be on one task queue at once.
* Do not enqueue tasks that are still part of another queue! */
void task_enqueue(struct kern*, struct task_desc*, struct task_queue*);
/* Attempt to dequeue a task from a task queue. Returns NULL if empty. */
struct task_desc *task_dequeue(struct kern*, struct task_queue*);
#endif