Golem  v0.1.1
Generic Operating system Libraries for Embedded Multitasking
 All Data Structures Files Functions Variables Pages
/home/ruud/Engineering/software/projects/golem-project-code/trunk/glm_scheduler.c
1 
11 /* INCLUDES **********************************************************/
12 #include <float.h>
13 #include "glm_scheduler.h"
14 #include "glm_conf.h"
15 #include "glm_conf_tasks.h"
16 
17 
18 /* COMPILE-TIME CHECKS ************************************************/
19 
20 // Make sure the scheduler slot's IDLE-time functionality is working
21 // properly.
22 #if defined SCHEDULER_IDLE_ENTER_FUNC || defined SCHEDULER_IDLE_LEAVE_FUNC
23  #ifdef SCHEDULER_IDLE_FUNC_TH
24  #if defined SCHEDULER_IDLE_FUNC_TH < 0 || SCHEDULER_IDLE_FUNC_TH > 100
25  #error "SCHEDULER_IDLE_FUNC_TH must be in range 0 - 100 (%)"
26  #endif
27  #else
28  #error "Please specify SCHEDULER_IDLE_FUNC_TH in glm_conf.h \
29 when using SCHEDULER_IDLE_ENTER_FUNC and/or SCHEDULER_IDLE_LEAVE_FUNC"
30  #endif
31 #endif
32 
33 
34 /* DEFINES & CONSTANTS ***********************************************/
35 #define NR_OF_TASKS (sizeof(m_task_list) / sizeof(task_t))
36 
37 
38 /* PRIVATE VARIABLES *************************************************/
39 static task_stats_t m_task_stats[ NR_OF_TASKS ];
40 static task_stats_t m_slot_stats;
41 static bool m_is_aborted = false;
42 
43 
44 /* PRIVATE FUNCTION DECLARATIONS *************************************/
45 // Initializes all statistics
46 static void scheduler_init();
47 
48 // Provides extra functionality during a scheduler slot idle time
49 static void scheduler_idle(tickstamp_t slot_start);
50 
51 // Check if it is time for the given task to run and if so runs it and stores
52 // its statistics.
53 static void scheduler_run_task( uint_base_t a_slot, const task_t *a_task,
54  uint_base_t a_task_id );
55 
56 
57 // Determines if current runtime is a new maximum or minimum and if so
58 // updates the new max/min runtime
59 static void scheduler_update_runtime_stats( tickstamp_t *min, tickstamp_t *max,
60  const tickstamp_t *cur);
61 
62 
63 /* PUBLIC FUNCTIONS **************************************************/
64 
65 void
66 scheduler_run()
67 {
68 uint_base_t t = 0;
69 uint_base_t slot = 0;
70 tickstamp_t begin = {0,0};
71 tickstamp_t end = {0,0};
72 tickstamp_t runtime = {0,0};
73 
74  // Perform initialization
75  scheduler_init();
76 
77  // This is the scheduler's main loop where all registered tasks are run at
78  // the specified intervals and offsets. This loop will only exit if
79  // scheduler_abort() is called.
80  while(!m_is_aborted)
81  {
82  tick_current( &begin );
83 
84  // Loop through task-administration to see which tasks must be run in
85  // this scheduling slot
86  for( t=0 ; t<NR_OF_TASKS ; t++ )
87  {
88  // Decide if it is time to run the task. If so run it
89  scheduler_run_task( slot, &m_task_list[t], t );
90  }
91 
92  // Determine runtime
93  tick_current( &end );
94  tick_diff( &begin, &end, &runtime );
95 
96  // update runtime statistics
97  scheduler_update_runtime_stats( &(m_slot_stats.runtime_min),
98  &(m_slot_stats.runtime_max),
99  &runtime);
100 
101  // Check if we're already in the next slot
102  if( SCHEDULER_SLOT_SIZE_TICKS <= runtime.tick)
103  {
104  // We crossed the slot-boundary, record this
105  if( UINT_BASE_MAX > m_slot_stats.slot_overruns )
106  m_slot_stats.slot_overruns++;
107  }
108  else
109  {
110  // We have time left in this slot, perform IDLE-mode activities
111  scheduler_idle( begin );
112 
113  // Determine time left in this slot
114  tick_current( &end );
115  tick_diff(&begin, &end, &runtime);
116 
117  // Wait until the end of the slot if necessary
118  while( SCHEDULER_SLOT_SIZE_TICKS > runtime.tick )
119  {
120  // Determine slot runtime
121  tick_current( &end );
122  tick_diff( &begin, &end, &runtime );
123  }
124  }
125 
126  // Increment slot-counter
127  slot++;
128  }
129 
130  // Scheduler and tasks are aborted. Run each task's abort-function.
131  for( t=0 ; t<NR_OF_TASKS ; t++ )
132  {
133  if(NULL != m_task_list[t].p_abort_func)
134  {
135  m_task_list[t].p_abort_func();
136  }
137  }
138 } // scheduler_main()
139 
140 
141 void
142 scheduler_abort()
143 {
144  m_is_aborted = true;
145 }
146 
147 bool
148 scheduler_task_stats( uint_base_t a_task, task_t *a_params,
149  task_stats_t *a_stats)
150 {
151  bool is_valid = false;
152 
153  if( a_task < NR_OF_TASKS )
154  {
155  // Copy data so that original data is never overwritten
156  *a_stats = m_task_stats[ a_task ];
157  *a_params = m_task_list[ a_task ];
158  is_valid = true;
159  }
160 
161  return is_valid;
162 }
163 
164 
165 void
166 scheduler_stats(task_stats_t * a_stats)
167 {
168  // Copy overall statistics so that original data is never overwritten
169  *a_stats = m_slot_stats;
170 }
171 
172 
173 /* PRIVATE FUNCTIONS *************************************************/
174 
175 void
176 scheduler_init()
177 {
178 unsigned int t = 0;
179 
180  // Let minimum runtime of each task start at maximum;
181  for( t=0 ; t<NR_OF_TASKS ; t++)
182  {
183  // Clear statistics
184  m_task_stats[t].runtime_max.tick = 0;
185  m_task_stats[t].runtime_max.subtick = 0;
186  m_task_stats[t].runtime_min.tick = UINT_BASE_MAX;
187  m_task_stats[t].runtime_min.subtick = UINT_BASE_MAX;
188  m_task_stats[t].slot_overruns = 0;
189  }
190 
191  // Do the same for the overall slot statistics
192  m_slot_stats.runtime_max.tick = 0;
193  m_slot_stats.runtime_max.subtick = 0;
194  m_slot_stats.runtime_min.tick = UINT_BASE_MAX;
195  m_slot_stats.runtime_min.subtick = UINT_BASE_MAX;
196  m_slot_stats.slot_overruns = 0;
197 
198  // Clear scheduler-aborted flag
199  m_is_aborted = false;
200 }
201 
202 
203 void
204 scheduler_run_task( uint_base_t a_slot, const task_t *a_task,
205  uint_base_t a_task_id )
206 {
207 uint_base_t rem = 1;
208 tickstamp_t begin = {0,0};
209 tickstamp_t end = {0,0};
210 tickstamp_t runtime = {0,0};
211 
212  // Run the task if remainder is zero and if function pointer is valid
213  if( (NULL != a_task) && (NULL != a_task->p_run_func) )
214  {
215  // Only perform division if divider is non-zero and if the current slot is
216  // equal or higher than the slot-offset
217  if ( (a_task->slot_interval > 0) &&
218  (a_slot >= a_task->slot_offset) )
219  {
220  rem = a_slot;
221  rem -= a_task->slot_offset;
222  rem %= a_task->slot_interval;
223  }
224 
225  // Decide if we should run the task
226  if( 0 == rem )
227  {
228  // Determine start tickstamp
229  tick_current(&begin);
230 
231  // Execute task (task is responsible for returning in time!)
232  a_task->p_run_func();
233 
234  // Determine runtime
235  tick_current(&end);
236  tick_diff(&begin, &end, &runtime);
237 
238  // update runtime statistics
239  scheduler_update_runtime_stats(
240  &(m_task_stats[a_task_id].runtime_min),
241  &(m_task_stats[a_task_id].runtime_max),
242  &runtime );
243 
244  // Register slot-overruns
245  if(runtime.tick >= SCHEDULER_SLOT_SIZE_TICKS)
246  {
247  if( UINT_BASE_MAX > m_task_stats[a_task_id].slot_overruns )
248  m_task_stats[a_task_id].slot_overruns++;
249  }
250  }
251  }
252 } // scheduler_run_task()
253 
254 
255 void
256 scheduler_idle(tickstamp_t slot_start)
257 {
258  tickstamp_t cur = {0,0};
259  tickstamp_t runtime = {0,0};
260 
261 #if defined(SCHEDULER_IDLE_ENTER_FUNC) || defined(SCHEDULER_IDLE_LEAVE_FUNC)
262  const uint_base_t FUNC_TH = (1-SCHEDULER_IDLE_FUNC_TH/100) * \
263  SCHEDULER_SLOT_SIZE_TICKS;
264 #endif
265 
266  // Determine slot runtime
267  tick_current(&cur);
268  tick_diff(&slot_start, &cur, &runtime);
269 
270 // If there is an enter-idle function, determine whether to run it
271 #if defined(SCHEDULER_IDLE_ENTER_FUNC)
272  if(FUNC_TH > runtime.tick)
273  {
274  SCHEDULER_IDLE_ENTER_FUNC();
275  }
276 #endif
277 
278 // If there is an leave-idle function, determine whether to run it
279 #if defined(SCHEDULER_IDLE_LEAVE_FUNC)
280  // Wait until we're reached the last SCHEDULER_IDLE_FUNC_TH %
281  // of the slot before running the idle-leave function
282  while(FUNC_TH > runtime.tick)
283  {
284  // Determine slot runtime
285  tick_current( &cur );
286  tick_diff(&slot_start, &cur, &runtime);
287  }
288 
289  // Run idle-leave function
290  SCHEDULER_IDLE_LEAVE_FUNC();
291 #endif
292 }
293 
294 
295 void
296 scheduler_update_runtime_stats( tickstamp_t *min, tickstamp_t *max,
297  const tickstamp_t *cur)
298 {
299  // Determine if we have a new minimum
300  if ( (cur->tick < min->tick) ||
301  (
302  (cur->tick == min->tick) &&
303  (cur->subtick < min->subtick )
304  )
305  )
306  {
307  *min = *cur;
308  }
309 
310  // Determine if we have a new maximum
311  if ( (cur->tick > max->tick) ||
312  (
313  (cur->tick == max->tick) &&
314  (cur->subtick > max->subtick )
315  )
316  )
317  {
318  *max = *cur;
319  }
320 }