]> rtime.felk.cvut.cz Git - arc.git/blob - system/kernel/task.c
Merge with tip
[arc.git] / system / kernel / task.c
1 /* -------------------------------- Arctic Core ------------------------------\r
2  * Arctic Core - the open source AUTOSAR platform http://arccore.com\r
3  *\r
4  * Copyright (C) 2009  ArcCore AB <contact@arccore.com>\r
5  *\r
6  * This source code is free software; you can redistribute it and/or modify it\r
7  * under the terms of the GNU General Public License version 2 as published by the\r
8  * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.\r
9  *\r
10  * This program is distributed in the hope that it will be useful, but\r
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
13  * for more details.\r
14  * -------------------------------- Arctic Core ------------------------------*/\r
15 \r
16 #include <stdlib.h>\r
17 #include "Os.h"\r
18 \r
19 #include "internal.h"\r
20 #include "arc.h"\r
21 #include "arch.h"\r
22 \r
23 /** @req OS067 */\r
24 \r
25 _Bool os_pcb_pid_valid( OsPcbType *restrict pcb ) {\r
26         return ( pcb->pid > OS_TASK_CNT ) ? 0 : 1;\r
27 }\r
28 /**\r
29  * Start an extended task.\r
30  * Tasks done:\r
31  * - Grab the internal resource for the process\r
32  * - Set it running state.\r
33  * - Start to execute the process\r
34  *\r
35  */\r
36 void Os_TaskStartExtended( void ) {\r
37 \r
38         OsPcbType *pcb;\r
39 \r
40         pcb = Os_TaskGetCurrent();\r
41 #if 0\r
42         Os_ResourceGetInternal();\r
43         Os_TaskMakeRunning(pcb);\r
44 #endif\r
45 \r
46 //      PRETASKHOOK();\r
47 \r
48         Os_ArchFirstCall();\r
49 \r
50         /* We got back without any TerminateTask() or ChainTask()\r
51          *\r
52          * OSEK:\r
53          *    Each task shall terminate itself at the end of its code.\r
54          *    Ending the task without a call to TerminateTask or ChainTask\r
55          *    is strictly forbidden and causes undefined behaviour.\r
56          *\r
57          * Autosar:\r
58          *    OS052, OS069, OS070 and OS239\r
59          * */\r
60 \r
61         /** @req OS239 */\r
62         Irq_Disable();\r
63         if( Os_IrqAnyDisabled() ) {\r
64                 Os_IrqClearAll();\r
65         }\r
66 \r
67         /** @req OS070 */\r
68         if( Os_TaskOccupiesResources(pcb) ) {\r
69                 Os_ResourceFreeAll(pcb);\r
70         }\r
71 \r
72         /** @req OS069 */\r
73         ERRORHOOK(E_OS_MISSINGEND);\r
74 \r
75         /** @req OS052 */\r
76         TerminateTask();\r
77 }\r
78 \r
79 /**\r
80  * Start an basic task.\r
81  * See extended task.\r
82  */\r
83 \r
84 void Os_TaskStartBasic( void ) {\r
85 \r
86         OsPcbType *pcb;\r
87 \r
88         pcb = Os_TaskGetCurrent();\r
89 #if 0\r
90         Os_ResourceGetInternal();\r
91         Os_TaskMakeRunning(pcb);\r
92 #endif\r
93 \r
94 //      PRETASKHOOK();\r
95 \r
96         Os_ArchFirstCall();\r
97 \r
98         /** @req OS239 */\r
99         Irq_Disable();\r
100         if( Os_IrqAnyDisabled() ) {\r
101                 Os_IrqClearAll();\r
102         }\r
103 \r
104         /** @req OS070 */\r
105         if( Os_TaskOccupiesResources(pcb) ) {\r
106                 Os_ResourceFreeAll(pcb);\r
107         }\r
108 \r
109         /** @req OS069 */\r
110         ERRORHOOK(E_OS_MISSINGEND);\r
111 \r
112         /** @req OS052 */\r
113         TerminateTask();\r
114 }\r
115 \r
116 \r
117 static void Os_StackSetup( OsPcbType *pcbPtr ) {\r
118         uint8_t *bottom;\r
119 \r
120         /* Find bottom of the stack so that we can place the\r
121          * context there.\r
122          *\r
123          * stack bottom = high address. stack top = low address\r
124          */\r
125         bottom = (uint8_t *)pcbPtr->stack.top + pcbPtr->stack.size;\r
126         pcbPtr->stack.curr = bottom;\r
127         // TODO: alignments here..\r
128         // TODO :use function os_arch_get_call_size() ??\r
129 \r
130         // Make some space for back-chain.\r
131         bottom -= 16;\r
132         // Set the current stack so that it points to the context\r
133         pcbPtr->stack.curr = bottom - Os_ArchGetScSize();\r
134 \r
135         Os_StackSetEndmark(pcbPtr);\r
136 }\r
137 \r
138 /**\r
139  * Fill the stack with a predefined pattern\r
140  *\r
141  * @param pcbPtr Pointer to the pcb to fill with pattern\r
142  */\r
143 static void Os_StackFill(OsPcbType *pcbPtr) {\r
144         uint8_t *p = pcbPtr->stack.curr;\r
145 \r
146         assert(pcbPtr->stack.curr > pcbPtr->stack.top);\r
147 \r
148         while (p > (uint8_t *) pcbPtr->stack.top) {\r
149                 --p;\r
150                 *p = STACK_PATTERN;\r
151         }\r
152 }\r
153 \r
154 #if 0\r
155 /**\r
156  *\r
157  * @param pcbPtr\r
158  */\r
159 static void Os_TaskSetEntry(OsPcbType *pcbPtr ) {\r
160 \r
161 }\r
162 #endif\r
163 \r
164 \r
165 /**\r
166  * Setup the context for a pcb. The context differs for different arch's\r
167  * so we call the arch dependent functions also.\r
168  * The context at setup is always a small context.\r
169  *\r
170  * @param pcb Ptr to the pcb to setup context for.\r
171  */\r
172 void Os_ContextInit( OsPcbType *pcb ) {\r
173 \r
174         if( pcb->autostart ) {\r
175                 Os_TaskMakeReady(pcb);\r
176         } else {\r
177                 pcb->state = ST_SUSPENDED;\r
178         }\r
179 \r
180         Os_StackSetup(pcb);\r
181         Os_StackFill(pcb);\r
182         Os_ArchSetTaskEntry(pcb);\r
183 \r
184         Os_ArchSetupContext(pcb);\r
185 }\r
186 \r
187 /**\r
188  *\r
189  * @param pcb\r
190  */\r
191 void Os_ContextReInit( OsPcbType *pcbPtr ) {\r
192         Os_StackSetup(pcbPtr);\r
193 }\r
194 \r
195 /**\r
196  * Search for a specific task in the pcb list.\r
197  *\r
198  * @param tid The task id to search for\r
199  * @return Ptr to the found pcb or NULL\r
200  */\r
201 OsPcbType *os_find_task( TaskType tid ) {\r
202         OsPcbType *i_pcb;\r
203 \r
204         /* TODO: Implement this as an array */\r
205         TAILQ_FOREACH(i_pcb,& os_sys.pcb_head,pcb_list) {\r
206                 if(i_pcb->pid == tid ) {\r
207                         return i_pcb;\r
208                 }\r
209         }\r
210         assert(0);\r
211         return NULL;\r
212 }\r
213 \r
214 /**\r
215  * Adds a pcb to the list of pcb's\r
216  * @param pcb\r
217  */\r
218 TaskType Os_AddTask( OsPcbType *pcb ) {\r
219         long msr;\r
220 \r
221         Irq_Save(msr);  // Save irq status and disable interrupts\r
222 \r
223         pcb->pid = os_sys.task_cnt;\r
224         // Add to list of PCB's\r
225         TAILQ_INSERT_TAIL(& os_sys.pcb_head,pcb,pcb_list);\r
226         os_sys.task_cnt++;\r
227 \r
228         Irq_Restore(msr);  // Restore interrupts\r
229         return pcb->pid;\r
230 }\r
231 \r
232 \r
233 #define PRIO_ILLEGAL    -100\r
234 \r
235 /**\r
236  * Find the top priority task. Even the running task is included.\r
237  * TODO: There should be a priority queue (using a heap?) here instead.\r
238  *        giving O(log n) for instertions and (1) for getting the top\r
239  *        prio task. The curerent implementation is ehhhh bad.\r
240  * @return\r
241  */\r
242 \r
243 OsPcbType *Os_TaskGetTop( void ){\r
244         OsPcbType *i_pcb;\r
245         OsPcbType *top_prio_pcb = NULL;\r
246         OsPriorityType top_prio = PRIO_ILLEGAL;\r
247 \r
248 //      OS_DEBUG(D_TASK,"os_find_top_prio_proc\n");\r
249 \r
250         TAILQ_FOREACH(i_pcb,& os_sys.ready_head,ready_list) {\r
251                 // all ready task are canidates\r
252                 if( i_pcb->state & (ST_READY|ST_RUNNING)) {\r
253                         if( top_prio != PRIO_ILLEGAL ) {\r
254                                 if( i_pcb->prio > top_prio ) {\r
255                                         top_prio = i_pcb->prio;\r
256                                         top_prio_pcb = i_pcb;\r
257                                 }\r
258                         } else {\r
259                                 top_prio = i_pcb->prio;\r
260                                 top_prio_pcb = i_pcb;\r
261                         }\r
262                 } else {\r
263                         assert(0);\r
264                 }\r
265         }\r
266 \r
267         assert(top_prio_pcb!=NULL);\r
268 \r
269         OS_DEBUG(D_TASK,"Found %s\n",top_prio_pcb->name);\r
270 \r
271         return top_prio_pcb;\r
272 }\r
273 \r
274 \r
275 #define USE_LDEBUG_PRINTF\r
276 #include "debug.h"\r
277 \r
278 // we come here from\r
279 // - WaitEvent()\r
280 //   old_pcb -> WAITING\r
281 //   new_pcb -> READY(RUNNING)\r
282 // - Schedule(),\r
283 //   old_pcb -> READY\r
284 //   new_pcb -> READY/RUNNING\r
285 \r
286 /*\r
287  * two strategies\r
288  * 1. When running ->\r
289  *    - remove from ready queue\r
290  *    - set state == ST_RUNNING\r
291  *\r
292  * 2. When running ->\r
293  *    * leave in ready queue\r
294  *    * set state == ST_RUNNING\r
295  *    - ready queue and ST_READY not the same\r
296  *    + No need to remove the running process from ready queue\r
297  */\r
298 \r
299 OsPcbType *Os_FindTopPrioTask( void ) {\r
300 \r
301 \r
302         return NULL;\r
303 }\r
304 \r
305 /**\r
306  * Tries to Dispatch.\r
307  *\r
308  * Used by:\r
309  *   ActivateTask()\r
310  *   WaitEvent()\r
311  *   TerminateTask()\r
312  *   ChainTask()\r
313  *\r
314  * @param force Force a re-scheduling\r
315  *\r
316  */\r
317 void Os_Dispatch( uint32_t op ) {\r
318         OsPcbType *pcbPtr;\r
319         OsPcbType *currPcbPtr = Os_TaskGetCurrent();\r
320 \r
321         assert(os_sys.int_nest_cnt == 0);\r
322         assert(Os_SchedulerResourceIsFree());\r
323 \r
324         /* When calling post hook we must still be in ST_RUNNING */\r
325         assert( currPcbPtr->state & ST_RUNNING );\r
326         POSTTASKHOOK();\r
327 \r
328         /* Go the correct state for running task */\r
329         if( op  & ( OP_SET_EVENT | OP_SCHEDULE | OP_RELEASE_RESOURCE )) {\r
330                 Os_TaskRunningToReady(currPcbPtr);\r
331         } else if( op & (OP_WAIT_EVENT )) {\r
332                 Os_TaskMakeWaiting(currPcbPtr);\r
333         } else if( op & (OP_SLEEP )) {\r
334                 Os_TaskMakeSleeping(currPcbPtr);\r
335         } else if( op & OP_ACTIVATE_TASK ) {\r
336                 Os_TaskMakeReady(currPcbPtr);\r
337         } else if( op & OP_CHAIN_TASK ) {\r
338                 assert( os_sys.chainedPcbPtr != NULL );\r
339 \r
340                 /*  #  from chain  top\r
341                  * ----------------------------------------------------------\r
342                  *  1    1     1     1    1->RUNNING\r
343                  *  2    1     1     2    1->READY,            2->RUNNING\r
344                  *  3    1     2     2    1->SUSPENDED/READY*, 2->RUNNING\r
345                  *  4    1     2     3    1->SUSPENDED/READY*, 2->READY  , 3-RUNNING\r
346                  *\r
347                  *  *) Depends on the number of activations.\r
348                  *\r
349                  *  - Chained task is always READY when coming from ChainTask()\r
350                  */\r
351                 if( currPcbPtr != os_sys.chainedPcbPtr ) {\r
352                         /* #3 and #4 */\r
353                         --currPcbPtr->activations;\r
354                         if( currPcbPtr->activations <= 0 ) {\r
355                                 currPcbPtr->activations = 0;\r
356                                 Os_TaskMakeSuspended(currPcbPtr);\r
357                         } else {\r
358                                 Os_TaskRunningToReady(currPcbPtr);\r
359                         }\r
360                         /* Chained task is already in READY */\r
361                 }\r
362                 os_sys.chainedPcbPtr = NULL;\r
363 \r
364         } else if( op & OP_TERMINATE_TASK ) {\r
365                 /*@req OSEK TerminateTask\r
366                  * In case of tasks with multiple activation requests,\r
367                  * terminating the current instance of the task automatically puts the next\r
368                  * instance of the same task into the ready state\r
369                  */\r
370                 --currPcbPtr->activations;\r
371 \r
372                 if( currPcbPtr->activations <= 0 ) {\r
373                         currPcbPtr->activations = 0;\r
374                         Os_TaskMakeSuspended(currPcbPtr);\r
375                 }\r
376         } else {\r
377                 assert(0);\r
378         }\r
379 \r
380         pcbPtr = Os_TaskGetTop();\r
381 \r
382 \r
383 \r
384         /* Swap if we found any process or are forced (multiple activations)*/\r
385         if( pcbPtr != currPcbPtr ) {\r
386 \r
387                 if( (op & OP_CHAIN_TASK) && ( currPcbPtr == os_sys.chainedPcbPtr ) ) {\r
388                         /* #2 */\r
389                         Os_TaskRunningToReady(currPcbPtr);\r
390                 }\r
391                 /*\r
392                  * Swap context\r
393                  */\r
394                 assert(pcbPtr!=NULL);\r
395 \r
396                 Os_ResourceReleaseInternal();\r
397 \r
398 #if (OS_STACK_MONITORING == 1)\r
399                 if( !Os_StackIsEndmarkOk(currPcbPtr) ) {\r
400 #if (  OS_SC1 == 1) || (  OS_SC2 == 1)\r
401                         /** @req OS068 */\r
402                         ShutdownOS(E_OS_STACKFAULT);\r
403 #else\r
404 #error SC3 or SC4 not supported. Protection hook should be called here\r
405 #endif\r
406                 }\r
407 #endif\r
408                 OS_DEBUG(D_TASK,"Swapping to: %s\n",pcbPtr->name);\r
409                 Os_TaskSwapContext(currPcbPtr,pcbPtr);\r
410 \r
411                 /* ActivateTask, SetEvent, Schedule, .. */\r
412 //              pcbPtr = Os_TaskGetCurrent();\r
413 //              Os_TaskMakeRunning(pcbPtr);\r
414 //              PRETASKHOOK();\r
415 \r
416 //              Os_ResourceGetInternal();\r
417 \r
418         } else {\r
419                 OS_DEBUG(D_TASK,"Continuing task %s\n",pcbPtr->name);\r
420                 /* Setup the stack again, and just call the basic task */\r
421                 Os_StackSetup(pcbPtr);\r
422                 /* TODO: release and get the internal resource ? */\r
423                 Os_TaskMakeRunning(pcbPtr);\r
424                 PRETASKHOOK();\r
425                 Os_ArchSetSpAndCall(pcbPtr->stack.curr,Os_TaskStartBasic);\r
426                 assert(0);\r
427         }\r
428 }\r
429 \r
430 \r
431 /*\r
432  * Thoughts on task switching and memory protection\r
433  *\r
434  * If we would have had memory protection:\r
435  * - Applications have their own MMU settings.\r
436  * - Swapping between tasks in same Application does NOT involve the MMU.\r
437  * - When running a non-trusted Application I need will have to:\r
438  *   - Run kernel in supervisor mode.\r
439  *   - Trap the start of each task\r
440  *   - All calls to the kernel will have a trap interface, i.e.  Os_ResourceGetInternal(ActivateTask(TASK_ID_foo);\r
441  *   - An ISR2:\r
442  *     - The interupt is taken, the kernel runs in supervisor mode\r
443  *     - If the ISR2 activates\r
444  *\r
445  * Stack design:\r
446  * ALT1: 1 kernel stack...\r
447  * ALT2:\r
448  *\r
449  *  Do we need virtual memory??\r
450  */\r
451 \r
452 void Os_TaskSwapContext(OsPcbType *old_pcb, OsPcbType *new_pcb ) {\r
453         set_curr_pcb(new_pcb);\r
454         Os_ResourceGetInternal();\r
455         Os_TaskMakeRunning(new_pcb);\r
456         /* TODO: The pretask hook is not called with the right stack\r
457          * (it's called on the old task stack, not the new ) */\r
458         PRETASKHOOK();\r
459         Os_ArchSwapContext(old_pcb,new_pcb);\r
460 }\r
461 \r
462 void Os_TaskSwapContextTo(OsPcbType *old_pcb, OsPcbType *new_pcb ) {\r
463         set_curr_pcb(new_pcb);\r
464         Os_ResourceGetInternal();\r
465         Os_TaskMakeRunning(new_pcb);\r
466         PRETASKHOOK();\r
467         Os_ArchSwapContextTo(old_pcb,new_pcb);\r
468         assert(0);\r
469 }\r
470 \r
471 \r
472 void Os_Arc_GetStackInfo( TaskType task, StackInfoType *s) {\r
473         OsPcbType *pcb  = os_get_pcb(task);\r
474 \r
475         s->curr         = Os_ArchGetStackPtr();\r
476         s->top          = pcb->stack.top;\r
477         s->at_swap      = pcb->stack.curr;\r
478         s->size         = pcb->stack.size;\r
479         s->usage        = (void *)Os_StackGetUsage(pcb);\r
480 }\r
481 \r
482 \r
483 #define TASK_CHECK_ID(x)                                \\r
484         if( (x) > OS_TASK_CNT) { \\r
485                 rv = E_OS_ID;                                   \\r
486                 goto err;                                               \\r
487         }\r
488 \r
489 \r
490 /**\r
491  * Returns the state of a task (running, ready, waiting, suspended)\r
492  * at the time of calling GetTaskState.\r
493  *\r
494  * @param TaskId  Task reference\r
495  * @param State   Reference to the state of the task\r
496  */\r
497 \r
498 StatusType GetTaskState(TaskType TaskId, TaskStateRefType State) {\r
499         state_t curr_state;\r
500         StatusType rv = E_OK;\r
501 \r
502         TASK_CHECK_ID(TaskId);\r
503 \r
504         curr_state = os_pcb_get_state(os_get_pcb(TaskId));\r
505 \r
506         // TODO: Lazy impl. for now */\r
507         switch(curr_state) {\r
508         case ST_RUNNING:        *State = TASK_STATE_RUNNING;    break;\r
509         case ST_WAITING:        *State = TASK_STATE_WAITING;    break;\r
510         case ST_SUSPENDED:      *State = TASK_STATE_SUSPENDED;  break;\r
511         case ST_READY:          *State = TASK_STATE_READY;      break;\r
512         }\r
513 \r
514         // Prevent label warning. Remove when proper error handling is implemented.\r
515         if (0) goto err;\r
516 \r
517         OS_STD_END_2(OSServiceId_GetTaskState,TaskId, State);\r
518 }\r
519 \r
520 \r
521 /**\r
522  * GetTaskID returns the information about the TaskID of the task\r
523  * which is currently running.\r
524  *\r
525  * @param task_id Reference to the task which is currently running\r
526  * @return\r
527  */\r
528 StatusType GetTaskID( TaskRefType TaskID ) {\r
529         StatusType rv = E_OK;\r
530         *TaskID = INVALID_TASK;\r
531 \r
532         /* Test specification say return CALLEVEL if in ISR\r
533          * but impl. spec says otherwise */\r
534         if( os_sys.int_nest_cnt == 0 ) {\r
535                 if( os_sys.curr_pcb->state & ST_RUNNING ) {\r
536                         *TaskID = os_sys.curr_pcb->pid;\r
537                 } else {\r
538                         /* This is not a real error since this could\r
539                          * be the case when called from ErrorHook */
540                 }\r
541         }\r
542 \r
543     return rv;\r
544 }\r
545 \r
546 \r
547 ISRType GetISRID( void ) {\r
548 \r
549         /** @req OS264 */\r
550         if(os_sys.int_nest_cnt == 0 ) {\r
551                 return INVALID_ISR;\r
552         }\r
553 \r
554         /** @req OS263 */\r
555         return (ISRType)Os_TaskGetCurrent()->pid;\r
556 }\r
557 \r
558 static inline void Os_Arc_SetCleanContext( OsPcbType *pcb ) {\r
559         if (pcb->proc_type == PROC_EXTENDED) {\r
560                 /** @req OSEK ActivateTask Cleanup events\r
561                  * OSEK,ActivateTask, When an extended task is transferred from suspended\r
562                  * state into ready state all its events are cleared.*/\r
563                 pcb->ev_set = 0;\r
564                 pcb->ev_wait = 0;\r
565         }\r
566         Os_StackSetup(pcb);\r
567         Os_ArchSetTaskEntry(pcb);\r
568         Os_ArchSetupContext(pcb);\r
569 }\r
570 \r
571 /**\r
572  * The task <TaskID> is transferred from the suspended state into\r
573  * the  ready state. The operating system ensures that the task\r
574  * code is being executed from the first statement.\r
575  *\r
576  * The service may be called from interrupt  level and from task\r
577  * level (see Figure 12-1).\r
578  * Rescheduling after the call to  ActivateTask depends on the\r
579  * place it is called from (ISR, non preemptable task, preemptable\r
580  * task).\r
581  *\r
582  * If E_OS_LIMIT is returned the activation is ignored.\r
583  * When an extended task is transferred from suspended state\r
584  * into ready state all its events are cleared.\r
585  *\r
586  * Note!\r
587  * ActivateTask will not immediately change the state of the task\r
588  * in case of multiple activation requests. If the task is not\r
589  * suspended, the activation will only be recorded and performed later.\r
590  *\r
591  * @param pid\r
592  * @return\r
593  */\r
594 \r
595 StatusType ActivateTask( TaskType TaskID ) {\r
596         long msr;\r
597         OsPcbType *pcb = os_get_pcb(TaskID);\r
598         StatusType rv = E_OK;\r
599 \r
600         OS_DEBUG(D_TASK,"# ActivateTask %s\n",pcb->name);\r
601 \r
602 #if (OS_STATUS_EXTENDED == STD_ON )\r
603         /* extended */\r
604         TASK_CHECK_ID(TaskID);\r
605 #endif\r
606 \r
607         Irq_Save(msr);\r
608         /* @req OS093 ActivateTask */\r
609         if( Os_IrqAnyDisabled() ) {\r
610                 /* Standard */\r
611                 rv = E_OS_DISABLEDINT;\r
612                 goto err;\r
613         }\r
614 \r
615         pcb->activations++;\r
616         if( os_pcb_get_state(pcb) != ST_SUSPENDED ) {\r
617                 /** @req OSEK_? Too many task activations */\r
618                 if( pcb->activations >= (pcb->activationLimit + 1) ) {\r
619                         /* Standard */\r
620                         rv=E_OS_LIMIT;\r
621                         Irq_Restore(msr);\r
622                         --pcb->activations;\r
623                         goto err;\r
624                 }\r
625         } else {\r
626                 /* We have a suspended task, make it ready for use */\r
627                 assert( pcb->activations == 1 );\r
628                 Os_Arc_SetCleanContext(pcb);\r
629                 Os_TaskMakeReady(pcb);\r
630         }\r
631 \r
632         /* Preempt only if we are preemptable and target has higher prio than us */\r
633         if(     (Os_TaskGetCurrent()->scheduling == FULL) &&\r
634                 (os_sys.int_nest_cnt == 0) &&\r
635                 (pcb->prio > Os_TaskGetCurrent()->prio) &&\r
636                 (Os_SchedulerResourceIsFree()))\r
637         {\r
638                 Os_Dispatch(OP_ACTIVATE_TASK);\r
639         }\r
640 \r
641         Irq_Restore(msr);\r
642 \r
643         OS_STD_END_1(OSServiceId_ActivateTask,TaskID);\r
644 }\r
645 \r
646 /**\r
647  * This  service  causes  the  termination  of  the  calling  task.  The\r
648  * calling  task  is  transferred  from  the  running  state  into  the\r
649  * suspended state.\r
650  *\r
651  * An internal resource assigned to the calling task is automatically\r
652  * released. Other resources occupied by the task shall have been\r
653  * released before the call to TerminateTask. If a resource is still\r
654  * occupied in standard status the behaviour is undefined.\r
655  *\r
656  *   If the call was successful, TerminateTask does not return to the\r
657  * call level and the status can not be evaluated.\r
658  *\r
659  *   If the version with extended status is used, the service returns\r
660  * in case of error, and provides a status which can be evaluated\r
661  * in the application.\r
662  *\r
663  *   If the service TerminateTask is called successfully, it enforces a\r
664  * rescheduling.\r
665  *\r
666  *  [ Ending   a   task   function   without   call   to   TerminateTask\r
667  *    or ChainTask is strictly forbidden and may leave the system in an\r
668  *    undefined state. ]\r
669  *\r
670  * [] is an OSEK requirement and is overridden by OS052\r
671  *\r
672  * @return\r
673  */\r
674 \r
675 StatusType TerminateTask( void ) {\r
676         OsPcbType *curr_pcb = Os_TaskGetCurrent();\r
677         StatusType rv = E_OK;\r
678         uint32_t flags;\r
679 \r
680         OS_DEBUG(D_TASK,"# TerminateTask %s\n",curr_pcb->name);\r
681 \r
682 #if (OS_STATUS_EXTENDED == STD_ON )\r
683 \r
684 \r
685         if( os_sys.int_nest_cnt != 0 ) {\r
686                 rv =  E_OS_CALLEVEL;\r
687                 goto err;\r
688         }\r
689 \r
690 #if 0\r
691         if ( Os_SchedulerResourceIsOccupied() ) {\r
692                 rv =  E_OS_RESOURCE;\r
693                 goto err;\r
694         }\r
695 #endif\r
696 \r
697         if( Os_TaskOccupiesResources(curr_pcb) ) {\r
698                 /* Note! Do NOT release the resource here */\r
699                 rv =  E_OS_RESOURCE;\r
700                 goto err;\r
701         }\r
702 \r
703 #endif\r
704         Irq_Save(flags);\r
705 \r
706         /* Force the dispatcher to find something, even if its us */\r
707         Os_Dispatch(OP_TERMINATE_TASK);\r
708 \r
709         assert(0);\r
710 \r
711         OS_STD_END(OSServiceId_TerminateTask);\r
712 }\r
713 \r
714 StatusType ChainTask( TaskType TaskId ) {\r
715         OsPcbType *curr_pcb = Os_TaskGetCurrent();\r
716         StatusType rv = E_OK;\r
717         uint32_t flags;\r
718         OsPcbType *pcb = os_get_pcb(TaskId);\r
719 \r
720 \r
721         OS_DEBUG(D_TASK,"# ChainTask %s\n",curr_pcb->name);\r
722 \r
723 #if (OS_STATUS_EXTENDED == STD_ON )\r
724         /* extended */\r
725         TASK_CHECK_ID(TaskId);\r
726 \r
727         if( os_sys.int_nest_cnt != 0 ) {\r
728                 /* extended */\r
729                 rv = E_OS_CALLEVEL;\r
730                 goto err;\r
731         }\r
732 \r
733 #endif\r
734 \r
735         Irq_Save(flags);\r
736 \r
737 #if (OS_STATUS_EXTENDED == STD_ON )\r
738 #if 0\r
739         if ( Os_SchedulerResourceIsOccupied() ) {\r
740                 /* extended */\r
741                 rv = E_OS_RESOURCE;\r
742                 Irq_Restore(flags);\r
743                 goto err;\r
744         }\r
745 #endif\r
746 \r
747         if( Os_TaskOccupiesResources(curr_pcb) ) {\r
748                 /* extended */\r
749                 rv = E_OS_RESOURCE;\r
750                 Irq_Restore(flags);\r
751                 goto err;\r
752         }\r
753 #endif\r
754 \r
755 //      if( os_pcb_get_state(pcb) != ST_SUSPENDED ) {\r
756         if (curr_pcb != pcb) {\r
757                 /** @req OSEK_? Too many task activations */\r
758                 if( (pcb->activations + 1) >  pcb->activationLimit ) {\r
759                         /* standard */\r
760                         rv = E_OS_LIMIT;\r
761                         Irq_Restore(flags);\r
762                         goto err;\r
763                 }\r
764 \r
765                 if( os_pcb_get_state(pcb) == ST_SUSPENDED ) {\r
766                         assert( pcb->activations == 0 );\r
767                         Os_Arc_SetCleanContext(pcb);\r
768                         Os_TaskMakeReady(pcb);\r
769                 }\r
770 \r
771                 pcb->activations++;\r
772 \r
773         }\r
774 \r
775         os_sys.chainedPcbPtr = pcb;\r
776 \r
777         Os_Dispatch(OP_CHAIN_TASK);\r
778 \r
779         assert( 0 );\r
780 \r
781         OS_STD_END_1(OSServiceId_ChainTask,TaskId);\r
782 }\r
783 \r
784 /**\r
785  * If a higher-priority task is ready, the internal resource of the task\r
786  * is released, the current task is put into the  ready state, its\r
787  * context is saved and the higher-priority task is executed.\r
788  * Otherwise the calling task is continued.\r
789  *\r
790  * TODO: The OSEK spec says a lot of strange things under "particulareties"\r
791  * that I don't understand\r
792  *\r
793  * See OSEK/VDX 13.2.3.4\r
794  *\r
795  */\r
796 StatusType Schedule( void ) {\r
797         StatusType rv = E_OK;\r
798         uint32_t flags;\r
799         OsPcbType *curr_pcb = get_curr_pcb();\r
800 \r
801         OS_DEBUG(D_TASK,"# Schedule %s\n",Os_TaskGetCurrent()->name);\r
802 \r
803         /* Check that we are not calling from interrupt context */\r
804         if( os_sys.int_nest_cnt != 0 ) {\r
805                 rv =  E_OS_CALLEVEL;\r
806                 goto err;\r
807         }\r
808 \r
809         if ( Os_TaskOccupiesResources(curr_pcb) ) {\r
810                 rv = E_OS_RESOURCE;\r
811                 goto err;\r
812         }\r
813 \r
814         assert( Os_TaskGetCurrent()->state & ST_RUNNING );\r
815 \r
816         /* We need to figure out if we have an internal resource,\r
817          * otherwise no re-scheduling.\r
818          * NON  - Have internal resource prio OS_RES_SCHEDULER_PRIO (32+)\r
819          * FULL - Assigned internal resource OR\r
820          *        No assigned internal resource.\r
821          * */\r
822         if( Os_TaskGetCurrent()->scheduling != NON ) {\r
823                 return E_OK;\r
824         }\r
825 \r
826         Irq_Save(flags);\r
827         OsPcbType* top_pcb = Os_TaskGetTop();\r
828         /* only dispatch if some other ready task has higher prio */\r
829         if (top_pcb->prio > Os_TaskGetCurrent()->prio) {\r
830                 Os_Dispatch(OP_SCHEDULE);\r
831         }\r
832 \r
833         Irq_Restore(flags);\r
834         // Prevent label warning. Remove this when proper error handling is implemented.\r
835         if (0) goto err;\r
836 \r
837         OS_STD_END(OSServiceId_Schedule);\r
838 }\r
839 \r