-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.c
212 lines (181 loc) · 6.43 KB
/
main.c
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
#include "core.h" // core defines needed by entire system
#include "mtutil.h" // multi tasker prototypes
#include "mtint.h" // machine interface prototypes for multi-tasker
#include "firstTask.h" // prototypes for module contining main task
#include "timeSlice.h" // time slice interrupt control
ubyte multi_tasker_grabbed;
ubyte task_switch_requested;
unsigned int remaining_slices;
ubyte task_volenteered_suspend;
_task_cb * current_task;
_task_cb * queue_anchor;
void mt_set_slices( ubyte slices )
{
ubyte isr = mt_get_interrupt_status();
signed long difference;
difference = slices - current_task->slices;
current_task->slices = slices;
difference += remaining_slices;
if ( difference <= 0 ) mt_task_suspend();
remaining_slices = difference;
mt_set_interrupt_status( isr );
}
ubyte mt_get_slices( void )
{
return current_task->slices;
}
void mt_task_suspend( void )
{
ubyte isr = mt_get_interrupt_status();
// indicate a volentary task suspension
task_volenteered_suspend = TRUE;
// do the suspension
mt_suspend_execution();
mt_set_interrupt_status( isr );
}
void mt_task_start(
void (*task) (void)
, ubyte slices
, _task_cb * task_handle
, void * stack_pointer
, unsigned int task_id
)
{
ubyte isr = mt_get_interrupt_status();
// prepare the task control block
task_handle->slices = slices;
task_handle->task_id = task_id;
task_handle->stack_pointer = stack_pointer;
task_handle->next_tcb = NULL;
// make initial stack image with new task's context
// reset to first instruction of task
mt_prepare_stack_image( &task_handle->stack_pointer, task );
// place the task in the task queue for execution
// if there is currently no task in the queue then
if ( queue_anchor == NULL )
{
// initiate the queue
task_handle->next_tcb = task_handle;
queue_anchor = task_handle;
current_task = task_handle;
}
else
{
// put task in of queue
task_handle->next_tcb = queue_anchor->next_tcb;
queue_anchor->next_tcb = task_handle;
queue_anchor = task_handle;
}
mt_set_interrupt_status( isr );
}
void mt_init( void )
{
// start up the time slice timer
// this enables the pre-emptive mode
time_slice_interrupt_start();
time_slice_interrupt_enable();
}
void mt_grab( void )
{
multi_tasker_grabbed = TRUE;
}
void mt_free( void )
{
multi_tasker_grabbed = FALSE;
if ( task_switch_requested )
{
mt_suspend_execution();
}
}
C_task void main( void )
{
// initiate the task queue with no tasks in it
queue_anchor = NULL;
current_task = NULL;
// the following line bootstrapps the system into running the main
// task. Main task is un-aware at start that it is a task and thinks
// that it is starting the multi tasker. In reality it only switches
// the multi tasker from a strictly cooperative to a blended system
// that mixes pre-emption with cooperation. The main task starts the
// task slice timer.
mt_task_start(
first_task
, 1
,&first_task_handle
,&first_task_stack[FIRST_TASK_STACK_SIZE - 1]
, FIRST_TASK_FLAG
);
// init time slice timer and set its interrupt vector
time_slice_interrupt_init( mt_suspend_execution );
// begin running tasks
do
{
// if there are tasks in the queue to execute then
if ( queue_anchor != NULL )
{
// get next task to execute from beginning of queue
current_task = current_task->next_tcb;
remaining_slices = current_task->slices;
// if last task volenteered to give up its time and its time
// is not up then give next task one extra slice so it gets at
// least one full slice to execute
if ( task_volenteered_suspend )
{
++remaining_slices;
}
// clear all possible events that can occure because of
// task execution
multi_tasker_grabbed = FALSE;
task_switch_requested = FALSE;
task_volenteered_suspend = FALSE;
// go run task until it gives up or is out of time
do
{
// shut down interrupts before enabling timer interrupt to prevent
// timer interrupt durring mt execution. If the task that is running
// has enabled interrupts then interrupts will be re-enabled by
// my_jump_into_task just as it begins execution of the task.
disable_interrupt();
time_slice_interrupt_enable();
// go run task for a while
mt_jump_into_task( ¤t_task->stack_pointer );
// if 10 ms heartbeat timer has timed out then
time_slice_interrupt_disable();
enable_interrupt();
// check if left task because of timer interrupt
if ( time_slice_timed_out() )
{
// if left task because of timer interrupt then must reset the
// time slice interrupt timer.
disable_interrupt();
time_slice_interrupt_reset();
enable_interrupt();
}
// if multi tasker is not to allow exit from above task then
// note that either a timeout occured or that the task
// tried to exit with a task suspend and continue executing it
if ( multi_tasker_grabbed )
{
task_switch_requested = TRUE;
continue;
}
// if the multi tasker is allowed to exit above task and
// time has run out or task suspends it self then exit loop and
// get next task to execute
if ( --remaining_slices == 0 ) break;
if ( task_volenteered_suspend ) break;
}
while ( FOREVER );
}
else
{
// loop until watchdog resets
disable_interrupt();
while ( FOREVER )
{
halt();
}
}
}
while ( FOREVER );
}