]> rtime.felk.cvut.cz Git - rtems-pluggable-edf.git/blob - src/edf/scheduler_edf.c
8212a90621a0489e863f2c73bed2f2e0c8709994
[rtems-pluggable-edf.git] / src / edf / scheduler_edf.c
1 #include "scheduler_edf.h"
2 #include "rbtree.h"
3 #include <stdio.h>
4 #include <rtems/system.h>
5 #include <rtems/score/isr.h>
6 #include <rtems/score/watchdog.h>
7 #include <rtems/score/wkspace.h>
8 #include <rtems/score/percpu.h>
9 #include <rtems/score/thread.h>
10 #include <stdint.h>
11
12
13 /** 
14  * The threads wanted to be served on a priority base will be assigned the very 
15  * longest deadlines.
16  */ 
17 #define edf_initial_priority_shift(init_prio)  \
18         (init_prio + EDF_ABS_DEADLINE_MAX + 1)
19
20 void edf_next_period(Thread_Control *the_thread) {
21         RBT_Node *node = (RBT_Node*)the_thread->scheduler_info; 
22         the_thread->real_priority = the_thread->current_priority = (_Watchdog_Ticks_since_boot + node->rel_deadline) % EDF_HYBRID_MASK;
23         node->abs_deadline = the_thread->current_priority;      
24 }
25
26
27
28 int _Scheduler_edf_Priority_compare (Priority_Control p1, Priority_Control p2) {
29         uint32_t time = _Watchdog_Ticks_since_boot;
30         //correct priorities
31         if (p1 < EDF_HYBRID_MASK)
32                 p1 = (p1 - time) % EDF_HYBRID_MASK;
33         if (p2 < EDF_HYBRID_MASK)
34                 p2 = (p2 - time) % EDF_HYBRID_MASK;
35         if (p1 > p2) return -1;
36         else if (p1 < p2) return 1;
37         else return 0;
38 }
39
40
41 void _Scheduler_edf_Initialize(void) {
42         // initialize the RB tree
43         _Thread_Ready_EDF_chain.root = NULL;
44         _Thread_Ready_EDF_chain.first = NULL;
45         _Thread_Heir = NULL;
46         _Thread_Executing = NULL;
47 }
48
49 void _Scheduler_edf_Block(  Thread_Control    *the_thread ) {
50         _Scheduler_edf_Extract(the_thread);
51         
52         /* TODO: flash critical section? */
53
54         if ( _Thread_Is_heir( the_thread ) )
55                 _Scheduler_edf_Schedule();
56
57         if ( _Thread_Is_executing( the_thread ) )
58                 _Thread_Dispatch_necessary = true;      
59 }
60
61 void _Scheduler_edf_Schedule(void) {
62         // set the heir
63         _Thread_Heir = (Thread_Control *) _Thread_Ready_EDF_chain.first;
64 }
65
66 void * _Scheduler_edf_Allocate(  Thread_Control      *the_thread) {
67         void * sched;
68         RBT_Node *schinfo;
69         sched = _Workspace_Allocate (sizeof(RBT_Node));
70         the_thread->scheduler_info = (RBT_Node *) sched;
71         the_thread->real_priority = the_thread->current_priority = edf_initial_priority_shift(the_thread->real_priority);
72         
73         schinfo = (RBT_Node *)(the_thread->scheduler_info);
74         schinfo->rel_deadline = 0;      // This has to be negotiated afterwards
75         schinfo->abs_deadline = 0;
76         schinfo->left = NULL;
77         schinfo->right = NULL;
78         schinfo->parent = NULL;
79         schinfo->ready_chain = &_Thread_Ready_EDF_chain;
80         
81         return sched;
82 }
83
84 void _Scheduler_edf_Free(  Thread_Control      *the_thread) {
85         _Workspace_Free (the_thread->scheduler_info);
86 }
87
88 void _Scheduler_edf_Update(  Thread_Control      *the_thread) {
89         // Update deadlines for deadline driven tasks
90         if (!(the_thread->current_priority && EDF_HYBRID_MASK))
91                 ((RBT_Node*)the_thread->scheduler_info)->abs_deadline = the_thread->current_priority;   
92         else
93                 ((RBT_Node*)the_thread->scheduler_info)->abs_deadline = 0;      
94         _Scheduler_edf_Extract(the_thread); 
95         _Scheduler_edf_Enqueue(the_thread); 
96         if ( the_thread->current_priority < _Thread_Heir->current_priority ) {
97                 _Thread_Heir = the_thread;
98                 if ( _Thread_Executing->is_preemptible || the_thread->current_priority == 0 )
99                         _Thread_Dispatch_necessary = true;      
100         }
101 }
102
103 void _Scheduler_edf_Unblock(  Thread_Control    *the_thread ) {
104         _Scheduler_edf_Enqueue(the_thread);
105         /* TODO: flash critical section? */
106
107         /*
108         *  If the thread that was unblocked is more important than the heir,
109         *  then we have a new heir.  This may or may not result in a
110         *  context switch.
111         *
112         *  Normal case:
113         *    If the current thread is preemptible, then we need to do
114         *    a context switch.
115         *  Pseudo-ISR case:
116         *    Even if the thread isn't preemptible, if the new heir is
117         *    a pseudo-ISR system task, we need to do a context switch.
118         */
119         if ( the_thread->current_priority < _Thread_Heir->current_priority ) {
120                 _Thread_Heir = the_thread;
121                 if ( _Thread_Executing->is_preemptible || the_thread->current_priority == 0 )
122                         _Thread_Dispatch_necessary = true;      
123         }
124 }
125
126 void _Scheduler_edf_Yield( void ) {
127         RBT_Node *sched_info;
128         ISR_Level                      level;
129         Thread_Control                *executing;
130         EDF_Chain_Control                 *ready;
131
132         executing  = _Thread_Executing;
133         sched_info = (RBT_Node *) executing->scheduler_info;
134         ready      = sched_info->ready_chain;
135         _ISR_Disable( level );
136         if ( !_RBT_Has_only_one_node( ready ) ) {
137                 _RBT_Extract(ready,executing); 
138                 _RBT_Insert(ready,executing); // preserve the abs_deadline
139
140                 _ISR_Flash( level );
141
142                 if ( _Thread_Is_heir( executing ) )
143                         _Thread_Heir = (Thread_Control *) ready->first;
144                 _Thread_Dispatch_necessary = TRUE;
145         }
146         else if ( !_Thread_Is_heir( executing ) )
147                 _Thread_Dispatch_necessary = TRUE;
148
149         _ISR_Enable( level );
150         
151 }
152
153 void _Scheduler_edf_Enqueue(  Thread_Control    *the_thread) {
154         RBT_Node *node = (RBT_Node*)the_thread->scheduler_info;
155         EDF_Chain_Control *chain = node->ready_chain;
156
157         _RBT_Insert(chain,the_thread);
158 }
159
160 void _Scheduler_edf_Enqueue_first(  Thread_Control    *the_thread) {
161         // FIXME: force first position
162         _Scheduler_edf_Enqueue(the_thread);
163 }
164
165 void _Scheduler_edf_Extract(  Thread_Control     *the_thread) {
166         EDF_Chain_Control* chain = ((RBT_Node*)the_thread->scheduler_info)->ready_chain;
167         _RBT_Extract(chain,the_thread);
168 }
169